排序算法的利弊分析及在工程中的使用| 青训营笔记
这是我参与「第四届青训营」笔记创作活动的第3篇笔记
引入
Redis-zset,skiplist整体有序
Redis集群,主从算法、分片算法,避免单机压力过大
保证集群原信息的稳定,使用一致性算法
缓存算法LRU降低Redis压力,不需要频繁读取数据
最快的排序算法?
分情况:可并发吗?数据多少?
分语言:py-timsort C++-introsort Rust-pdqsort
问题
GO1.19的排序算法?
工程算法和课程算法的区别?
GO的排序算法是快排吗?
经典排序算法
插入排序
整理扑克牌,找到第一个比其小的元素
best O(n)
avg O(n^2)
worst O(n^2)
缺点:慢
快速排序
分治思想,不断分割直至整体有序
选定一个轴点,使用轴点分割成比轴点大/小的两个序列
best O(nlogn)
avg O(nlogn)
worst O(n^2)
堆排序
构造一个大根堆(用数组模拟)
层序遍历的结尾和根节点交换,剩余节点重新调整为大根堆,重复操作
最后得到层序遍历有序的树
best O(nlogn)
avg O(nlogn)
worst O(nlogn)
“众生平等”
元素排列情况
随机random
有序sorted/reverse
元素重复度较高mod8
根据序列长度的划分(16/128/1024)
短序列,插入排序最快
中序列、长序列,快速排序最快
序列有序时
插入排序最快
堆排序其次
快排最慢
pdsort
pattern-defeating-quicksort,一种不稳定的混合排序算法,广泛应用在C++、Rust、GO
v1
短序列使用插入排序
其他情况使用快排
当快排表现不佳时,使用堆排序维持O(nlogn)
Q:
1.短序列指多长?
12-32
2.如何知道快排表现不佳,以及如何切换堆排序?
当最终轴点的位置离序列两端很接近时(距离小于len/8)判定为表现不佳,当这种情况次数达到limit(即bits.Len(length))时,切换到堆排序。
V2
优化快排选择轴点的策略
1.使用首个元素
2.遍历寻找中位数
3.寻找近似的中位数 ✅
根据序列长度,选择决定策略
短序列(<=8),选择固定元素
中序列(<=50),采样三个元素
长序列(>50),采样九个元素
采样使得我们探知当前状态的能力
采样的元素都是逆序->序列可能已经逆序->反转整个序列
采样的元素都是顺序->序列可能已经有序->使用插入排序
ps:插入排序实际使用partial Insertion Sort
V3
还可以优化…?
短序列 插入排序 check
极端情况 堆排序 check
完全随机 选择轴点的策略 check
有序/逆序 翻转或插入排序 check
元素重复度较高mod8 ❌
采样轴点时检测重复度?采样数量有限,改进为...
如果两次partition找到相同的轴点,则认为轴点是重复元素,先将重复元素排列在一起
当上一次轴点选择策略表现不佳时(比如轴点离两端太近),随机交换元素,以防黑客攻击,limit - 1,limit = 0时调用堆排序。
\