並查集的實現

2021-10-04 09:48:17 字數 1851 閱讀 6303

給定乙個沒有重複值的整形陣列arr,初始時認為arr中每乙個數各自都是乙個單獨的集合。請設計一種叫unionfind的結構,並提供以下兩個操作。

boolean issameset(int a, int b): 查詢a和b這兩個數是否屬於乙個集合

void union(int a, int b): 把a所在的集合與b所在的集合合併在一起,原本兩個集合各自的元素以後都算作同乙個集合

[要求]

如果呼叫issameset和union的總次數逼近或超過o(n),請做到單次呼叫issameset或union方法的平均時間複雜度為o(1)

按照樹形結構給每個數設定自己的父親 可以用map或者陣列來表示

比如, , , , => [1, 1, 3, 4, 5, 6],陣列的下標表示數 值表示對應的父節點

如果乙個數沒有父節點,特別地設定該數的父節點為自身

陣列用parent來表示

要查詢乙個數所屬的集合(通過祖先來表示) 可以遞迴向上找到祖先結點(父節點等於自身的)

public

intfind

(int x)

return x;

}

上面這種方法就是單純的樹結構,但是這種方法在查詢的時候需要逐層向上查詢,但是實際上想知道數x的祖先是多少並不需要知道x的父親是多少,類似給葉子節點加上乙個指向根節點的指標的思想,直接將x的父親設定為x的祖先

public

intfind

(x)return parent[x]

;}

合併兩個數所在的集合不需要考慮合併的方法,只要合併後兩個數能夠找到同乙個祖先即可,再根據路徑壓縮的思想 直接把其中乙個的祖先設定為另乙個祖先的兒子

public

void

union

(int x,

int y)

parent[f1]

= f2;

}

上面的合併是兩者間隨意合併,現有樹t1和t2有以下兩種情況,合併後的樹為t3

t1合併到t2

t2合併到t1

假設t1的高度比t2的高度高

那麼情況1相比於情況2合併後的樹t3的高度會增加,也就會增大下次查詢的路徑長度

因此可以根據樹的高度 選擇較小的合併到較大的樹上

因此在初始化的時候引入新的陣列rank用來表示每棵樹的高度,這種方法也稱按秩合併

public

void

union

(int x,

int y)

int r1 = rank[f1]

;int r2 = rank[f2];if

(r1 > r2)

else

if(r1 == r2)

else

}

也可以換乙個標準,按照樹的結點數作為評估標準,此時rank表示每棵樹的結點個數

public

void

union

(int x,

int y)

int r1 = rank[f1]

;int r2 = rank[f2];if

(r1 > r2)

else

}

使用路徑壓縮和啟發式合併之後,並查集的每個操作平均時間為o(α

(n))

o(\alpha(n))

o(α(n)

),只說下結論可以看成常數時間

兩個陣列,複雜度o(n

)o(n)

o(n)

並查集 - oi wiki

並查集 並查集

本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...

java實現並查集

並查集是根據這篇博文學習的,寫得很不錯 下面是實現 public class unionfindset count n 合併p,q所在集合 param p param q public void union int p,int q if size rootp size rootq else coun...

C 實現並查集

將n個不同的元素分成一組不相交的集合。開始時,每個元素就是乙個集合,然後按規律將兩個集合進行合併。假如已知有n個人和m對好友關係 存於陣列r 如果兩個人是直接的或間接的好友關係 好友的好友的好友.則認為他們屬於同一好友圈,請求出這n個人中有幾個好友圈。例如 n 5,m 3,r 表示有5個人,1和2是...