所謂並查集,它是乙個集合,這個集合的元素也是集合,他支援三種操作:
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 而每個數又有屬於他自己的集合,例如,我們的任務就是判斷某兩個數是否屬於同乙個集合。我們把每個集合都可以看成是一棵樹,不知道什麼是樹的同學可以接著往下看 判斷兩個數是否屬於乙個集合,實際就是判斷他們的根節點是都是同乙個?劃重點,考...