並查集(不相交集)ADT

2021-08-16 22:37:44 字數 1939 閱讀 1597

等價關係:需要同時滿足下列三個性質的關係r

等價集合:如果乙個元素a 屬於集合s,則元素a的等價集合是集合s的乙個子集,它包含所有與元素a有等價關係的元素。

輸入資料最初是n個元素(元素也是乙個集合)的集合,其中每個集合只含有乙個元素,且互不相同,也不存在等價關係,使得這些集合互不相交,此時只能進行兩種運算:一種find操作,一種union操作。

find操作:返回包含給定元素的集合(等價集合)的名字

union操作:首先先判斷要進行此操作的兩個元素是否已經在同乙個等價集合中,若判斷兩個元素分別屬於不同的等價集合,則把含有a 和 b的兩個等價集合合併為乙個新的等價集合

注意:該演算法是動態的,因為在演算法的執行過程中,集合可以通過union操作而發生改變

基本資料結構:使用樹(tree)來表示乙個等價集合,乙個顆樹只有乙個根節點,所以等價集合的名字由根處的節點給出,同一顆樹上的節點具有共同的根節點,在執行find操作時,只要返回根節點資訊即可。注意:這裡指的樹不一定是二叉樹。由於只需要關心其父節點資訊,所以我們就可以使用乙個陣列來表示這棵樹,陣列的每個成員p[i]表示元素 i 的父親,如果 i 是根,那麼p[i] = 0。

那麼初始**如下:

for(i = 1; i <= 8; i++)

s[ i ] = 0;//代表每個元素集合互不相交

find操作**如下:

int find(int i, int s)

if(s [ i ] ==0)

return  i;//返回此樹的根

else

return find(s[i], s);//否則不斷通過其父節點往上查詢,直至找到根

union(x, y)約定為y的根為x,union操作**如下:

void union(int s,  int root1, int  root2)

s [root2] = root1;

由於上面的合併是隨機的,這樣會存在乙個問題:這顆樹有時會退化為乙個鍊錶,導致find操作時間複雜度為o(n),因此我們需要按照一定的規則來進行合併:

按大小合併:使得總讓較小的樹成為較大的樹的子樹(根節點儲存節點個數的負值,初始時為-1)

void union(int s,  int root1, int  root2)

int  temp;

temp = s[root1] + s[root2];

if(s[root1] < s[root2])

s[root2] = root1;

s[root1] = temp;

}else

s[root1] = root2;

s[root2] = temp;

}按高度合併:使得高度小的樹成為高度大的樹的子樹(根節點儲存高度的負值,初始時為0)

void union(int s,  int root1, int  root2)

if(s[root1] < s[root2])

s[root2] = root1;

}else

s[root1] = root2;

if(s[root1] == s[root2])

s[root2]--;

}路徑壓縮:從x到根的路徑上每乙個節點,都使它們的父節點變成根

find操作**如下:

int find(int i, int s)

if(s [ i ] <= 0)

return  i;//返回此樹的根

else

return s[i] = find(s[i], s);//更新尋找根路徑上每乙個節點的父節點為根

並查集(不相交集合)

早上早早起來看kruscal的mst演算法,原來要用到不相交集合來實現。拿起 演算法導論 看完不相交集合這章,頓然茅塞頓開,終於完成並查集的基礎知識的學習。演算法導論 真是牛 不相交集合有兩種不同的實現,鍊錶表示和帶路徑壓縮的按秩合併策略。看到大家都比較喜歡用帶路徑壓縮的按秩合併策略,那麼我只認真研...

不相交集ADT

1.不相交集是解決等價關係的一種資料結構,執行合併和查詢的速度都非常快,m次執行合併和查詢的執行時間為 m logn 在乙個集合中,對於每一對元素 a,b a,b s,對於關係r如果滿足下面三個條件,則成關係r為等價關係 1 自反性 對於所有a s,ara 2 對稱性 arb當且僅當bra 3 傳遞...

不相交集ADT

首先我們必須明白不相交集這種資料結構是用來幹什麼的。不相交即主要用來實現動態等價問題的求解。動態 等價問題 這裡不再說明等價關係的概念,這個可以參考數理邏輯之類的書。假設我們有乙個集合和乙個等價關係 針對集合中的任意兩個元素 a 和 b,我們如何確定他們有等價關係 即a b.那麼我們需要等價類的概念...