Go排序算法详解
本章具体介绍了Go在1.18和在1.18版本之后的标准库排序算法的区别;个人感觉和其他语言标准库也类似,在对应不同数据长度时,大家的标准库实现都会用不同的排序算法去对应不同的数组长度;这也体现了计算机科学中具体情况具体分析的最佳实践。
详解经典排序算法
课本和生产实践算法差异
- 举例:某个时间段内,直播间礼物数TOP10房间获得奖励,需要在每个房间展示排行榜;解决方案:礼物数量存在Redis-zset中,使用skiplist使得元素整体有序;Redis集群的主从算法、分片算法;集群原信息,使用一致性算法;后端使用缓存算法(LRU)降低Redis压力,展示房间排行榜
- 什么是最快的排序算法:python-timsort;c++-introsort;Rust-psqsort;Go(<=1.18)-introsort;Go1.19之后使用pdqsort
插入排序
快速排序:分治
堆排序:利用堆的性质,上浮和下沉
实际场景benchmark:
- 插入排序在短序列最快
- 快排适合长序列
- 堆排序时间复杂度比较稳定
结合三种算法的长处
从零开始打造pdqsort
pdqsort:Pattern-Defeating-QuickSort
不稳定的混合排序算法,短序列使用插入排序,其他情况使用快速排序,当快排表现不佳时使用堆排序
version1:
- 短序列具体长度:12-32,Go使用24
- 如何从快排切换到堆排序?当最后Pivot离序列两端很接近(小于length/8),当这种情况测数达到Limit(bits.Len(length))切换堆排序
version2:
- 使得pivot为序列中位数,改进choose pivot,寻找近似中位数,根据序列长度的不同,来决定选择策略,采样;pivot的采样方式使得我们有探知序列当前状态的能力!(插入排序实际使用partialInsertionSort,即有限制次数的插入排序)
- 改进partition
final version:
- 如何优化重复元素很多的情况:如果两次Partition生成的pivot相同,认为pivot的值为重复元素;使用partitionEqual将重复元素排列在一起
后续如果对标准库的代码实现感兴趣可以看看1.19之后的实现。