知乎上有一个问题是这样的:算法
堆排序是渐进最优的比较排序算法,达到了O(nlgn)这一下界,而快排有必定的可能性会产生最坏划分,时间复杂度可能为O(n^2),那为何快排在实际使用中一般优于堆排序?测试
昨天恰好写了一篇关于快排优化的文章,今天再多作一个比较吧。首先先看一个排序算法图:优化
排序方法 | 平均状况 | 最好状况 | 最坏状况 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
简单选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 |
直接插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(logn)~O(n) | 不稳定 |
能够看到,到达nlogn级别的排序算法,一共有三种,分别是堆排序,归并排序以及快速排序,其中只有归并排序最稳定。那么,为何要说快速排序的平均状况是最快的呢?code
实际上在算法分析中,大O的做用是给出一个规模的下界,而不是增加数量的下界。所以,算法复杂度同样只是说明随着数据量的增长,算法时间代价增加的趋势相同,并非执行的时间就同样,这里面有不少常量参数的差异,好比在公式里各个排序算法的前面都省略了一个c,这个c对于堆排序来讲是100,可能对于快速排序来讲就是10,但由于是常数级因此不影响大O。排序
另外,即便是一样的算法,不一样的人写的代码,不一样的应用场景下执行时间也可能差异很大。下面是一个测试数据:table
测试的平均排序时间:数据是随机整数,时间单位是s 数据规模 快速排序 归并排序 希尔排序 堆排序 1000万 0.75 1.22 1.77 3.57 5000万 3.78 6.29 9.48 26.54 1亿 7.65 13.06 18.79 61.31
堆排序每次取一个最大值和堆底部的数据交换,从新筛选堆,把堆顶的X调整到位,有很大多是依旧调整到堆的底部(堆的底部X显然是比较小的数,才会在底部),而后再次和堆顶最大值交换,再调整下来,能够说堆排序作了许多无用功。class
总结起来就是,快排的最坏时间虽然复杂度高,可是在统计意义上,这种数据出现的几率极小,而堆排序过程里的交换跟快排过程里的交换虽然都是常量时间,可是常量时间差不少。方法