桶排序¶
「桶排序 Bucket Sort」考虑设置 \(k\) 个桶,并将 \(n\) 个元素根据大小分配到 \(k\) 个桶中,并在每个桶内部分别执行排序,由于桶之间的大小关系的确定的,因此最后按照桶之间的顺序将元素依次展开即可。
假设元素平均分布在各个桶内,则每个桶内元素数量为 \(\frac{n}{k}\) ;如果使用「快速排序」来实现桶内排序,则排序单个桶使用 \(O(\frac{n}{k} \log\frac{n}{k})\) 时间,排序所有桶使用 \(O(n \log\frac{n}{k})\) 时间。当桶数量 \(k\) 比较大时,时间复杂度则趋向于 \(O(n)\) 。
Note
计数排序可以看作是桶排序的一种特例。我们可以把计数排序中 counter
的每个索引想象成一个桶,将统计数量的过程想象成把 \(n\) 个元素分配到对应的桶中,再根据桶之间的有序性输出结果,从而实现排序。
(图)
理论上桶排序的时间复杂度是 \(O(n)\) ,但前提是需要将元素均匀分配到各个桶中,而这并不容易做到。假设想要把淘宝的 \(100\) 万件商品根据价格范围平均分配到 \(100\) 个桶中,而商品价格不是均匀分布的,例如 \(100\) 元以下的商品非常多、\(1000\) 元以上的商品非常少等。如果我们将价格区间平均划分为 \(100\) 份,那么各个桶内的商品数量差距会非常大。为了实现平均分配,我们一般这样做:
- 先粗略设置分界线,将元素分配完后,把元素较多的桶继续划分为多个桶,直至所有桶内元素数量合理为止;该做法本质上是一个递归树;
- 如果我们提前知道商品价格的概率分布,则可以根据已知分布来设置每个桶的价格分界线;值得说明的是,数据分布不一定需要特意统计,也可以根据数据特点采用某种常见概率模型来近似,例如自然界的正态分布等;
(图)
另外,排序桶内元素需要选择一种合适的排序算法,比如快速排序。