并查集由一个整数型的数组和两个函数组成
pre[]数组记录了每个点的前导点是什么,函数find()是查找,函数merge()是合并。
初始化函数,让自己就是自己的掌门
void init()
{
for(int i=1;i<=n;i++)
pre[i]=i;
}
这里不知道谁是掌门,每个人只知道自己的上级是谁,要想找掌门就要一级一级向上查。
查找根节点
int find(int r)//查找r的掌门(根节点)
{
while(pre[r]!=r)//如果r的上级不是r自己,说明r不是掌门
{
r=pre[r];//让r接着找她的上级,直到找到掌门为止
}
return r;//找到掌门啦
}
路径压缩算法查找元素:
int find(int r)
{
if(pre[r]==r){
return r;
}else{
/*路径压缩,每次函数在返回的时候,把各自的上级改为掌门,
这样能提高找到掌门的速度*/
pre[r]=find(pre[r]);
return pre[r];
}
}
改成如下图所示的样子 6的上级是4,4的上级是2,2的上级是1,通过find函数知道6的掌门人是1,路径压缩就是让2,4的掌门人也是1。
非递归方式的路径压缩:
int find(int x){
int r=x;
while(pre[r]!=r){
r=pre[r];
}
int i=x;
int t;
while(i!=r){
t=pre[i];//在改变上级之前临时变量t记录他的值
pre[i]=r;//把上级改为根节点
i=t;
}
return r;
}
合并 判断 u,v是否连通,如果没连通,就把她们所在的连通分支合并起来。
void merge(int u,int v)
{
int t1=find(u);
int t2=find(v);
if(t1!=t2)//判断他们的掌门是否相同
{
pre[t2]=t1;//靠左原则(其实随便啦)让t2的掌门是t1
}
}