并查集的概念
并查集,从字面意思上理解,支持合并和查找操作的集合。
其主要是用来判断联通问题,也就是图中两点间是否存在道路可以连通。
并查集主要分为两种基本操作:
- 合并(Union/Merge):合并两个集合。
- 查询(Find/Get):查询元素所属集合。
在下面这篇文章中我会具体描述。
具体实现
一. 理论实现:
首先,我们建立一个数组 f a [ fa[ fa[ ] ] ] 用来存储并查集中的关系, f a [ i ] fa[i] fa[i] 就表示 i i i 的父节点,也就是父亲。
- 初始化:初始时每一个节点都表示一个集合,即 f [ i ] = i f[i]=i f[i]=i。
- 查询:每一个节点不断递归寻找自己的父节点,若某节点的父节点就是自己,那么它就是整个集合的根节点,就返回该点。
- 合并:合并时只需要合并两个节点的根节点, f a [ R o o t A ] = R o o t B fa[RootA]=RootB fa[RootA]=RootB, R o o t A RootA RootA和 R o o t B RootB RootB分别表示两个集合的根节点。
二. 代码实现
- 初始化模板
void init(int n){
for(int i=1;i<=n;i++)fa[i]=i;
}
- 查询模板
int Find(int x){
if(fa[x]==x)return x;
else return Find(fa[x])
}
- 合并模板
void Union(int x,int y){
int fx=Find(x),fy=Find(y);
if(fx!=fy)fa[fx]=fy;
}
三.优化
- 路径压缩:实际上,我们在查询过程中只关心根结点是什么,并不关心这棵树的形态(有一些题除外)。因此我们可以在查询操作的时候将访问过的每个点都指向树根,这样的方法叫做路径压缩,单次操作复杂度为
O
(
l
o
g
N
)
O(logN)
O(logN),如果你还不是很明白,请看下图
四.优化代码实现
int Find(int x){
if(x==fa[x])return x;
return fa[x]=Find(fa[x]);
}