排序5-快速排序

来源:互联网 发布:linux ubuntu gcc 编辑:程序博客网 时间:2024/05/18 22:12

基本思想

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
这里写图片描述

算法步骤

算法步骤简述如下:

  • 选择一个基准值(pivot)(选择方法很多,可以固体选某个值,比如第一个或最后一个或中间值,或者是三数取中法等);
  • 将比基准值(pivot)小的数值划分到基准值左边,构成左子串列,将比基准值(pivot)大的数值划分到基准值右边,构成右子串列;
  • 分别对左子串列和右子串列递归地作上述两个步骤;
  • 直到左子串列或右子串列只剩一个值或者为空。

基准值的选取

上面的第一步基准值的选择对快速排序的效率有很大关系。基准值(pivot)的选择办法有下面几种:

  • 固定位置:第一个,最后一个或中间值;
  • 随机选取:用随机函数随机选取一个;
  • 三数取中:去第一个,中间值和最后一个数的平均值。

固定位置和随机选取的方法容易造成一种极端,如果选取的那个数刚好是最小值或最大值,比如数组是有序的,就会导致一个很差的分割,是左子串或右子串列为0,而且随机选取过程还会有额外的时间开销。所以都是不可取的。三数取中的办法就避免了上面的情况。

时间空间复杂度

快速排序的时间性能跟递归的深度有关,而空间复杂度跟递归造成的栈空间使用有关。最好的情况是,选取的基准值刚好是中位数,刚好将数据等分成2个子串,递归树也就是平衡的。递归调用需要log2n次,空间复杂度为O(logn),时间复杂度为O(nlogn);最坏的情况就是待排序的数据是有序的,正序或者逆序。递归需要n1次,空间复杂度则需要O(n)时间复杂度为O(n2)

代码实现

#define MAX_LENGTH_INSERT_SORT 7   // 数组长度阈值int  Partition(int arr[], int Left, int Right){    /* 三数取中*/    int mid = Left + (Right - Left) / 2;    if(arr[Left] > arr[Right])        swap(arr[Left],arr[Right]);    if(arr[mid] > arr[Right])        swap(arr[mid], arr[Right]);    if(arr[mid] > arr[Left])        swap(arr[mid], arr[Left]);    int pivot_key = arr[Left];    while(Left < Right)    {        while(Left < Right && arr[Right] >= pivot_key )            Right --;        arr[Left] = arr[Right];        while(Left < Right && arr[Left] <= pivot_key)            Left ++;        arr[Right] = arr[Left];    }    arr[Left] = pivot_key;    return Left;}void QSort(int arr[], int Left, int Right){    int pivot_index;   /*当Right - Left 大于 MAX_LENGTH_INSERT_SORT 采用 快排,否则使用直接插入*/    if(Right - Left > MAX_LENGTH_INSERT_SORT)    {        pivot_index = Partition(arr, Left, Right);        QSort(arr, Left, pivot_index - 1);        QSort(arr, pivot_index + 1, Right);    }    else        Insert_sort(arr, Right - Left + 1); // 直接插入法是简单排序当中性能最好的}void Quick_sort(int arr[], int len){    QSort(arr, 0, len - 1);}

测试程序

