1 并查集是一种树形数据结构,经常用于处理一些集合之间的操作。不同集合在并查集以不同的树来表示,一般每棵树的根节点会作为当前集合的代表元
想要查询两个集合是否在同一集合中,只需要比较两个元素所在集合的代表元是否相同即可
2 并查集的初始化
//假设一开始有n个元素,这些元素初始都是独立的,一开始构成n个集合,每个集合的代表元都是元素自己
const int maxn=100005;
int fa[maxn];//fa数组记录每个元素由谁代表
int sz[maxn];//sz数组代表每个集合元素个数
int dep[maxn];//dep数组记录每个集合的树深度
void initalize(int n){
for(int i=1;i<=n;i++){
fa[i]=i;
sz[i]=dep[i]=1;
}
}
3 集合合并
//先找到x,y对应的代表元
//将其中一个代表元的fa指向另外一个
int findset(int x){
if(x==fa[x])
return x;
fa[x]=findset(fa[x]);
return fa[x];
}
void union(int x,int y){
int fx=findset(x),fy=findset(y);
if(fx==fy) return;
fa[fx]=fy;
}
4 路径压缩:在查询代表元的过程中,把沿途的每个结点fa都设为集合代表元
int findset(int x){
if(x==fa[x])
return x;
fa[x]=findset(fa[x]);
return fa[x];
}
//简写
int findset(int x){
return x==fa[x]? x:(fa=findset(fa[x]));
}
5 启发式合并
//在合并集合时,选择包含元素个数少的集合,将它合并到另外一个集合中,使需要改变代表元的元素尽量少
void union(int x,int y){
int fx=findset(x),fy=findset(y);
if(fx==fy) return;
if(sz[fx]>sz[fy])
swap(fx,fy);
fa[fx]=fy;
sz[fy]+=sz[fx];
}
6 按深度合并
//每次合并的时候,将深度比较小的合并到深度比较大的一方,并更新一下新集合的深度即可
void union(int x,int y){
int fx=findset(x),fy=findset(y);
if(fx==fy) return;
if(dep[fx]>dep[fy]) swap(fx,fy);
fa[fx]=fy;
if(dep[fx]==dep[fy])
dep[fy]++;
}