对并查集来说,可能正常情况下会退化为链表,就是树太高了,那我们如何改变呢,那就用路径压缩了,以下用两种路径压缩的方法。
原来的未路径压缩
int find(int x){
int s=x;
while(pre[s]!=s){
s=pre[s]; //当s不是根节点,指向它的父节点
}
return s;
}
接下来提供两个路径压缩方法,当然会有缺陷,就是会破坏rank,但你可以不用管它,根据对比和概率来说,继续保留rank会更好,虽然rank被破坏,但在随机性上来说,还是保留更好。
简单的路径压缩
int find(x){
int s=x;
while(pre[s]!=s){
pre[s]=pre[pre[s]]; //该节点指向其爷爷节点,若父亲节点是根节点,该式子也成立
s=pre[s]; //跳到他的新父亲节点
}
return s;
}
下面写出基于递归的优秀路径压缩
int find(x){
int p=x;
if(p==pre[p]){
return p; //此时根节点为p
}
else{
pre[p]=find(pre[p]); //一直递归 找到祖先
return pre[p]; //实际上 ,所有的pre[x]=祖先
}
}
上式要理解一下,假设有一条链a->b->c->d>e;
开始pre[a]=b,pre[b]=c,pre[c]=d,pre[d]=e,pre[e]=e;
然后一直执行pre[s]=find(pre[s]);
直到
if(p==pre[p]){
return p; //此时根节点为p
}
然后一直执行return pre[s];会发现pre[s]不断改变为e返回e。