桶排序与计数排序
看完你能讲清桶排序与计数排序的适用边界与稳定性差异
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
桶排序与计数排序
看完你能讲清桶排序与计数排序的适用边界与稳定性差异
大数据+小范围的排序问题
现实里有一类棘手问题:数据量极大(百万、千万级),值域却只有几十、几百——比如年龄、考分、星级。在这类场景下,传统的 n log n 比较排序为什么撑不住?
尾号只 10 种,清点每种张数即可,无须逐张比较
问题抽象:映射到小范围
左侧进入原始数据,右侧输出有序序列。映射函数 f 是核心,把大范围 v 压缩为小范围索引 k。
桶排序的核心思想
上一页我们把数据映射到了0-100的小范围。映射之后怎么排最自然?按值分桶,桶内排好,再按桶顺序串起来——这就是桶排序的核心三步。
不同邮编入不同格(分桶),同格按时间排(桶内排序),按格顺序发出(合并)
桶排序的步骤分解
桶排序分五步:先把数据按值域散入桶,再让每桶内部有序,最后按桶序串回原数组。
桶排序完整流程图
沿箭头方向读:从原数组出发,经分桶、桶内排序、最终拼接成有序数组。
桶排序代码实现
看一段 Python 实现桶排序的核心五步:建桶、入桶、桶内排序、拼接输出。
五步对应核心思路:找范围→建桶→按比例映射→桶内小排序→顺序拼接。每桶内元素少,整体复杂度近 O(n)。
桶排序复杂度分析
代码写完了,但它到底跑得多快?占多少内存?什么场景才值得用?这一页我们把时间和空间复杂度算清楚,并说清它的适用边界。
分拣员(桶内排序)是速度瓶颈;分拣格(桶)太少会堆积,太多多占场地
计数排序的核心思想
桶排序把元素分到若干桶再分别排序。但桶内还是要排。如果值域足够小,让每个取值独占一个桶呢?那连比较都不用——数一数就够了。
每个候选人是固定取值,每张选票是一次出现,票数即为该值的频次
计数排序的步骤分解
计数排序四步走:建表→计数→定位→落位,把「值→次数→位置→有序」的转换拆开看。
计数排序完整流程图
看图路径:左侧一列是公共准备,到频次数组C之后分出两条生成有序输出的路线。
计数排序代码实现
稳定版计数排序的 Python 实现,三步走:计数→前缀和→反向填位。
高亮行串起稳定版计数排序的三大动作:计数累加→前缀和转位置→反向填位。稳定性关键在 reversed(arr):相同值的元素保持原相对顺序。
计数排序复杂度分析
从计数排序的代码看,两层循环一眼就能数出来。但「快」的背后其实有代价——你为速度放弃了空间,还要牺牲一个叫「稳定性」的东西。这个牺牲值不值?这一页讲清楚。
同年入职的人要保留部门内原顺序,否则下一轮就排错
桶排序 vs 计数排序
两者都'按值分桶',但桶的含义截然不同——一个装区间,一个装具体值,这是最容易混淆的地方。
- 桶:值范围区间(连续)
- 桶内还需再排序
- 场景:均匀分布的大数据
- 桶:具体值(离散)
- 只累加计数,无排序
- 场景:值域小的离散整数
算法选择与适用边界
- ✓范围紧凑且n较大→优先计数排序
- ✓数据近似均匀分布→桶排序更快
- ✓计数排序可视为桶尺寸为1的特例
- ✓分布严重倾斜时桶排序退化为O(n²)
- ✓两者均以O(n+k)空间换取线性时间
课后思考
先自己想想,再对照参考答案——重点关注思路,不必追求完整。
参考答案基于比较的排序才有 O(n log n) 下界;它们用『值映射到位置』代替比较,绕开了比较模型,因此不违反下界。
参考答案选计数排序。范围只有 10000,计数数组规模远小于数据量,O(n+range)≈O(n),空间开销也值得。
参考答案不划算。复杂度退化为 O(n+m)=O(m),数组过大还可能爆内存,此时应回到基于比较的排序。