这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记
pdqsort简介
是一种不稳定的混合排序算法,它的不同版本被应用在C++ BOOST、Rust 以及Go 1.19中。它对常见的序列类型做了特殊的优化, 使得在不同条件下都拥有不错的性能
pdqsort 是 Pattern-defeating quicksort 的缩写,是一种新型的排序算法,将随机快速排序的快速平均情况与堆排序的最坏情况快速组合在一起,同时在具有特定模式的输入上实现了线性时间。
思路:
结合三种排序方法的优点
- 对于短序列(小于一定长度)我们使用插入排序
- 其他情况,使用快速排序来保证整体性能
- 当快速排序表现不佳时,使用堆排序来保证最坏情况下时间复杂度仍然为O(n*logn)
1.短序列的具体长度是多少呢?
12 ~ 32,在不同语言和场景中会有不同,在泛型版本根据测试选定24
2.如何得知快速排序表现不佳,以及何时切换到堆排序?
当最终pivot的位置离序列两端很接近时(距离小于length/8)判定其表现 不佳,当这种情况的次数达到limit (即bits.Len(length)) 时,切换到堆排序
version1
- 对于短序列(<=24) 我们使用插入排序
- 其他情况,使用快速排序(选择首个元素作为pivot)来保证整体性能
- 当快速排序表现不佳时(limit==0) ,使用堆排序来保证最坏情况下时间复杂度仍然为O(n*logn)
version2
根据序列长度的不同,来决定选择策略
优化- Pivot的选择
- 短序列(<=8),选择固定元素
- 中序列(<=50),采样三个元素
- 长序列(>50),采样九个元素
Pivot的采样方式使得我们有探知序列当前状态的能力
Version1升级到version2优化总结
升级pivot选择策略(近似中位数)
发现序列可能逆序,则翻转序列->应对reverse场景
发现序列可能有序,使用有限插入排序->应对sorted场景
final version
优化重复元素较多的情况(partitionEqual)
当检测到此时的pivot和上次相同时(发 生在leftSubArray), 使用 partitionEqual将重复元素排列在一起,减少重复元素对于pivot选择的干扰
优化-当pivot选择策略表现不佳时,随机交换元素
避免一些极端情况使得QuickSort总是表现不佳, 以及一些黑客攻击情况