#include <iostream>#include <cstring>#include <ctime>#include <cmath>using namespace std;#define ArraySize 100000void swap(int *x, int *y){    int temp;    temp = *x;    *x   = *y;    *y   = temp;}void Bubble_sort(int arr[], int len){    for(int i = 0; i < len; i ++)    {        for(int j = i + 1; j < len; j ++)            if(arr[i] > arr[j])                swap(arr[i], arr[j]);    }}void Bubble_sort1(int arr[], int len){    for(int i = 0; i < len; i ++)    {        for(int j = len - 1; j >= i; j --)        {            if(arr[i] > arr[j])                swap(arr[i], arr[j]);        }    }}void Bubble_sort2(int arr[], int len){    bool flag = true;    while(flag)    {        flag = false;        for(int i = 0; i < len; i ++)            for(int j = len - 1; j >= i; j --)                if(arr[i] > arr[j])                    swap(arr[i], arr[j]);    }}void Slect_sort(int arr[], int len){    for(int i = 0; i < len; i ++)    {        int min_index = i ;        for(int j = i + 1; j < len; j ++)        {            if(arr[min_index] > arr[j])                min_index = j;        }        if(i != min_index)            swap(arr[i],arr[min_index]);    }}void Insert_sort(int arr[], int len){    for(int i= 1; i < len; i ++)    {           int key = arr[i];        int j = i;        while(j && arr[j - 1] > key)        {            arr[j] = arr[j - 1];            j --;        }        arr[j] = key;    }}void Shell_sort(int arr[], int len){    int increment = len / 2;    while(increment)    {        for(int i = increment; i < len; i ++)        {            int key = arr[i];            /*int j ;            for(j = i; j >= increment; j -= increment)            {                if(arr[j-increment] > key )                    arr[j] = arr[j-increment];                else                     break;            }*/            int j = i;            while(j >= increment && arr[j-increment] > key)            {                arr[j] = arr[j-increment];                j -= increment;            }            arr[j] = key;        }        increment /= 2;    }}void Shell_sort1(int arr[], int len){    int increment = 0;    for(increment = len/2; increment > 0; increment /=2)    {        for(int i = increment; i < len; i++)        {            int key = arr[i];            int j = 0;            for(j = i; j >= increment; j -=increment)            {                if(arr[j-increment] > key)                    arr[j] = arr[j-increment];                else                     break;            }            arr[j] = key;        }    }}void Shell_sort2(int arr[], int len){    int index = log( 2*len + 1) / log(3.0);    //cout << index << endl;    int increment = ( pow(3.0, index) - 1 ) / 2;    //cout << increment << endl;    while(increment)    {        for(int i = increment; i < len; i ++)        {            int key = arr[i];            /*int j ;            for(j = i; j >= increment; j -= increment)            {                if(arr[j-increment] > key )                    arr[j] = arr[j-increment];                else                     break;            }*/            int j = i;            while(j >= increment && arr[j-increment] > key)            {                arr[j] = arr[j-increment];                j -= increment;            }            arr[j] = key;        }        index -= 1;        increment = ( pow(3.0, index) - 1 ) / 2;    }}void Heap_adjust(int arr[], int index, int len){    while(true)    {        int iMax = index;        int iLeft = 2 * index + 1;        int iRight = 2 * index + 2;        if(iLeft < len && arr[index] < arr[iLeft])            iMax = iLeft;        if(iRight < len && arr[index] < arr[iRight])            iMax = iRight;        if(iMax != index)        {            swap(arr[index], arr[iMax]);            index = iMax;        }        else             break;    }}void Heap_adjust2(int arr[], int index, int len){    int iMax = index;    int iLeft = 2 * index + 1;    int iRight = 2 * index + 2;    if(iLeft < len && arr[index] < arr[iLeft])        iMax = iLeft;    if(iRight < len && arr[index] < arr[iRight])        iMax = iRight;    if(iMax != index)    {        swap(arr[index], arr[iMax]);        Heap_adjust2(arr, iMax, len);    }}void Build_maxheap(int arr[], int len){    for(int i = len / 2; i >= 0; i --)    {        Heap_adjust(arr, i , len);    }}void Heap_Sort(int arr[], int len){    Build_maxheap(arr, len);    for(int i = len - 1; i > 0; i --)    {        swap(arr[0], arr[i]);        Heap_adjust(arr, 0, i);    }}void Print_array(int arr[], int len){    for(int i = 0; i < len; i++)    {        cout << arr[i] << " ";    }    cout << endl;}void merge_array(int arr[], int tmp[], int Left, int mid, int Right){    assert(arr && Left >= 0 && Left <= mid && mid <= Right);    int i = Left;    int j = mid + 1;    int index = 0;    while(i <= mid && j <= Right)    {        if(arr[i] <= arr[j])            tmp[index++] = arr[i++];        else            tmp[index++] = arr[j++];    }    while(i <= mid)        tmp[index++] = arr[i++];    while(j <= Right)        tmp[index++] = arr[j++];    memcpy(arr + Left, tmp, (Right - Left + 1) * sizeof(int)); }void merge_sort(int arr[], int tmp[], int Left, int Right){    assert(arr && Left >= 0);    int mid;    if(Left < Right)    {        mid = (Left + Right) / 2;        merge_sort(arr, tmp, Left, mid);        merge_sort(arr, tmp, mid + 1, Right);        merge_array(arr, tmp, Left, mid, Right);    }}void Merge_Sort(int arr[], int len){    assert(arr && len);    int *tmp_arr;    //tmp_arr = (int *)malloc(len * sizeof(int));    tmp_arr = new int[len];    merge_sort(arr, tmp_arr, 0, len - 1);    delete[] tmp_arr;}#define MAX_LENGTH_INSERT_SORT 7   // 数组长度阈值int  Partition(int arr[], int Left, int Right){    /* 三数取中*/    int mid = Left + (Right - Left) / 2;    if(arr[Left] > arr[Right])        swap(arr[Left],arr[Right]);    if(arr[mid] > arr[Right])        swap(arr[mid], arr[Right]);    if(arr[mid] > arr[Left])        swap(arr[mid], arr[Left]);    int pivot_key = arr[Left];    while(Left < Right)    {        while(Left < Right && arr[Right] >= pivot_key )            Right --;        arr[Left] = arr[Right];        while(Left < Right && arr[Left] <= pivot_key)            Left ++;        arr[Right] = arr[Left];    }    arr[Left] = pivot_key;    return Left;}void QSort(int arr[], int Left, int Right){    int pivot_index;   /*当Right - Left 大于 MAX_LENGTH_INSERT_SORT 采用 快排,否则使用直接插入*/    if(Right - Left > MAX_LENGTH_INSERT_SORT)    {        pivot_index = Partition(arr, Left, Right);        QSort(arr, Left, pivot_index - 1);        QSort(arr, pivot_index + 1, Right);    }    else        Insert_sort(arr, Right - Left + 1); // 直接插入法是简单排序当中性能最好的}void Quick_sort(int arr[], int len){    QSort(arr, 0, len - 1);}int main(int argc, char const *argv[]){    /* code */    int Array[ArraySize];    int Array1[ArraySize];    int Array2[ArraySize];    int Array3[ArraySize];    time_t begin , end;    srand(time(NULL));    for(int i = 0; i < ArraySize; i ++)    {        Array[i] = rand()%ArraySize;        //cout << Array[i] << " ";    }    memcpy(Array1, Array, ArraySize * sizeof(Array1[0]));    memcpy(Array2, Array, ArraySize * sizeof(Array2[0]));    memcpy(Array3, Array, ArraySize * sizeof(Array2[0]));//  Print_array(Array, ArraySize);/*  begin = clock();    Bubble_sort2(Array, ArraySize);    end = clock();    cout << "Bubble_sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    begin = clock();    Slect_sort(Array1, ArraySize);    end = clock();    cout << "Slect_sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    begin = clock();    Insert_sort(Array2, ArraySize);    end = clock();    cout << "Insert_sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;*/     begin = clock();    Shell_sort2(Array, ArraySize);    end = clock();    cout << "Shell_sort2 runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    begin = clock();    Heap_Sort(Array1, ArraySize);    end = clock();    cout << "Heap_Sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    begin = clock();    Merge_Sort(Array2, ArraySize);    end = clock();    cout << "Merge_Sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    //Print_array(Array2, ArraySize);    begin = clock();    Quick_sort(Array3, ArraySize);    end = clock();    cout << "Quick_sort runtime:   " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;    //Print_array(Array3, ArraySize);    return 0;}

运行结果如下:

Shell_sort2 runtime:   0.028sHeap_Sort runtime:   0.005sMerge_Sort runtime:   0.013sQuick_sort runtime:   0.011s

参考文献

知无涯之std::sort源码剖析
http://feihu.me/blog/2014/sgi-std-sort/

0 0
原创粉丝点击