这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记,此次主要讲解Golang中<=1.18的默认排序算法,以及新版本中优化过后的sort算法,老师先是从最基础的插入排序、快速排序和堆排序开始讲解,介绍了各个算法的优势与不足之处,最后引出本次课程的重头戏pdqsort及其优化过程。下面是详细笔记:
数据结构与算法
主流语言的默认排序算法
python Timsort
c++ introsort
rust pdqsort
Go ≤1.18 是introsort
经典排序算法
插入排序
时间复杂度
最好O( n )
平均O(n ^ 2)
最坏O(n ^ 2)
快速排序 分治的思想,选取一个pivot
最好O( nlogn )
平均O( nlogn )
最坏O(n ^ 2)
堆排序 利用堆的性质构造一个大根堆(或者是小根堆),然后将根节点交换到最后一个位置,再重新调整堆,直至排序完成。
最好O( nlogn )
平均O( nlogn )
最坏O( nlogn )
有一个benchmark 的实验
直接上结论
- 插入排序在短序列中速度最快
- 快速排序在其他情况中速度最快
- 堆排序速度于最快算法差距不大
引入pdqsort算法
pdqsort pattern-defeating-quicksort 是一种不稳定的混合排序算法。
v1
对于短序列来说使用插入排序
其他情况使用快速排序来保证整体性能
这个需要考虑快速排序性能不佳的时候,选用堆排序来改善算法性能
这里的limit是用来判读快速排序表现不佳时的依据。
v2
在快速排序中选取pivot对于性能的影响还是很大的
所以通过优化pivot的选取来实现pdqsort性能的提升
当然寻找pivot的开销需要和带来的性能进行平衡, 需要寻找一个近似的中位数
根据序列长度的不同,选择不同的策略
短序列 ≤8 选择固定的三个数
中序列 ≤50 采样三个元素
长序列 >50 采样九个元素
升级了选择pivot的策略
发现序列逆序的话则反转序列
发现有序则使用插入排序
最终的pdqsort go1.19默认排序