并查集(Disjoint Set Union, DSU)维护一组互不相交的集合,支持两种操作:
find(x):返回x所在集合的代表(根)union(a, b):把a和b所在的集合合并
底层数据结构非常简洁:用一个 parent[] 数组,parent[i] 指向 i 的父节点,根节点的 parent 指向自己。
两个关键优化
朴素实现退化成链时 find 是 O(n)。两个标准优化把均摊复杂度降到几乎 O(1):
- 路径压缩:
find(x)上溯到根之后,把路径上的所有节点的 parent 直接指向根,下次访问就是 O(1) - 按 rank 合并:合并两棵树时,让较矮的挂到较高的下,避免树长高
两者合用,每次操作的均摊复杂度是 O(α(n)),α 是反阿克曼函数,对任何合理大小的 n 都不超过 4。
在动画里看什么
- 红圈 是根节点;蓝色 是被高亮的节点(当前操作涉及的)
- 节点下方的
rk是 rank(树高近似上界) union时先各自find找根,根不同才会真正合并find时高亮整条上溯路径,然后路径压缩把它们一次性挂到根下,可以看到指针从一条链变成一个扇形