排序算法之選擇排序2—快排

快速排序也叫分區排序,其基本思想是在特定範圍內對於某個基準值,將小於這個基準值的元素全部移到這個值的前面,大於這個值的元素全部移到這個值的後面,然後再對前後範圍的元素遞歸進行分區,最終得到一個有序序列。快速排序的時間複雜度爲O(nlgn),空間複雜度爲O(lgn),當數組元素數量較大時,快速排序要比其他排序都要好,但是當數量級較小時,快速排序的性能可能沒有其他排序好。
下面給出快排的實現:

#include <iostream>
using namespace std;
#include <cassert>
#include <ctime>
#include <cstdlib>
template <typename T>
struct Less
{
    bool operator()(T &left, T &right)const
    {
        return left < right;
    }
};

template <typename T>
struct Greater
{
    bool operator()(T &left, T &right)const
    {
        return left > right;
    }
};

template <typename T>
void SelectMid(T *array, int left, int right)    //三數取中函數
{
    assert(NULL != array && left >= 0 && right >= 0);
    if(right - left <= 1)
        return;
    int mid = left + ((right-left)>>1);

    int buf[3] = { left, mid, right-1 };
    for(int i = 0; i < 2; i++)
    {
        for(int j = 0; j < 2-i; j++)
        {
            if(Greater<T>()(array[buf[j]], array[buf[j+1]]))
                swap(buf[j], buf[j+1]);
        }
    }
    if(array[buf[1]] != array[right-1])
        swap(array[buf[1]], array[right-1]);
}

template <typename T>
int Partition1(T *array, int left, int right)      //分區函數1,也是最容易想到的
{
    assert(NULL != array && left >= 0 && right >= 0);
    assert(right - left > 1);
    int start = left;
    int tail = right-1;
    T key = array[right-1];
    while(start < tail)
    {
        while((Less<T>()(array[start], key)||array[start]==key) && start < tail)
            start++;
        while((Greater<T>()(array[tail], key)||array[tail]==key) && start < tail)
            tail--;
        if(start < tail)
            swap(array[start], array[tail]);
    }
    if(start != right-1)
        swap(array[start], array[right-1]);
    return start;
}
template <typename T>
int Partition2(T *array, int left, int right)   //分區函數2,也稱爲挖坑法
{
    assert(NULL != array && left >= 0 && right >= 0);
    assert(right - left > 1);
    int start = left;
    int tail = right-1;
    T key = array[right-1];
    while(start < tail)
    {
        while((Less<T>()(array[start], key)||array[start]==key) && start < tail)
            start++;
        if(Greater<T>()(array[start], key))
            array[tail] = array[start];
        while((Greater<T>()(array[tail], key)||array[tail]==key) && start < tail)
            tail--;
        if(Less<T>()(array[tail], key))
            array[start] = array[tail];
    }
    if(start < right)
        array[start] = key;
    return start;
}
template <typename T>
int Partition3(T *array, int left, int right)     //分區函數3
{
    assert(NULL != array && left >= 0 && right >= 0);
    assert(right - left > 1);
    int start = left-1;
    int tail = left;
    T& key = array[right-1];
    while(tail < right-1)
    {
        start++;
        tail++;
        while(Less<T>()(array[start], key) && tail < right-1)
        {
            start++;
            tail++;
        }
        while(Greater<T>()(array[tail], key) && tail < right-1)
            tail++;
        if(tail < right && Greater<T>()(array[start], array[tail]))
            swap(array[start], array[tail]);
    }
    return start;
}
template <typename T>
void _quickSort(T *array, int left, int right)
{
    assert(NULL != array && left >= 0 && right >= 0);
    if(right - left <= 1)
        return;
    SelectMid(array, left, right);      //利用三數取中法將基準元素移到最右邊
    int keysub = Partition3(array, left, right);
    _quickSort(array, left, keysub);
    _quickSort(array, keysub+1, right);
}

template <typename T>
void QuickSort(T *array, const int size)
{
    assert(NULL != array && size > 0);
    if(size == 1)
        return;
    _quickSort(array, 0, (int)size);
}

測試函數:

void test7()
{
    int arr[100] = { 0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    srand((unsigned int)time(0));
    for(int i = 0; i < sz; i++)    //Assign values with random numbers
    {
        arr[i] = rand() % sz;
    }
    for(int i = 0; i < sz; i++)    //print array
        cout << arr[i] << " ";
    cout << endl << endl << endl << "sort:" << endl;
    QuickSort(arr, sz);             //sort
    for(int i = 0; i < sz; i++)    //print array
        cout << arr[i] << " ";
    cout << endl;
    for(int i = 1; i < sz; i++)  //check that the sort is correct
    {
        if(Less<int>()(arr[i], arr[i-1]))
            cout << "sort error! " << arr[i] << endl;
    }
}

三個分區函數實現算法不同,達到效果一樣。因此這裏就僅貼一種分區函數的測試結果圖:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章