这是我参与「第五届青训营」伴学笔记创作活动的第 16 天,今天对go语言1.19中默认使用的pdqsort设计原理进行了简单的学习,并在这做一下小结
上一篇对基础排序算法总结的笔记:各基础排序算法小结
pdqsort简介
pdqsort,全称pattern-defeating-quicksort,是一种不稳定的混合排序算法,它的不同版本被用于C++ BOOST、RUST,它对常见的序列进行了特殊的优化,使得在不同情况下都拥有着不错的性能
pdqsort的初步设计及不断优化
version 1
借助上一篇总结,我们可以得到,在序列长度短时,我们可以使用插入排序;而中等长度以及较长的序列时,我们可以使用快速排序;当出现快速排序效率低时,我们可以转为使用各情况都比较稳定的堆排序,这样可以保证算法在最坏的情况下仍为的复杂度。
如何判断快排会出现效率低的情况
当选择的中心点最终位置离序列边界过近(距离<8),这样的次数超过limit次时,我们可以认定它表现不佳,切换为堆排序继续进行
version 2
对于version 1中的方法,我们还可以做些许改进,即改进快排的中心值选值方法,使选择的值的最终位置更靠近中心
一些寻找中心值方案
(1) 将第一个数作为中心值:确定中心值简单,但排序效率往往不好
(2) 寻找中位数作为中心值:确定中心值的消耗过大
为了兼顾寻找中心值的消耗,以及确认后排序的效率,需要采取寻找近似中位数
优化后的选择:
对于中序列(<=50),可以采样3个元素,将3个元素的中位数作为选中的中心值
对于长序列,可以采样9个元素,将9个元素的中位数作为选中的中心值(midian of midians)
对于采样出的元素序列,可以对原序列进行一定猜想:
采样的序列逆序 -> 原序列可能逆序 -> 翻转整个序列
采样的序列顺序 -> 原序列可能顺序 -> 使用有限制次数的插入排序
version 3
在优化完快排后,还有一种极端情况仍未被处理:序列元素重复度较高
因此,可以在选择中心值时,我们可以进行一些优化:当连续两次选择到相同的中心值时,可以将两个值排列到一块,减小相同值对快排效率的影响
其他优化
随机交换序列中的元素,既可以简单预防快排效率不佳,也可以简单防止黑客攻击
pdqsort复杂度分析
| 最优 | 平均 | 最差 |
|---|---|---|
总结
要想设计一个性能较优的排序算法,需要利用各排序的优势,根据不同策略,取长补短;在初步设计出算法后,仍要继续思考有无尚未考虑的特殊情况,再对特殊情况进行考虑,这样才能把算法设计的更好。