快速排序

昨天通宵,早上四点的时候就开始写博客.结果五点的时候电脑罢工,自动重启.我写的东西也就都没有了,都怪自己平时没有保存的习惯。

下次一定要注意,要养成保存的习惯,要不然再发生这样的情况,那就只能笑话自己还是个马马虎虎的小孩子了.

刚才自己列了一下文章中需要讲到的部分,很庆幸,今天的状态还不错,自己还是很满意的.

说到排序算法,首先来搞清楚一个问题,内排序和外排序指的是什么?要想解释这个问题,需要将内排序和外排序比较区分.

内排序: 需要比较的数据数量相比较外排序少,排序的数据可以一次装入内存中,在内存中进行排序.

外排序: 需要比较的数据数量相比较内排序多,数据无法一次装入内存进行排序操作.数据一般存储在较慢的外存储器.而且一般借助临时

             文件完成排序操作.

快速排序算法也是基于分治模式.分治模式怎么解释?

所谓分治模式,来自算法的一种思想-- 分治思想.分治算法的基本思想就是将一个规模为N的问题分解为K个规模较小的子问题,且子问题

与原问题相互独立而且性质相同,所以求出子问题的解,就可一得到原问题的解.

分治算法的解题步骤:

1. 分解: 将需要解决的问题划分为相互独立且性质相同的若干子问题.

2. 求解: 求解每一个子问题的解.

3. 合并:  合并子问题的解得到原问题的解.

从分治算法的解题步骤可以看出,分治的思想突出的就是分开治理,从局部到整体.用个不恰当的例子来理解一下分治,就像是生活中我们

遇到复杂棘手的问题,仔细分析,然后按照步骤一个个解决,从简单到复杂.

为什么要浪费这么多的语言来说明一下分治算法思想,因为<<算法导论>>中对于快速排序的描述是用分治模式来描述的.

快速排序算法的描述:(<<算法导论>>)

分解:  数组A[p..r]被划分成为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A(q),而且小于等于A[q+1..r]

          中的元素,下标q也在划分的过程中进行计算.

解决: 通过递归调用快速排序,对子数组A[p..q-1],A[q+1..r]排序.

合并: 因为两个子数组是就地排序的,将他们的合并不需要操作:整个数组A[p..r]已排序.

就地排序是什么? 怎么理解呢? -,-,先别急,先来看看对于快速排序过程的伪代码描述,让我们清晰的理解一下快速排序的过程.

QUICKSORT(A,p,r)

1  if p < r

2     then q <-- PARTITION(A,p,r)

3      QUICKSORT(A,p,q-1)

4      QUICKSORT(A,q+1,r)


QUICKSORT函数中三个参数的意义: A 待排序数组  p 排序开始标志位  r 待排序数组A的长度.

如果想要给一个完整的数组A排序,那么就需要执行QUICKSORT(A,1,length[A]).

从上面的排序过程可以看出3,4都是递归调用解决子问题,而就地排序的过程在PARTITION中进行。所以重点理解PARTITION。

PARTITION(A,p,r)

1  x <-- A[r]

2  i  <-- p-1

3  for j <-- p to r-1

4        do if A[j] <= x

5              then  i <-- i+1

6                 exchange A[i] <--> A[j]

7 exchange A[i+1] <--> A[r]

8 return i+1

上述就地排序的过程是:选取数组最后一个元素作为主元,然后循环遍历A(p) to A(r-1) 将数组分为左右两个部分,

左边部分的元素都是小于等于A(r),右边的元素都大于A(r).注意交换的元素索引,是i而不是j,所以在最后执行一步操作

exchage A[i+1] <--> A[j],将此次排序的基准主元移动到分界点,然后返回索引,用于下面对于划分后的左右两个部分的

递归排序,也就是上面

3      QUICKSORT(A,p,q-1)

4      QUICKSORT(A,q+1,r)

操作.

对于快速排序的概念解释的差不多了,下面来说说快速排序的性能.

快速排序的最坏性能:

     最坏的情况发生子划分的过程中,产生的两个区域分别包含N-1个元素和1个0元素.那么运行时间就可以递归的表示

     为T(n) = T(n-1)+ T(0)+O(n)= T(n-1) + O(n) = O(n^2)

快速排序的最佳性能:

     快速排序就地排序的过程中划分出的两个子问题都不可能大于n/2(因为主元已经被划分出,不需要放在任意一个子问题中

     重复求解).如果每次的划分总是两边对称的,那么就会得到最佳运行情况:

              T(n) <= 2T(n/2)+ O(n)    T(n) = O(nlgn)

快速排序的平衡性能:

      快速排序的性能接近最佳性能而不是接近最坏性能。当划分情况是按照常数比例划分的时候,得到的性能指标是O(nlgn)

上面只是说了一些快速排序的性能指标,按照我的层次也不能去证明这些. 另外也没有必要,只要知道在什么情况下是最好情况,

什么情况下是最坏情况. 证明的事情就留给有想法的人去做吧.

至于快速排序的源码实现:

看了网上很多网友在博客中给出的快速排序源码,不发表评论.但是我还是比较相信标准,所以将看一下glibc和libstd++中GNU对

C和C++两个不同版本的快速排序的源码实现.将会在下篇文章中给出.

 
 
原文地址:https://www.cnblogs.com/respawn/p/2716100.html