理论
定义
并查集是一种维护集合的数据结构,它的名字中“并”“查”“集“分别取自Union(合并)、Find(查找)、Set(集合)这三个单词。也就是说,并查集之锤下面两个操作:
1.合并:合并两个集合。
2.查找:判断两个元素是否在一个集合。
并查集一般就是用一个father数组实现,表示其父亲结点。
基本操作
初始化
for(int i=0;i<=N;i++){
father[i]=i;//father[i]=-1也行 此处习惯用i
}
查找
int findFather(int x){
if(x==father[x]) return x;
return findFather(father[x]);
}
查找优化(让并查集的高度尽量低一点) 即路径压缩
int findFather(int x){
if(x==father[x]) return x;
else{
int F=findFather4(father[x]);//注意是father[x]
father[x]=F;//回溯过程中一步步退回来更改每个结点的根
return F;
}
}
合并
int Union(int a,int b){
int faA=findFather(a);
int faB=findFather(b);
if(faA!=faB){
father[faA]=faB;
}
}
例子
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int maxn=100;
int father[maxn];
//查找 返回x所在集合根节点
int findFather(int x){
while(x!=father[x]){//如果不是根节点,继续循环
x=father[x];
}
//最后father[x]=x肯定就是根x了
return x;
}
//查找 递归实现
int findFather(int x){
if(x==father[x]) return x;
return findFather2(father[x]);//注意调用findFather2
}
//合并
int Union(int a,int b){
int faA=findFather(a);
int faB=findFather(b);
if(faA!=faB){
father[faA]=faB;
}
}
//路径压缩 边找边改
int findFather3(int x){
int a=x;
while(x!=father[x]){
x=father[x];
}
//此时x是根 a是原始节点 走过的结点现在都直接让他指向根
while(a!=father[a]){
int z=a;
a=father[a];//循环的下一步
father[z]=x;//每个走过的结点都直接指向根
}
return x;
}
//路径压缩递归写法
int findFather4(int x){
if(x==father[x]) return x;
else{
int F=findFather4(father[x]);//注意是father[x]
father[x]=F;//回溯过程中一步步退回来更改每个结点的根
return F;
}
}
int main(){
freopen("input.txt","r",stdin);
int N;
cin>>N;
//初始化
for(int i=0;i<=N;i++){
father[i]=i;//father[i]=-1也行 此处习惯用i
}
return 0;
}