快速排序

2016-06-28  本文已影响88人  melouverrr

快速排序

QuickSort是一种分治的算法,将一个数组分为两个小数组,将两部分独立排序。

与MergeSort比较

关键在于partition

使得数组满足3个条件:

切分的实现

一般选择a[lo]作为切分元素

我们先从数组左端开始扫描,找到第一个比切分元素大的元素,然后从数组右端开始找到第一个比切分元素小的元素。显然这两个元素是没有排定的,因此我们交换它们的位置。如此继续,我们可以保证左指针i左侧的元素都不大于切分元素,右指针j的右侧元素都不小于切分元素。当两个指针相遇的时候,将切分元素与左子数组最右侧的元素交换位置即可。

算法正确性

由于切分过程总是能排定一个元素,由归纳法可知一定能正确递归将整个数组排序

性能特点

QuickSort的内循环会用一个递增的index将数组的元素和一个定值比较(切分元素),shell sort 和 merge sort慢的原因在于它们在内层循环中移动元素

Quick sort另一速度优势在于比较次数少.

但是排序效率还是取决于切分数组的效果,切分实际上有可能发生于一个数组的任何位置。理想情况是将数组对半分。在这种情况下,quick sort所需的比较次数满足Cn = 2Cn/2 + N
.2Cn/2表示两个子数组的比较成本,N表示需要让左右指针于数组中间处相遇的比较次数.

如果第一次从最小的元素开始切分,第二次从第二小的元素切分,那么大数组每次都要被切分,效率极低,因此在排序之前将数组随机排序的主要原因就是要避免这种情况。

相关数学命题

命题K(按照算法书上的顺序)

将长度为N的无重复数组排序,快速排序平均需要~2NLnN次比较以及1/6NLnN的交换.具体证明见书

命题L

快速排序最多需要N^2/2次比较,但随机打乱数组能够预防这种情况。即:

若每次排序后总有其中一个数组是空的,则比较次数是∑n = N(N+1)/2 ~ N^2/2.

提升性能的几个方法

1.切换到插入排序

基于以下两点:

2.三取样切分

使用子数组的一小部分元素的中位数来切分数组,取样大小为3并用大小剧中的元素切分效果最好.

3.熵最优的排序

简单的想法是将数组切分为三部分,分别对应于小于,等于,大于切分元素的数组元素.

Dijkstra解法:
维护一个lt指针,使得a[lo..lt-1]中的元素都小于v,一个gt指针使得a[gt+1..hi]中的元素都大于v,一个指针i使得a[lt..i-1]中的元素都等于v,a[i..gt]中的元素待定.

对于只有若干不同主键的随机数组,MergeSort的时间复杂度是NLgN,而quick3way则是线性的。3way的最坏情况正是所有主键不同,当存在重复主键时,性能会比merge sort好很多。三向切分是信息量最优的(熵值最低),对于任意分布的输入,最优的基于比较的算法平均所需的比较次数和3way切分的quicksort平均所需比较次数处于常数因子范围内。

3way运行时间与输入的信息量的N倍成正比。实际运用中这个性质很重要,因为对于包含大量重复元素的数组,它将排序时间从线性对数降到了线性级别。这和元素的顺序没有关系,因为会事先打乱以避免前文所提到的最坏情况。

有人提出了不基于比较的排序算法,但仍然是quicksort的表现最优良见后文

上一篇 下一篇

猜你喜欢

热点阅读