基本模板
int f[10000];
void init(int n){
for(int i=1;i<=n;i++)
f[i]=i;
}
//非递归
int getf(int a) {
int root = a;
while (f[root] != root)
root = f[root];
int tmp;
while (a != root) {
tmp = f[a];
f[a] = root;
a = tmp;
}
return root;
}
//递归
int getf(int a){
if(f[a]==a)return a;
else return f[a]=getf(f[a]);
}
void merge(int a, int b) {
a = getf(a);
b = getf(b);
if (a != b) {
f[b] = a;
}
}
bool same(int a,int b){
return getf(a)==getf(b);
}
并查集的优化
int f[10000];
int rank[10000];//存储树的高度
void init(int n){
for(int i=0;i<n;i++){
f[i]=i;
rank[i]=0;
}
}
int getf(int a){
if(f[a]==a)return a;
else return f[a]=getf(f[a]);
}
void merge(int a,int b){//主要是这里的优化
a=getf(f[a]);
b=getf(f[b]);
if(a==b)return;
if(rank[a]<rank[b]){
f[a]=b;
}else{
f[b]=a;
//若两棵树原本一样高,则高度会增加
if(rank[a]==rank[b]) rank[a]++;
}
}
并查集删除
- 首先每个节点不再指向自己而是另一个比不会出现的节点,类似于将每个节点放到一个盒子中
- 这样,删除时只需要把这个节点从当前盒子拿出来,放到另一个盒子中
- 由于节点之间都是通过盒子来确定关系的,所以盒子中元素是否存在并不影响节点之间的关系
int index; //存放盒子节点使用到哪一个了
int f[22222];
void init(int n)
{
index = n+1;
for(int i=1;i<=n;i++) //普通节点指向他的盒子节点
f[i] = index++;
for(int i=n+1;i<=2*n;i++) //盒子节点指向自己就像一般的并查集一样
f[i] = i;
}
void del(int n)
{
f[n] = index; //将要删除的节点重新指向一个新的盒子
f[index] = index++ ; //盒子节点指向自己
}
int getf(int a){
if(f[a]==a)return a;
else return f[a]=getf(f[a]);
}
void merge(int a, int b) {
a = getf(a);
b = getf(b);
if (a != b) {
f[b] = a;
}
}
注意:这种方法要保证空间足够大,不然会出错。
应用
- 判断图是否联通。