用於不相交集合的資料操作 並查集

2021-06-22 13:33:37 字數 2584 閱讀 9836

假定有一組詞彙,其中有一些詞是同義詞,可以把意思不同的詞分別放到不同的集合中,構成一組不相交的集合,每個集合內部都是同義詞。最開始我們不知到哪些詞可以歸併到相同的組中,因此開始的時候它們每個詞為一組。然後我們再一一給出哪些詞是同義詞,據此將初始的組進行合併……直到最後同義詞都被合併到各自應該歸屬的組裡面。

講的簡單點,假定這些單詞是乙個個的整數,他們構成了一組不相交的動態集合 s=

,,每個集合可能包含乙個或多個元素,並選出集合中的某個元素作為代表。每個集合中具體包含了哪些元素是不關心的,具體選擇哪個元素作為代表一般也是不關心的。我們關心的是,對於給定的元素,可以很快的找到這個元素所在的集合(的代表),以及合併兩個元素所在的集合,而且這些操作的時間複雜度都是常數級的。

這就是並查集的問題,並查集的基本操作有三個:

makeset(s):建立乙個新的並查集,其中包含 s 個單元素集合。

unionset(x, y):把元素 x 和元素 y 所在的集合合併,要求 x 和 y 所在的集合不相交,如果相交則不合併。

find(x):找到元素 x 所在的集合的代表,該操作也可以用於判斷兩個元素是否位於同乙個集合,只要將它們各自的代表比較一下就可以了。

1.並查集的森林表示

並查集的實現原理也比較簡單,就是使用樹來表示集合,樹的每個節點就表示集合中的乙個元素,樹根對應的元素就是該集合的代表,如圖 1 所示。

圖 1 並查集的樹表示

圖中有兩棵樹,分別對應兩個集合,其中第乙個集合為

,代表元素是

a ;第二個集合為

,代表元素是

e 。

樹的節點表示集合中的元素,指標表示指向父節點的指標,根節點的指標指向自己,表示其沒有父節點。沿著每個節點的父節點不斷向上查詢,最終就可以找到該樹的根節點,即該集合的代表元素。

2.構造並查集並初始化

現在,假設使用乙個足夠大的的連續空間來儲存樹節點,那麼 makeset 要做的就是構造出如圖 2 的森林,其中每個元素都是乙個單元素集合,即父節點是其自身:

圖 2 構造並查集初始化

3.並查集的find操作

接下來,就是 find 操作了,如果每次都沿著父節點向上查詢,那時間複雜度就是樹的高度,完全不可能達到常數級。這裡需要應用一種非常簡單而有效的策略——路徑壓縮。路徑壓縮,就是在每次查詢時,令查詢路徑上的每個節點都直接指向根節點,如圖 3 所示。

圖 3 路徑壓縮

4.並查集的合併操作

最後是合併操作 unionset,並查集的合併也非常簡單,就是將乙個集合的樹根指向另乙個集合的樹根,如圖 4 所示。

圖 4 並查集的合併

這裡也可以應用乙個簡單的啟發式策略——按秩合併。該方法使用秩來表示樹高度的上界,在合併時,總是將具有較小秩的樹根指向具有較大秩的樹根。簡單的說,就是總是將比較矮的樹作為子樹,新增到較高的樹中。為了儲存秩,需要為節點增加乙個成員rank,並將其值初始化為 0。(樹的秩:從樹的根節點x到某一後代葉節點的最長簡單路徑上邊的數目)

5.源**

#include #include #include #include using namespace std;

const int max = 20; //節點總數

const int num = 50; //操作次數

//節點定義

class node

};//並查集類操作定義

class uf;

//建構函式,批量申請記憶體並初始化

uf::uf()

}//析構函式,釋放空間

uf::~uf()

//查詢本家族代表單詞

node* uf::find(node *r) else

}//合併兩個家族

void uf::unit(node *x, node *y) else

} }}//列印所有節點的資訊,以供參考(當max大於20時建議不要用該函式)

void uf::print()

cout << endl;

cout << "祖先:";

for(node* p = s; p < s + max; p++)

cout << endl;

cout << "大小:";

for(node* p = s; p < s + max; p++)

cout << endl;

cout << "秩: ";

for(node* p = s; p < s + max; p++)

cout << endl;

}//測試函式

int main()

}

並查集(不相交集合)

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

用於不相交集合的資料結構(並查集)

一,兩個重要操作 1 找出給定元素所屬的集合 2 合併兩個集合 二,原理 保持一組不相交的動態集合s 每個集合通過乙個代表來識別,代表即集合中的某個元素 三,操作 1 make set x 建立乙個新的集合,其唯一成員就是x 因各集合是不相交的,故要求x沒有在其他集合 現過 2 union x,y ...

不相交集合的資料結構 並查集

在介紹操作之前,我得先說說實現這些操作的背景。對於並查集中的每乙個集合,都有乙個代表,這個代表就是集合中的乙個元素,其表示了整個集合。打個比喻吧,最近召開了19大,各個代表都召集到了人民大會堂,假設每個代表都代表著某個省份的人去參加會議,比如我是江西的,江西省的人大代表就代表了江西人民參加會議進行投...