並查集演算法

2021-06-20 12:07:04 字數 2419 閱讀 7510

所謂並查集,它是乙個集合,這個集合的元素也是集合,他支援三種操作:

makeset(x),建立乙個只有乙個元素x的集合x0,將這個集合放入並查集中;

findset(x),在並查集中尋找乙個元素s(注意並查集的元素s也是集合) ,滿足

x屬於s; union(x,y), 將並查集中的元素s1,s2合併,其中x屬於s1,y屬於s2。

下面說說並查集的實現,其實很簡單,用樹來實現。所有屬於同一集合的元素屬於

同一棵樹,這樣我們就可以用樹根來表示乙個集合,要找到某個元素屬於哪個集合

,只要找到這個元素所在的樹的樹根;要合併兩個集合,只要合併兩棵樹。一般比

較方便的方法是用父親陣列parent來表示樹,parent[i]就是節點i的父結點,樹

根的父結點就是它本身。這樣很容易根據某個節點找到他的根,也很容易合併兩棵

樹。但是我們要考慮效率問題。在最壞的情況下,一棵樹退化成乙個單鏈表(想象

一下所有的結點只有唯一的兒子節點),這樣如果鍊錶長度為l,從乙個節點找到

他的根也需要l次運算,對於一共有n個節點元素的並查集,findset平均情況和最

壞情況下的複雜度都是o(n),效率並不高。對於一棵樹而言,如果樹的高度為h,

那麼從葉節點只要經過h次運算就可以找到樹根,所以我們應該儘量減少樹的高度

,最好的情況是樹的高度只有1層,這樣就是乙個樹根下面有很多兒子,這些兒子

都是樹葉。但是如果兩棵這樣的樹合併,數的高度就會增加,比如高度為h1的樹

t1和高度為h2的樹t2合併,得到的樹的高度有兩種情況: max 或者

max,前一種情況是t2的根作為t1的根的兒子,後一種情況則是t1的根

作為t2的根的兒子。這就說明經過多次union操作以後,樹的高度會增加。為了使

得樹的高度盡量地小,我們應該將較矮的樹合併到較高的樹上,因此我們用乙個數

rank記錄每棵樹的高度,rank[i]就是以i為根的子樹的高度,在合併的時候就可以

根據rank的值進行合併,union的**如下:

// 合併x,y所在的集合,並返回交集

int union(int x, int y)

else

}union其實是一種啟發式演算法,rank[i]就是啟發函式值。

另外,為了降低樹的高度,我們在findset的時候也會壓縮路徑,比如原來a是樹根

,b是a的兒子,c是b的兒子,d是c的兒子,我們呼叫findset(d)找d所在的樹的樹

根,在找的同時,我們改變該樹的結構,使得呼叫findset(d)結束以後樹的結構變

為a是樹根,b是a的兒子,c也是a的兒子,d也是a的兒子。這就叫做路經壓縮。因

此findset**如下:

// 返回到元素i所屬的集合的代表元素, 同時進行路徑壓縮

int findset(int i)

else

}並查集的效率很高,可以證明,通過這種樹形結構實現的帶啟發式路徑壓縮的並查

集,findset和union操作的平均代價是o(lgn),這和二分查詢的複雜度一致,可以

證明這已經是理論上最好的演算法了,不可能有更好的演算法了。如果不進行這種路經

壓縮的話,並查集就退化成了鍊錶,在同一鍊錶中的元素屬於同一集合,這樣的話

findset的複雜度是o(n)。

並查集也是很常用的資料結構,有一道題目「親戚」,也要用並查集:

題目: 親戚(relations)

或許你並不知道,你的某個朋友是你的親戚。他可能是你的曾祖父的外公的女

婿的外甥女的表姐的孫子。如果能得到完整的家譜,判斷兩個人是否親戚應該是可

行的,但如果兩個人的最近公共祖先與他們相隔好幾代,使得家譜十分龐大,那麼

檢驗親戚關係實非人力所能及。在這種情況下,最好的幫手就是計算機。

為了將問題簡化,你將得到一些親戚關係的資訊,如同marry和tom是親戚,

tom和ben是親戚,等等。從這些資訊中,你可以推出marry和ben是親戚。請寫乙個

程式,對於我們的關於親戚關係的提問,以最快的速度給出答案。

參考輸入輸出格式 輸入由兩部分組成。

第一部分以n,m開始。n為問題涉及的人的個數(1 ≤ n ≤ 20000)。這些人的

編號為1,2,3,…,n。下面有m行(1 ≤ m ≤ 1000000),每行有兩個數ai, bi,表示

已知ai和bi是親戚。

第二部分以q開始。以下q行有q個詢問(1 ≤ q ≤ 1 000 000),每行為ci,

di,表示詢問ci和di是否為親戚。

對於每個詢問ci, di,若ci和di為親戚,則輸出yes,否則輸出no。

樣例輸入與輸出

輸入relation.in

10 7

2 45 7

1 38 9

1 25 6

2 33

3 47 10

8 9輸出relation.out

yesno

yes

並查集演算法

並查集是一種樹型的資料結構,用於處理一些不相交集合 disjoint sets 的合併及查詢問題。常常在使用中以森林來表示。讓每個元素構成乙個單元素的集合,也就是按一定順序將屬於同一組的元素所在的集合合併。1 makeset s 建立乙個新的並查集,包含s個單元素集合。2 union x,y 把x ...

並查集演算法

includeint pre 10 int find int x 查詢祖先節點 int i x,j while i r 壓縮路徑 return r void join int x,int y int main 2 食物鏈問題 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈...

並查集演算法

並查集是一種資料結構。首先,我們有一群數,1,2 3,4,5 1115 而每個數又有屬於他自己的集合,例如,我們的任務就是判斷某兩個數是否屬於同乙個集合。我們把每個集合都可以看成是一棵樹,不知道什麼是樹的同學可以接著往下看 判斷兩個數是否屬於乙個集合,實際就是判斷他們的根節點是都是同乙個?劃重點,考...