“稀疏表把同一“按二的幂分块”思想用于静态区间查询,数与矩阵的快速幂是它在乘法结构上的化身。并行环境中的指针跳跃与链表排名也反复把后继距离加倍,但评价指标变成总工作与并行深度。函数图上的第 $…”
List ranking 接口 ​
给一条以 next[v] 表示的无环单链表,尾节点满足 next[tail]=null。本文把 rank 定义为节点到尾的原始边数,因此尾 rank 为 0,前驱为 1;若应用要从表头开始的下标,可由总长度和尾距离换算,不能混用两个方向。
初始化
每个节点记录一条当前跳指针和这条跳边代表的原链距离。
同步 pointer jumping ​
每一轮所有活跃节点并行读取上一轮快照。若
尾节点和已跳到 null 的节点保持不变。所有新值写到另一缓冲或在轮末统一发布;若原地边读边写,不同处理器会混合两个轮次,倍增不变量失效。
第 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 冲突规则 ​
每个节点只写自己的新记录,所以写是 exclusive。读取时,处理器
对一般 functional graph,多节点还可能共享同一后继,使并发读更明显。EREW 实现要复制目标记录或安排更复杂的读调度,并计入额外成本;不能只因为写目标不同就声称 EREW。
与 binary lifting 的区别 ​
倍增表预处理 up[v][j],保留所有
两者都用 doubling 不变量,但接口不同:前者是静态查询索引,后者是并行收缩过程。需要恢复原链时,必须另存初始 next,不能指望最终全部为 null 的数组仍含结构。
失败边界 ​
输入若含环,就没有尾距离,pointer jumping 会在环上周期跳转而不终止为 null。应先验证链结构、指定一个断点,或把问题改成 functional graph 的环检测与距离分解。
边带权时把初始 dist[v] 设为边权,更新仍用加法;负权不影响有限链求和,但可能溢出。多个不相交链可同时排名,尾节点各自为 0;共享尾的树形结构则不再是一条链,排名语义要重新定义。
参考资料
- 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.