八种排序算法(一)------快速排序

一、基本思想

(1)从数列当中选取一个数作为基准(一般是数组的第一个元素)

(2)分区过程。将比这个数大的放到选取的数字的右边,比这个数小的放到选取的数左边。

(3)对左右区间重复(2)过程,直到每个区间都只含有一个数为止。

二、具体过程(以第一趟排序为例)

如下图所示:


a.设置初始值key = 32.同时将low设置为要排序数组中的第一个元素下标,第一次排序操作时其值为0,将high设置为要排序序列最后一个元素的下标,在上图中第一次取值为45;

b.将下标为high的数组元素与key进行比较,由于该元素大于key值,因此key向左移动一个位置继续扫描;

c.由于接下来的数字为23,小于key的值,因此将23赋值给下标low所指向的数组元素;

d.接下来low右移一个位置,将low所指向的数组元素的值与key进行比较,因为接下来的12,7都小于key,因此low继续右移扫描,直至下标low所指向的数组元素的值为78即大于key为止;

e.将78赋值给下标为high所指向的数组元素,同时将high左移一个位置,接下来由于low不再小于high,划分结束。

注:在进行划分的过程当中,都是讲扫描的值与key的值进行对比,如果小于key,那么僵该值赋值给数组中的另一个元素,而该元素的值并没有改变。所以需要在划分的最后将作为划分基准的key的值赋给下标为pos的数组元素,这个元素不再参与接下来的划分操作。

第一次划分结束之后,得到了左右两部分序列A[0],A[1],A[2]和A[4],A[5].继续进行划分,即对每轮划分后得到的两部分序列继续划分,直至得到有序序列为止。

三、代码实现

void quick_sort(int s[],int high,int low)

{

    int s[0] = s[low];

    int l = low,h = high;

    if(h > l)

    {

        while((h > l) && (s[h] > s[0]))

            --h;

        if(h > l)

            s[l] = s[h];

        while((h > l) && (s[h] < s[0]))

            ++l;

        if(h > l)

            s[h] = s[l];

    }

    s[l] = s[0];

    quick_sort(s,low,l-1);

    quick_sort(s,l+1,high);

}

四、复杂度分析


快速排序的时间代价很大程度上取决于枢轴的选择,最简单的办法就是选择第一个记录或者最后一个记录作为枢轴值,但这样做的弊端在于当原始的输入序列已经有序,每次分割会将剩余的记录全部分到一个序列当中,而另外一个序列为空。这种情况也是最差的情况(eg:第一趟经过n-1次比较,第一个记录定在原始位置,左半子序列为空,右半子序列为n-1个记录;第二趟n-1个经过n-2次比较,第2个记录定在原始位置,左半子序列仍为空,右半子序列为n-2个记录,以此类推,共需进行n-1趟排序,其比较次数为[(n-1)+(n-2)+......+(n-(n-1))]=n(n-1)/2=O(n^2)【时间复杂度取最高项,然后忽略掉其系数】;

最好的情况就是,每次分割都恰好将记录序列分为两个长度相等的子1序列。初始的n个记录序列,第一次分割为两个长度为n/2的子序列,第2次分割为4个长度为n/4的子序列,以此类推,总共需要分割logn次,所有分割步数之和为n,因此最终的时间复杂度为O(nlogn).

五、稳定性

因为快速排序每次移动记录的跨度比较大,因此快排是不稳定的。

猜你喜欢

转载自blog.csdn.net/m0_37962600/article/details/80064521