并查集模板
简介
并查集是一种数据结构,用于处理一组不相交的集合的 合并 和 查询 问题
它支持两种操作:
-
查找(Find):确定某个元素处于哪个子集
-
合并(Union):将两个子集合并成一个集合
实现
初始化
void make_set(int siz)
{
for(int i = 1; i <= siz; i++){
fa[i] = i;
rk[i] = 0;
}
}
查找
int find_set(int x)
{
if(x == fa[x])
return x;
else
return find_set(fa[x]);
}
这样虽然能达成目的但效率显然太低,我们可以将路径上的每个节点直接连接到根上,这就是 路径压缩
int find_set(int x)
{
if(x != fa[x])
fa[x] = find_set(fa[x]);
return fa[x];
}
合并
void union_set(int x, int y)
{
int u = find_set(x);
int v = find_set(y);
if(u == v)
return;
fa[u] = v;
}
在合并操作中我们也有优化方法 按秩合并 ,我们在每个节点上维护一个秩 rk[x]
用于表示表示该节点的高度,在合并时让具有较小秩的根指向较大秩的根
void union_set(int x, int y)
{
int u = find_set(x);
int v = find_set(y);
if(u == v)
return;
if(rk[u] > rk[v]) {
fa[v] = u;
}else{
fa[u] = v;
if(rk[u] == rk[v])
rk[v]++;
}
}
完整模板
const int MAX_N = 10000 + 5;
int fa[MAX_N];
int rk[MAX_N];
void make_set(int siz)
{
for(int i = 1; i <= siz; i++) {
fa[i] = i;
rk[i] = 0;
}
}
int find_set(int x)
{
if(x != fa[x])
fa[x] = find_set(fa[x]);
return fa[x];
}
void union_set(int x, int y)
{
int u = find_set(x);
int v = find_set(y);
if(u == v)
return;
if(rk[u] > rk[v]) {
fa[v] = u;
}else{
fa[u] = v;
if(rk[u] == rk[v])
rk[v]++;
}
}