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
计算几何凸包旋转卡壳最近点对线段相交扫描线求交
查找二分查找二分边界旋转数组搜索二分答案三分查找

双调排序(排序网络)

经典排序算法 · 比较器网络 · 深度 O(log²n),可并行

一张写死的「排序电路」

前面 15 个排序都是程序:看数据、做判断、决定下一步。双调排序是另一个物种——排序网络:一张固定的「电路图」,n 条水平线(wire)上按固定位置放比较器(连接两条线,把小值送一端、大值送另一端)。比较器的位置与顺序在排序开始前就定死,与数据完全无关。正因如此,同一列的比较器互不相干、可以同时执行——这是 GPU 和硬件排序的思想根基。

先造双调,再合并

双调序列指「先升后降」(或其循环移位)。网络分两阶段:构造——递归地把前半排成升序、后半排成降序,拼在一起就是双调;双调合并——对双调序列做一轮距离 n/2 的成对比较交换,它会神奇地裂成两个双调半区、且前半整体 ≤ 后半,距离减半递归下去就全有序。n=8 展开后是 6 列、24 个比较器:总比较次数 O(n log²n) 比快排多,但每列并行,墙钟时间只有 6 拍。

下面固定输入 [5,2,7,1,8,3,6,4]。点「下一步」逐列看:8 条水平线左端标着当前值,比较器竖线上的小三角指着大值要去的方向;琥珀是正在执行的列(4 个比较器同时动)、绿色是已执行的列。走完第 3 列(列 2),序列变成 [1,2,5,7,8,6,4,3]——升到 8 再降,完美双调;后 3 列距离 4→2→1 合并,第 6 拍全有序。右侧代码随每一步同步高亮。

52718364

这是一张固定的「排序网络」:24 个比较器排成 6 列,位置与数据无关——同一列的比较器互不相干,可以并行执行

1function bitonicSort(a: number[]): void {
2 const n = a.length; // n 为 2 的幂
3 for (let k = 2; k <= n; k *= 2) { // 阶段:构造长度 k 的双调段
4 for (let j = k >> 1; j >= 1; j >>= 1) { // 一列:比较距离 j(同列可并行)
5 for (let i = 0; i < n; i++) {
6 const l = i ^ j; // 与 i 距离 j 的伙伴
7 if (l > i) {
8 const asc = (i & k) === 0; // 该段方向:升 or 降
9 if (asc ? a[i] > a[l] : a[i] < a[l])
10 [a[i], a[l]] = [a[l], a[i]]; // 比较交换(比较器)
11 }
12 }
13 }
14 }
15}
n / 列数8 / 6
并行深度log²n 级 = 6 拍
1 / 8

为什么值得多做几次比较

数据无关:比较器序列固定 → 无分支、无随机访存,天生适合硬件/SIMD/GPU。
并行深度:同列并行,总深度 log n·(log n+1)/2 列 = O(log²n) 拍。
双调合并:距离 n/2 的一轮比较把双调裂成「有序的两个双调半区」。
0-1 原理:只要网络能排好所有 0/1 序列,就能排好任意序列——排序网络的正确性基石。

对比一下:快排在 CPU 上无可匹敌,但它的分支和数据依赖让 GPU 难受;双调排序多做常数倍比较,换来完全规整的并行结构,是显卡排序、外部归并预排序的常客。同族的还有 Batcher 奇偶归并网络(比较器更少)与理论上 O(log n) 深度的 AKS 网络(常数巨大,纸面冠军)——「排序」这件事,在并行世界里有一套自己的谱系。