1. 并查集是一种树型的数据结构,用于处理一些不相交集合S={S1, S2, …, Sn},每个集合Si都有一个特殊元素,称为集合的代表元。
2. 朴素的并查集支持三种操作:
初始化:把元素xi加到集合Si中。每个集合Si只有一个独立的元素xi,并且元素xi就是集合Si的代表元素。
查找:查找xi所在集合Si的代表root[Si]。
合并:把x和y所在的两个不同集合合并。
3. 我们利用不相交的结合森林实现并查集。我们使用有根树来表示集合,树中的每个节点包含一个成员,每棵树代表一个集合。每棵树的根包含集合的代表,并且是自己的父节点。通过双亲表示法(即保存每个结点的父节点)存储这棵树,这样可以方便地找到任意元素所在集合的代表元。
如图就是一个不相交集合森林。两棵树表示两个集合。
左边的树表示集合{b, c, e, h},其中c作为集合的代表;
右边的树表示集合{d, f, g},其中f作为集合的代表。
4. 代码去实现一个朴素的并查集:
1)初始化:将每个元素的父结点设为自己。
void init() {
for(int i=1; i<=n; i++) {
fa[i]=i;
}
}
2)查找:返回待查找元素的所在集合的代表元。如果树是一棵直线树,查找的复杂度会退化为O(n),不可取,怎么办?使用路径压缩技巧。
int find(int x) {
return x==fa[x] ? x : fa[x]=find(fa[x]);
}
3)合并:将一个集合的树根指向另一个集合的树的一个结点(最好是树根)。判断两个元素是否属于同一集合,只需要看他们的代表元是否相同即可。
bool merge(int x, int y) {
int fx=find(x), fy=find(y);
if(fx==fy) return false;
else {
fa[fx]=fy;/*根据需要,可以将fy改成y或y所在集合中的其他元素。
可以使用按秩合并或随机合并。*/
return true;
}
}
5. 但是并查集不会这么简单。我们都知道普通并查集可以理解为查看集合间的关系和集合间的合并。但是要考虑集合内元素的关系呢,就需要带权并查集。
带权并查集不仅记录集合间关系,还记录集合内元素间的关系(元素间连线的权值)。带权并查集主要分为两类:区间统计类和种类并查集。这个介绍会在kuangbin的专题里面更新内容以例题来介绍.
当然了,还有逆向并查集。