并查集(Disjiont-set)
更新
- 5/23/2018 更新路径压缩代码
简介
wiki上关于并查集的简介
在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作:
- Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
- Union:将两个子集合并成同一个集合。
并查集主要用于解决动态连通性问题(我也不懂是什么问题).
我们用一个代表来标识一个不交集. 通常我们不关心哪个成员作为代表, 但是对于属于同一个集合的两个变量, 查询应该得到相同的代表.
举个栗子. 假如有一个大型的计算机网络, 其中有很多台计算机, 如果计算机a与计算机b连通, b与c连通, 那么a与c连通. 对于网络中的两台计算机p, q我们可能有这些操作: 判断p, q是否连通find(p) == find(q)
; 在p, q之间建立一条路线使两者连通union(p, q)
.
通过上面的例子不难看出连通是一种等价关系, 它有以下性质:
- 自反性: p与p是连通的
- 对称性: p与q连通, 则q与p连通
- 传递性: p与q连通且q与r连通, 则p与r连通
算法实现
首先我们用一个数组记录所有元素, 对于set[i] == k
, i
表示一个元素, k
表示元素所属的集合, 通常可以指向或者间接指向集合的代表来表示属于这个集合. 当set[i] == i
是表明i
是一个根节点.
set[i] ==k
可以理解为i
, k
之间有一条连通的路线, 被称为链接.
初始化
让所有元素指向自己, 表示属于不同的集合, 此时集合中每个元素都是一个根节点
const int SIZE = 100001;
int set[SIZE];
void init(int n) {
for (int i = 1; i <= n; ++i)
set[i] = i;
}
Find
从x向上查找, 直到找到元素的根节点set[i] == i