並查集 學習詳解

2021-06-20 13:33:01 字數 1802 閱讀 5801

出處:勇幸|thinking (

昨天和今天學習了並查集和trie樹,並練習了三道入門題目,理解更為深刻,覺得有必要總結一下,這其中的內容定義之類的是取自網路,操作的說明解釋及程式的注釋部分為個人理解。

並查集學習:

一種簡單的用途廣泛的集合. 並查集是若干個不相交集合,能夠實現較快的合併和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數等。最完美的應用當屬:實現kruskar演算法求最小生成樹。

1、make_set(x) 把每乙個元素初始化為乙個集合

初始化後每乙個元素的父親節點是它本身,每乙個元素的祖先節點也是它本身(也可以根據情況而變)。

2、find_set(x) 查詢乙個元素所在的集合

查詢乙個元素所在的集合,其精髓是找到這個元素所在集合的祖先!這個才是並查集判斷和合併的最終依據。

判斷兩個元素是否屬於同一集合,只要看他們所在集合的祖先是否相同即可。

合併兩個集合,也是使乙個集合的祖先成為另乙個集合的祖先,具體見示意圖

3、union(x,y) 合併x,y所在的兩個集合

合併兩個不相交集合操作很簡單:

利用find_set找到其中兩個集合的祖先,將乙個集合的祖先指向另乙個集合的祖先。如圖

1、find_set(x)時 路徑壓縮

尋找祖先時我們一般採用遞迴查詢,但是當元素很多亦或是整棵樹變為一條鏈時,每次find_set(x)都是o(n)的複雜度,有沒有辦法減小這個複雜度呢?

答案是肯定的,這就是路徑壓縮,即當我們經過"遞推"找到祖先節點後,"回溯"的時候順便將它的子孫節點都直接指向祖先,這樣以後再次find_set(x)時複雜度就變成o(1)了,如下圖所示;可見,路徑壓縮方便了以後的查詢。

2、union(x,y)時 按秩合併

即合併的時候將元素少的集合合併到元素多的集合中,這樣合併之後樹的高度會相對較小。

注意:

**中路徑壓縮時秩不需變化的,正如eillen所說,秩只是表示節點高度的乙個上界

如果用秩進行計數,路徑壓縮也是不需要變化的

因為所屬集合的根節點的秩在合併時已經更新,其他子節點的秩不用到也無需再變化;

int father[max];   /* father[x]表示x的父節點*/

int rank[max]; /* rank[x]表示x的秩*/

/* 初始化集合*/

void make_set(int x)

/* 查詢x元素所在的集合,回溯時壓縮路徑*/

int find_set(int x)

return father[x];}

/*按秩合併x,y所在的集合

下面的那個if else結構不是絕對的,具體根據實際情況變化

但是,宗旨是不變的即,按秩合併,實時更新秩。*/

void union(int x, int y)

else

father[x] = y;}}

另外,我認為寫並查集時涉及到的路徑壓縮,最好用遞迴,一方面**的可讀性非常好,另一方面,可以更直觀的理解路徑壓縮時在回溯時完成的巧妙。

入門練習:

1161解題報告

2524解題報告

出處:勇幸|thinking (

並查集 學習詳解

include includeusing namespace std int m,n int i,j,maxnum int father 30005 num 30005 void makeset int n for i 0 i 主要的思想是 當合併集合的時候,如果待合併的兩個元素不在同乙個集合,則執...

並查集詳解

其實並查集顧名思義就是有 合併集合 和 查詢集合 兩種操作的關於資料結構的一種演算法。並查集演算法不支援分割乙個集合。用集合中的某個元素來代表這個集合,該元素稱為集合的代表元。乙個集合內的所有元素組織成以代表元為根的樹形結構。對於每乙個元素 parent x 指向x在樹形結構上的父親節點。如果x是根...

詳解並查集

並查集主要用來求解不相交集合的問題,主要針對於合併和查詢兩種演算法。並查集的實現主要包含了三個部分 並查集的初始化是對單個資料建立了乙個單獨的集合,每個集合應該包含以下兩個資料 由以上兩個資料,一般的並查集的結構一般有兩種表示形式 結構體構造如下 define max 50 struct node ...