對並查集來說,可能正常情況下會退化爲鏈表,就是樹太高了,那我們如何改變呢,那就用路徑壓縮了,以下用兩種路徑壓縮的方法。
原來的未路徑壓縮
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。