Go排序算法详解 | 青训营笔记

66 阅读2分钟

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

插入排序

快速排序:分治

堆排序:利用堆的性质,上浮和下沉

image-20230603133145105.png

实际场景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之后的实现。