经典排序算法:快速排序(Quick Sort)

来源:互联网 发布:mac下视频音频格式转换 编辑:程序博客网 时间:2024/06/05 04:52

快速排序算法

快速排序算法被称为20世纪十大算法之一,是最重要的算法之一,是一定要掌握和熟练的!
快速排序的基本思想是:(分治法)
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。

案例分析

假如现在我们要对这个序列,{50,10,90,30,70,40,80,60,20}进行快速排序,序列的原始状态是这样的:
这里写图片描述

关键代码

//算出中间值关键代码 int partition(SqList *L, int low, int high){    int pivotkey = L->r[low];    while(low < high){        while(low<high&&L->r[high] >= pivotkey){            high--;        }        swap(L, low, high);        while(low<high&&L->r[low] <= pivotkey){            low++;        }        swap(L, low, high);    }    return low;}//对无序序列进行排序 void qSort(SqList *L, int low, int high){    int mid;    if(low < high){        mid = partition(L, low, high);//算出中间值         qSort(L, low, mid-1);//对左边的表递归排序         qSort(L, mid+1, high);//对右边的表递归排序     }}

方法qSort表现了我们的算法思想,首先通过partition算出中间值,然后再对两边的值进行递归排序。
这里写图片描述

partition方法,初始时pivotkey 为50,然后进行逻辑判断。
当high指针所指向的值大于pivotkey,则一直让high指针递减,直到high指向一个比pivotkey小的数时,然后让high指针和low指针的值交换,目的就是为了把较小的值移到左边。图中20会与50交换。
当low指针指向的值小于pivotkey时,则一直让low递增,直到low指向一个比pivotkey大的数时,然后让high指针和low指针的值交换,目的就是为了把较大的值移到右边。图中low指针会移到90,然后90和50交换。

完整代码

#include <stdio.h>#include <stdlib.h>#define MAXSIZE 10typedef struct{    int r[MAXSIZE];    int length;}SqList;void swap(SqList *L, int i, int j){    int temp = L->r[i];    L->r[i] = L->r[j];    L->r[j] = temp;}void initSort(SqList *L){    L->length = 9;    L->r[0] = 0;    int a[9] = {50,10,90,30,70,40,80,60,20} ;    for(int i = 1; i<MAXSIZE; i++){        L->r[i] = a[i-1];    }}//算出中间值关键代码 int partition(SqList *L, int low, int high){    int pivotkey = L->r[low];    while(low < high){        while(low<high&&L->r[high] >= pivotkey){            high--;        }        swap(L, low, high);        while(low<high&&L->r[low] <= pivotkey){            low++;        }        swap(L, low, high);    }    return low;}//对无序序列进行排序 void qSort(SqList *L, int low, int high){    int mid;    if(low < high){        mid = partition(L, low, high);//算出中间值         qSort(L, low, mid-1);//对左边的表递归排序         qSort(L, mid+1, high);//对右边的表递归排序     }}void quickSort(SqList *L){    qSort(L, 1, L->length);}void searchSort(SqList *L){    for(int i = 1; i < MAXSIZE; i++){        printf("%d ", L->r[i]);    }}int main(){    SqList *L = new SqList;    initSort(L);    searchSort(L);    printf("\n");    quickSort(L);    searchSort(L);    return 0;}

结果如下:

这里写图片描述

算法时间复杂度分析

在最好的情况下,第一次partition会扫描n个关键字,做n次比较,因此此时的时间复杂度为n,记为T(n)。然后,获得的中间值将数组一分为二,那么各自需要T(n/2),此时的总时间为:2 T(n/2)+n
如下:
T(n) <= 2T(n / 2) + n
T(n) <= 2(2T(n / 4) + n/2) + n = 4T(n/4) + 2n
T(n) <= 4(2T(n / 8) + n/4) + 2n = 8T(n/8) + 3n
….
T(n) <= nT(1) + (logn) * n = O(nlogn)

所以,最优情况下,快速排序的算法时间复杂度为O(nlogn)

优化

  1. 发现一个问题,partition函数中,中间值pivotkey的取值是一个很值得商榷的问题,我们一开始设它为L->r[low],只是刚好L->r[low]为50,因此pivotkey的值是比较接近中间值的。但是假如在有这样一个序列,{9,1,4,8,6,5,2,3,7},那么此时pivotkey的值为9,但是9是整个序列最大值,这样我们的无用比较会做多少次啊!
    我们可以用三数取中法,取三个关键字排序,再将中间值作为序列的中间值,一般取左端,中间,右端三个数。
//算出中间值关键代码 int partition(SqList *L, int low, int high){    int pivotkey;    //增加了优化代码     int m = low + (high - low) / 2;//中间元素的下标     if(L->r[low] > L->r[high]){        swap(L, low, high);//保证左端较小     }    if(L->r[m] > L->r[high]){        swap(L, m, high);//保证中间值较小    }    if(L->r[m] > L->r[low]){        swap(L, low, m);//保证low位置的值为low,mid,high中第二大的    }     pivotkey = L->r[low];    while(low < high){        while(low<high&&L->r[high] >= pivotkey){            high--;        }        swap(L, low, high);        while(low<high&&L->r[low] <= pivotkey){            low++;        }        swap(L, low, high);    }    return low;}
  1. pivotekey的交换次数不必要,因为他最终都会到达中间(low
    public static int partition(int low, int high){        int privoteKey = array[low];        int back = privoteKey;        while(low < high){            while(low<high && array[high] >= privoteKey){                high--;            }            //直到发现了有半部分有小于privotekey的数            //采用替换            array[low] = array[high];            while(low<high && array[low] <= privoteKey){                low++;            }            array[high] = array[low];        }        array[low] = back;        return low;    }
0 0
原创粉丝点击