Go1.19排序算法实践 | 青训营笔记

130 阅读2分钟

01 为什么要学习数据结构和算法

例子-抖音直播排行榜功能

规则:某个时间段内,直播间礼物数TOP10房间获得奖励,需要在每个房间展示排行榜

解决方案

  • 礼物数量存储在 Redis-zset 中,使用 skiplist 使得元素整体有序
  • 使用 Redis 集群,避免单机压力过大,使用 主从算法、分片算法
  • 保证集群原信息的稳定,使用 一致性算法
  • 后端使用 缓存算法(LRU) 降低 Redis 压力,展示房间排行榜

02 经典排序算法

插入排序:最好 O(n) | 最坏 O(n2) | 平均 O(n2)

快速排序:最好 O(nlogn) | 最坏 O(n2) | 平均 O(nlogn)

堆排序:最好 O(nlogn) | 最坏 O(nlogn) | 平均 O(nlogn)

实际场景

根据序列元素排列情况划分

  • 完全随机的情况 (random
  • 有序/逆序的情况 (sorted/reverse
  • 元素重复度较高的情况 (mod8)
  • 在此基础上,还需要根据序列长度的划分(16/128/1024

结论

  • 所有短序列和元素有序情况下,插入排序性能最好
  • 在大部分的情况下,快速排序有较好的综合性能
  • 几乎在任何情况下,堆排序的表现都比较稳定

03 从零开始打造pdqsort

pdqsort - version1

结合三种排序方法的优点

  • 对于短序列 (小于一定长度)我们使用插入排序
  • 其他情况,使用快速排序来保证整体性能
  • 当快速排序表现不佳时,使用堆排序来保证最坏情况下时间复杂度仍然为 O(n*logn)

image.png

pdqsort - version2

  • 升级 pivot 选择策略(近似中位数)
  • 发现序列可能逆序,则翻转序列 -> 应对 reverse 场景
  • 发现序列可能有序,使用有限插入排序 -> 应对 sorted 场景

image.png

pdqsort - version3

优化-重复元素较多的情况(partitionEqual)

  • 当检测到此时的 pivot 和上次相同时 (发生在 leftSubArray) ,使用partitionEqual 将重复元素排列在一起,减少重复元素对于 pivot 选择的干扰

优化-当 pivot 选择策略表现不佳时,随机交换元素

  • 避免一些极端情况使得 QuickSort 总是表现不佳,以及一些黑客攻击情况

image.png

最终版本

image.png