生活随笔
收集整理的這篇文章主要介紹了
数据结构 之 并查集
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
并查集是一種樹型的數(shù)據(jù)結(jié)構(gòu),其保持著用于處理一些不相交集合(Disjoint Sets)的合并及查詢問題。
有一個聯(lián)合-查找算法(union-find algorithm)定義了兩個操作用于此數(shù)據(jù)結(jié)構(gòu):
- Find:確定元素屬于哪一個子集。它可以被用來確定兩個元素是否屬于同一子集。
- Union:將兩個子集合并成同一個集合。
下面代碼實現(xiàn)一些并查集中的一些基本操作:
一、并查集的初始化
假設(shè)現(xiàn)在有一個全集合為S= {0,1,2,3,4,5,6,7,8,9} ,初始化時,將每一元素都劃分成為一個單元素的集合。
如下圖所示:
這樣就初始化出10個單元素集合,每一個集合元素的parent值都是-1.
代碼實現(xiàn)過程:
[cpp]?view plaincopy
int?parent[100];?? ?? ?? ?? ?? void?ufset(int?s)?? {?? ????int?si=s;?? ????for(int?i=0;i<si;i++)?? ????parent[i]=-1;?? }?? 二、
合并Union
所謂合并,即是將兩個不相交的集合合并成為一個集合,這個過程將一個集合的parent修改成另一集合的parent。
代碼實現(xiàn)過程:
[cpp]?view plaincopy
?? ?? void?Union(int?root2,int?root1)?? {?? ????parent[root1]+=parent[root2];?? ????parent[root2]=root1;?? }??
舉個例子:初始化10個元素(如上圖所示),進(jìn)行下面的合并過程:
[cpp]?view plaincopy
ufset(10);???? ?? ????Union(6,0);?? ????Union(7,0);?? ????Union(8,0);?? ????Union(4,1);?? ????Union(9,1);?? ????Union(3,2);?? ????Union(5,2);??
合并之后的結(jié)果:
但是進(jìn)行這種合并之后,可能會出現(xiàn)一種不好的效果。如下圖:
我們稱之為一棵退化的樹。
那么如何進(jìn)行改進(jìn)呢?我們可以使用加權(quán)規(guī)則進(jìn)行合并。也就是將集合元素少的歸到集合元素多的中去。
例如:
下面給出代碼實現(xiàn):(注意下面這個方法存在錯誤,請看下面第二個方法,已修正錯誤。)
[cpp]?view plaincopy
?? void?WeightUnion(int?root2,int?root1)?? {?? ????int?r2=Find(root2);???? ????int?r1=Find(root1);?? ????int?temp;?? ????if(r1!=r2)?? ????{?? ????????temp=parent[r1]+parent[r2];?? ????????if(parent[r1]<parent[r2]){parent[r1]=temp;parent[r2]=r1;}???? ????????else?{parent[r1]=r2;parent[r2]=temp;}?? ????}?? }??
錯誤提醒:很感謝某位網(wǎng)友指出我上面段代碼的錯誤,由于一時疏忽上面WeightUnion這個方法有點錯誤!修改如下:
[cpp]?view plaincopy
?? void?WeightUnion(int?root2,int?root1)?? {?? ????int?r2=Find(root2);???? ????int?r1=Find(root1);?? ????int?temp;?? ????temp=parent[r1]+parent[r2];?? ????if(parent[r1]<=parent[r2])??? ?????? ?????? ????{???? ????????parent[r1]=temp;?????? ????????parent[r2]=r1;???? ????}???? ????else???? ????{???? ????????parent[r1]=r2;???? ????????parent[r2]=temp;???? ????}?????? }??
三、查找Find
我們知道,只有當(dāng)查找到的元素的parent值為負(fù)數(shù)(此時集合元素個數(shù)用這個負(fù)數(shù)表示),才表示找到根。
[cpp]?view plaincopy
?? ?? int?Find(int?x)??? {?? ????while(parent[x]>=0)?x=parent[x];?? ????return?x;?? }?? ? ? ? ? ? ? ?? 進(jìn)一步優(yōu)化,在查找過程中可以采用折疊規(guī)則壓縮路徑。
實現(xiàn)的代碼:
[cpp]?view plaincopy
?? ?? int?collapsingfind(int?i)?? {?? ????int?j;?? ????for(j=i;parent[j]>=0;j=parent[j]);??? ????while(i!=j)????? ????{?? ????????int?temp=parent[i];?? ????????parent[i]=j;?? ????????i=temp;?? ????}?? ????return?j;???? }??
附:上面代碼的完整版:
[cpp]?view plaincopy
#include?<iostream>?? using?namespace?std;?? ?? int?parent[100];?? ?? ?? ?? ?? void?ufset(int?s)?? {?? ????int?si=s;?? ????for(int?i=0;i<si;i++)?? ????parent[i]=-1;?? }?? ?? ?? ?? int?Find(int?x)??? {?? ????while(parent[x]>=0)?x=parent[x];?? ????return?x;?? }?? ? ? ? ? ? ? ?? ?? ?? ?? int?collapsingfind(int?i)?? {?? ????int?j;?? ????for(j=i;parent[j]>=0;j=parent[j]);??? ????while(i!=j)????? ????{?? ????????int?temp=parent[i];?? ????????parent[i]=j;?? ????????i=temp;?? ????}?? ????return?j;???? }?? ?? ?? ?? void?Union(int?root2,int?root1)?? {?? ????parent[root1]+=parent[root2];?? ????parent[root2]=root1;?? }?? ?? ?? void?WeightUnion(int?root2,int?root1)?? {?? ????int?r2=Find(root2);???? ????int?r1=Find(root1);?? ????int?temp;?? ????if(r1!=r2)?? ????{?? ????????temp=parent[r1]+parent[r2];?? ????????if(parent[r1]<parent[r2]){parent[r1]=temp;parent[r2]=r1;}???? ????????else?{parent[r1]=r2;parent[r2]=temp;}?? ????}?? }?? ?? int?main()?? {?? ????ufset(10);???? ?? ????Union(6,0);?? ????Union(7,0);?? ????Union(8,0);?? ????Union(4,1);?? ????Union(9,1);?? ????Union(3,2);?? ????Union(5,2);?? ?? ????for(int?i=0;i<10;i++)?cout<<parent[i]<<"?";?? ????return?0;?? } ?
總結(jié)
以上是生活随笔為你收集整理的数据结构 之 并查集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。