如何将C语言实现带路径压缩的并查集算法改写为长尾关键词?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1115个文字,预计阅读时间需要5分钟。
非递归写法(例如while循环+栈模拟)容易漏掉根节点,导致压缩不彻底。递归天然而然保证:
常见错误是写成「先改当前节点 parent,再调 find(parent)」,这会跳过中间层更新。正确做法是先递归获取根,再统一赋值:
int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); // 先递归到底,再回写 } return parent[x]; }
- 必须用
parent[x] = find(parent[x]),不能写成find(parent[x]); parent[x] = root(root 未定义) - 如果用迭代,需两遍扫描:第一遍找根,第二遍从 x 向上逐个重连,代码更长且易错
- gcc/clang 对这种尾递归有一定优化,深度 10⁵ 一般不会栈溢出;若真担心,可加编译器 pragma 或手动扩栈
unionSets 里要不要按秩合并?不加会怎样?
不加按秩合并(即只做 parent[rootY] = rootX),最坏情况下树退化成链,find 退化为 O(n),路径压缩虽能缓解单次查询,但连续 union+find 混合操作时,均摊性能仍不如带秩合并。
按秩合并本质是控制树高,和路径压缩正交互补。两者共用才能达到近乎 O(α(n)) 的均摊复杂度(α 是反阿克曼函数,实际 ≤ 4)。
本文共计1115个文字,预计阅读时间需要5分钟。
非递归写法(例如while循环+栈模拟)容易漏掉根节点,导致压缩不彻底。递归天然而然保证:
常见错误是写成「先改当前节点 parent,再调 find(parent)」,这会跳过中间层更新。正确做法是先递归获取根,再统一赋值:
int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); // 先递归到底,再回写 } return parent[x]; }
- 必须用
parent[x] = find(parent[x]),不能写成find(parent[x]); parent[x] = root(root 未定义) - 如果用迭代,需两遍扫描:第一遍找根,第二遍从 x 向上逐个重连,代码更长且易错
- gcc/clang 对这种尾递归有一定优化,深度 10⁵ 一般不会栈溢出;若真担心,可加编译器 pragma 或手动扩栈
unionSets 里要不要按秩合并?不加会怎样?
不加按秩合并(即只做 parent[rootY] = rootX),最坏情况下树退化成链,find 退化为 O(n),路径压缩虽能缓解单次查询,但连续 union+find 混合操作时,均摊性能仍不如带秩合并。
按秩合并本质是控制树高,和路径压缩正交互补。两者共用才能达到近乎 O(α(n)) 的均摊复杂度(α 是反阿克曼函数,实际 ≤ 4)。

