快速排序,终极研究

推荐一个在线算法学习的网站:http://sjjg.js.zwu.edu.cn/SFXX/sf1/sfys.html  

快速排序,终极研究_第1张图片

快速排序由霍尔 (Hoare) 提出,它是一种对冒泡排序的改正。由于其排序速度快,故称快速排序 (quick sort) 。快速排序方法的实质是将一组关键字 [K 1 ,K 2 ,…,K n ] 进行分区交换排序。 
1.算法思路
  ①以第一个关键字 K 1 为控制字,将 [K 1 ,K 2 ,…,K n ] 分成两个子区,使左区所有关键字小于等于 K 1 ,右区所有关键字大于等于 K 1 ,最后控制字居两个子区中间的适当位置。在子区内数据尚处于无序状态。 
  ②将右区首、尾指针 ( 记录的下标号 ) 保存入栈,对左区进行与第①步相类似的处理,又得到它的左子区和右子区,控制字居中。 
  ③重复第①、②步,直到左区处理完毕。然后退栈对一个个右子区进行相类似的处理,直到栈空。 
  由以上三步可以看出:快速排序算法总框架是进行多趟的分区处理;而对某一特定子区,则应把它看成又是一个待排序的文件,控制字总是取子区中第一个记录的关键字。现在设计一个函数 hoare ,它仅对某一待排序文件进行左、右子区的划分,使控制字居中;再设计一个主体框架函数 quicksort ,在这里多次调用 hoare 函数以实现对整个文件的排序。 
2.快速排序算法分析
  快速排序的非递归算法引用了辅助栈,它的深度为 log2n 。假设每一次分区处理所得的两个子区长度相近,那么可入栈的子区长度分别为:n/21n/22,n/23 ,n/24, … ,n/2k ,又因为 n/2k=1, 所以 k= log2n 。分母中 2 的指数恰好反映出需要入栈的子区个数,它就是 log2n ,也即栈的深度。在最坏情况下,比如原文件关键字已经有序,每次分区处理仅能得到一个子区。可入的子区个数接近 n, 此时栈的最大深度为 n. 
  快速排序主体算法时间运算量约 O(log2n) ,划分子区函数运算量约 O(n) ,所以总的时间复杂度为 O(nlog2n) ,它显然优于冒泡排序 O(n2). 可是算法的优势并不是绝对的。试分析,当原文件关键字有序时,快速排序时间复杂度是 O(n2), 这种情况下快速排序不快。而这种情况的冒泡排序是 O(n), 反而很快。在原文件记录关键字无序时的多种排序方法中,快速排序被认为是最好的一种排序方法。
【例】: 试用 [6,7,5 1 ,2,5 2 ,8] 进行快速排序。
排序过程简述如下:
 6    7   51   2   52  8      初始状态
[52   7   51]  6  [7   8] 
[2]  52  [51]  6   7  [8] 
[2   52   51   6   7   8]     最后状态 
  从这个例子可以分析出快速排序法的稳定性问题,其中51和52表示两个关键字的值相同,都是5。51表示排序之前它位于 52的前面。从结果中可以看出原先位于51之后的52在排序之后移到了51的前面,所以说快速排序是不稳定的。

3.快速排序执行过程
     快速排序执行的全过程可用递归树来描述。

      快速排序,终极研究_第2张图片


分析: 
     (1)递归执行的路线如图中带箭头的包络线所示。
     (2) 递归树上每一结点左旁方括号表示当前待排序的区间,结点内的关键字是划分的基准关键字
  注意:
     叶结点对应的子区间只有一个关键字,无须划分,故叶结点内没有基准关键字
  (3) 划分后得到的左、右两个子区间分别标在该结点的左、右两个孩子结点的左边方括号内。
【例】根结点左旁方括号[49,38,65,97,76,13,27,49]表示初始待排序的关键字,根内的49表示所选的划分基准记录的关键字,划分结果是[27,28,13]49[76,97,65,49_],其左右子区间分别标在根结点的两个孩子的左边。
     (4) 每个分支结点右旁圆括号中的内容表示对该结点左旁区间的排序过程结束之后返回的结果。它是其左右孩子对应的区间排序完成之后,将左右孩子对应的排序结果分别放在该分支结点的关键字前后所得到的关键字序列。
【例】分支结点76的左右孩子对应的区间排序后的结果分别是(49_,65)和(97),将它们分别放在76的前后即得(49,65,76,97),这是对结点76左旁区间[76,97,,65,49]排序的结果。
     (5) 算法的执行顺序是递归树中的箭头顺序,实际上当把划分操作视为访问结点的操作时,快速排序的执行过程相当于是先序遍历其递归树。
  注意:
     任何递归算法均可用递归树来描述其执行过程。

5、快速排序各次划分后的状态变化
[49 38 65 97 76 13 27 49] //初始关键字
[27 38 13] 49 [76 97 65 49] //第1次划分完成之后,对应递归树第2层
[13] 27 [3849 [49 65] 76 [97//对上一层各无序区划分完成后,对应递归树第3层
13 27 38 49 49 [65] 76 97 //对上一层各无序区划分完成后,对应递归树第4层
13 27 38 49 49 65 76 97 //最后的排序结果

你可能感兴趣的:(快速排序,终极研究)