交换排序—快速排序(Quick Sort)

来源:互联网 发布:公司数据管理制度 编辑:程序博客网 时间:2024/06/05 04:43

交换排序—快速排序(Quick Sort)


    • 交换排序快速排序Quick Sort
      • 基本思想
      • 排序流程
        • 1 基本流程
        • 2 排序实例
      • 算法实现
        • 1 基本快速排序
        • 2 算法改进
      • 算法分析

快速排序(Quicksort)是对冒泡排序的一种改进。快速排序由C. A. R. Hoare在1962年提出。

1. 基本思想

快速排序采用的思想是分治思想。

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

2. 排序流程

2.1 基本流程

(1)选择一个基准元素,通常选择第一个元素或者最后一个元素;

(2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大;

(3)此时基准元素在其排好序后的正确位置;

(4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。

2.2 排序实例

(a)一趟排序:

这里写图片描述

(b)排序全程:

这里写图片描述

3. 算法实现

3.1 基本快速排序

给定序列{A[0], A[1], … , A[N-1]}。

一趟快速排序的算法是:

(1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;

(2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];

(3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;

(4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;

(5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

代码

/* 快速排序--升序 */void quick_sort(int *a, int left, int right){    if(left >= right) /* 如果左边索引大于或者等于右边的索引,则已完成 */    {        return ;    }    int i = left;    int j = right;    int key = a[left]; /* 基准元素 */    while(i < j) /* 组内搜索 */    {        while(i < j && key <= a[j])        /* j向前搜索小于key的数,结束条件:1.找到一个小于等于key的数(降序为大于key)2.无符合条件1的,直到j等于i */         {            j--; /* 向前搜索 */        }        a[i] = a[j]; /* 将找到的数换到位置key上,如果没找到i=j就是本身 */        while(i < j && key >= a[i])        /* i向后搜索大于key的数,结束条件:1.找到一个大于等于key的数(降序为小于key)2.无符合条件1的,直到i等于j */         {            i++; /* 向后搜索 */        }        a[j] = a[i]; /* 将找到的数换到位置key上,如果没找到i=j就是本身 */    }    a[i] = key;/* 组内搜索完毕,key放在正确的位置上,此时key前面都小于等于key,后面都大于等于key */    step++;    print(a,left,right); /* 递归前打印 */    quick_sort(a, left, i - 1);/* 对于前面的组重复组内搜索 */    quick_sort(a, i + 1, right);/* 对于后面的组重复组内搜索 */    /* 递归每一个小组,直至所有组的i=j */}

结果

Before...No.0    4 7 1 2 9 5 3 8 6   [0, 0]Sorting...No.1    3 2 1 4 9 5 7 8 6   [0, 8]No.2    1 2 3 4 9 5 7 8 6   [0, 2]No.3    1 2 3 4 9 5 7 8 6   [0, 1]No.4    1 2 3 4 6 5 7 8 9   [4, 8]No.5    1 2 3 4 5 6 7 8 9   [4, 7]No.6    1 2 3 4 5 6 7 8 9   [6, 7]Sorted.

3.2 算法改进

  • “三者取中”选取基准数

    选取第一个A[0]、中间A[N/2]、最后一个A[N-1]中的中间数作为基准数,以防止基准数太大或太小。在划分开始前将该基准记录和该区的第 1 个数进行交换,此后的划分过程与基本算法完全相同。

  • 随机选择基准数

    选取 low 和 high 之间的随机数 k(low<=k<=high),用 A[k] 作为基准;选取基准最好的方法是用一个随机函数产生一个位于 low 和 high 之间的随机数 k(low<=k<=high) ,用 A[k] 作为基准 , 这相当于强迫 R[low, … high] 中的记录是随机分布的。用此方法所得到的快速排序一般称为随机的快速排序

  • 排序方法结合

    当快速排序递归至区间内数据较少(设置阈值k,即小于k)时,直接用其他方法排序以减小递归深度。

4. 算法分析

  • 时间复杂度

    (1)快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。

    (2)最坏情况下,每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n2)

    (3)最好情况下,每次划分所取的基准都是当前无序区的”中值”记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlogn)

    (4)平均性能,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名,快速排序是实践中已知最快的排序算法。它的平均时间复杂度为O(nlogn)

  • 空间复杂度

    快速排序在系统内部需要一个栈来实现递归。若每次划分较为均匀,则其递归树的高度为 O(logn), 故递归后所需栈空间为 O(logn) 。最坏情况下,递归树的高度为 O(n),所需的栈空间为 O(n)

  • 稳定性

    快速排序是一个不稳定的排序方法。

0 0