这是我参与「第五届青训营 」笔记创作活动的第2天。近日在掘金平台上听了Go语言排序算法的VIP课程,收获颇丰,这里整理一下。
排序算法在当今的程序开发几乎所有地方都有其应用,目前几种最快的排序算法如python的timsort,C++的introsort,Rust的pdqsort等。在Go-1.19中,目前复现的pdqsort方法速度提升表现优异,成为默认的排序算法。
几种经典的排序算法在Go语言中仍然发挥着其作用,如
- insertation sort (插入排序)
- quick sort(快速排序)
- heap sort (堆排序)
由于刚刚接触Go语言不久,本人也尝试复现了这三种排序方法的Go语言版本(源码在链接中):
这里也贴上了这些排序算法的时间与空间复杂度:
实际生产中我们需要考虑待排序序列元素的分布以及序列长度等诸多因素选择排序算法,一般而言:短序列且元素有序,插入排序性能较好;快速排序综合性能较好但不够稳定;堆排序是比较稳定的排序算法。
基于这些考量,便可以对pdqsort进行构建。其主要思想是集合上述三种排序方法的优势,在短序列(<=24)的序列中采用插入排序,其余大多情况采用快速排序,而如果快排表现不好则使用堆排序保证O(nlogn)的性能(pdqsort-v1已经于上述代码段实现)。此外,pdqsort还优化了快排中pivot的选取:根据序列长度随机采样一定个数,发现序列有可能逆序时,对序列进行翻转;发现序列有可能有序时,使用插入排序。
针对一些更复杂的情况,我们考虑到在检测到两次生成的pivot重复时(可能存在一定量重复元素)利用partitionEqual将重复元素排列在一起减少干扰;在一些不太好的情况中随机交换元素,增强pivot选择的随机性。最终版本的pdqsort流程图如下:
从这些分析中不难发现,实际生产中的排序算法更注重实践性能,且要经常进行优化和对于安全性,鲁棒性的检验,这些无疑是具有指导意义的。