V

算法可视化

ZHEN
分享到微博分享到 XGitHub 仓库个人主页
学习工具算法复杂度速查算法学习路径
数据结构数组链表栈队列树堆哈希表图字典树并查集LRU 缓存跳表线段树B+ 树布隆过滤器树状数组
经典排序算法冒泡排序鸡尾酒排序双调排序选择排序插入排序二分插入排序希尔排序归并排序自顶向下归并快速排序三路快排双轴快排堆排序计数排序基数排序桶排序
图算法Dijkstra 最短路Kruskal 最小生成树Prim 最小生成树Bellman-Ford 最短路拓扑排序Floyd 多源最短路强连通分量2-SAT最大流二分图匹配LCA 倍增欧拉路径
动态规划编辑距离0-1 背包完全背包最长公共子序列最长递增子序列硬币找零方案数石子合并旅行商 TSP树形 DP数位 DP换根 DP
回溯与搜索N 皇后子集生成全排列组合总和迷宫寻路岛屿数量单词搜索数独A* 寻路
字符串KMP 字符串匹配Rabin-KarpBoyer-MooreManacher后缀数组LCP / height 数组AC 自动机Z 函数
数学与数论埃氏筛线性筛欧几里得算法快速幂扩展欧几里得中国剩余定理欧拉函数米勒-拉宾FFTPollard's Rho
计算几何凸包旋转卡壳最近点对线段相交扫描线求交
查找二分查找二分边界旋转数组搜索二分答案三分查找

桶排序 Bucket Sort

经典排序 · 非比较 · 分桶 + 桶内排序 + 合并

什么是桶排序

桶排序不直接两两比较全体,而是按值域把元素撒进若干「桶」:每个桶负责一段连续的取值范围。撒完后每个桶内部各自排序,最后按桶的先后顺序把各桶依次倒出拼接,整体就有序了。它和计数排序、基数排序同属非比较的线性排序。

桶排序怎么做

分三步,对应下面播放器里高亮的三段代码:

①分配(distribute):遍历数组,按值算出该进哪个桶(这里取 ⌊v / 10⌋,每桶宽 10),把元素追加进去。②桶内排序(sortBucket):对每个桶各自排序——桶内元素少,用插入排序很快;空桶直接跳过。③合并(concat):按桶 0、1、2…的顺序,把每个桶里已排好的元素依次写回原数组。因为「桶之间已经按值域有序、桶内也各自有序」,拼起来自然全局有序。

下面固定 8 个数 [29, 25, 3, 49, 9, 37, 21, 43],分成 5 个桶(0–9 / 10–19 / 20–29 / 30–39 / 40–49)。点「下一步」看它怎么把数撒进桶(留意 10–19 是个空桶)、桶 20–29 内部 [29, 25, 21] 怎么排成 [21, 25, 29],再合并回主轨。

29
25
3
49
9
37
21
43
0–9
10–19
29
20–29
30–39
40–49

读 a[0]=29,⌊29/10⌋=2 → 入桶「20–29」

1function bucketSort(a: number[]): number[] {
2 const buckets: number[][] = Array.from({ length: 5 }, () => []);
3 for (const x of a) buckets[Math.min((x / 10) | 0, 4)].push(x);
4 for (const b of buckets) b.sort((x, y) => x - y);
5 let w = 0;
6 for (const b of buckets)
7 for (const x of b) a[w++] = x;
8 return a;
9}
n8
阶段分配
i0
v29
桶20–29
1 / 22

复杂度与适用

设 n 个元素分到 k 个桶。若数据大致均匀分布,每桶约 n/k 个,桶内排序总代价摊薄到接近线性,平均 O(n + k);额外空间 O(n + k),且是稳定排序。但分布若极不均匀——所有元素挤进同一个桶——就退化成「单个桶内排序」,最坏 O(n²)(或 O(n log n),取决于桶内用什么排序)。所以桶排序的前提是对数据分布有把握。

计数排序:桶 = 单个值(桶里只记「出现几次」)。
桶排序:桶 = 一段值域(桶里装实际元素,还要桶内排序)。
基数排序:按位多轮分配收集,每轮桶 = 一个数字 0–9。

桶排序在哪里用

最典型的是把 [0, 1) 上均匀分布的浮点数排序(按小数大小分桶)、或对成绩、年龄这类取值范围已知且分布较均匀的数据排序。它也是「先粗分、再细排」这一分治思想的直观范例——线性排序三件套(计数 ✓ 基数 ✓ 桶 ✓)至此补齐。