“稀疏表把同一“按二的幂分块”思想用于静态区间查询,数与矩阵的快速幂是它在乘法结构上的化身。并行环境中的指针跳跃与链表排名也反复把后继距离加倍,但评价指标变成总工作与并行深度。函数图上的第 $…”
形式陈述
List ranking 接口
给一条含 next[v] 表示的无环单链表,尾节点满足 next[tail]=null。本文把 rank 定义为节点到尾的原始边数,因此尾 rank 为 0,前驱为 1;若应用要从表头开始的下标,可由总长度和尾距离换算,不能混用两个方向。
初始化
每个节点记录一条当前跳指针和这条跳边代表的原链距离。
同步 pointer jumping
在并行算法模型中,每一轮让所有活跃节点并行读取上一轮快照。若
尾节点和已跳到 null 的节点保持不变。所有新值写到另一缓冲或在轮末统一发布;若原地边读边写,不同处理器会混合两个轮次,倍增不变量失效。
以初始化为第0轮,第 next[v] 非空,它恰指向原链上 dist[v] 等于从 null,dist[v] 就是到尾的完整距离。链长至多
直觉
每轮把当前后继替换为后继的后继,同时把两段距离相加,跳跃长度因而成倍增长。双缓冲让所有节点都读取同一个旧轮次,整个链在
例子与边界
四节点状态轨迹
原链为 a→b→c→d→null。初态距离是 (1,1,1,0)。
第一轮使用旧快照:a 跳到 c、距离 2;b 跳到 d、距离 2;c 跳到 null、距离 1;d 保持 0。第二轮 a 读取 c 的旧状态,得到 null 与距离 b 读取 d,距离仍为 2。
最终 (3,2,1,0) 正是到尾排名。若第一轮更新 c 后立刻让 a 读新 c,a 会提前跨越不同倍数,其他节点又仍在旧层;算法可能在简单链上碰巧得到距离,却不再有统一轮次证明。
Work、depth 与处理器
朴素方案每轮让所有
低 depth 并不等于 work-optimal:串行遍历只需
在
PRAM 冲突规则
单链上的非空后继映射在每轮仍为单射:不同原位置向前跳相同的
若输入改成多个节点共享后继的函数图,单射性就不成立,后继读取可能需要 CREW 或额外复制、调度。双缓冲负责旧新轮次分离,地址单射性负责排他读取;两份证明承担不同作用。
推论与应用
与 binary lifting 的区别
倍增表预处理 up[v][j],保留所有
两者都用倍增不变量,但本算法不调用预先保留全部层的倍增表,接口也不同:前者是静态查询索引,后者是并行收缩过程。需要恢复原链时,必须另存初始 next,不能指望最终全部为 null 的数组仍含结构。
失败边界
输入若含环,就没有尾距离,pointer jumping 会在环上周期跳转而不终止为 null。应先验证链结构、指定一个断点,或把问题改成 functional graph 的环检测与距离分解。
边带权时把初始 dist[v] 设为边权,更新仍用加法;负权不影响有限链求和,但可能溢出。多个不相交链可同时排名,尾节点各自为 0;共享尾的树形结构则不再是一条链,排名语义要重新定义。
参考资料
- David Karger, MIT6.854 Parallel Algorithms notes, “list ranking EREW”:后继加倍与距离累加。
- James Wyllie, The Complexity of Parallel Computations, PhD thesis, Cornell University, 1979.
- Joseph JáJá, An Introduction to Parallel Algorithms, Addison-Wesley, 1992.
- Richard Karp, Vijaya Ramachandran, Parallel Algorithms for Shared-Memory Machines, 1990.