並查集簡要分析

2021-07-04 22:11:47 字數 1290 閱讀 9031

並查集:(union-find sets)

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

並查集的精髓(即它的三種操作,結合實現**模板進行理解):

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

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

2、findset(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)時 按秩合併

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

int father[max];

int rank[max];

void makeset(int x)

int findset(int x)//遞迴實現路徑壓縮查詢

if (x!=father[x])

return father[x];

}int findset(int x)//非遞迴實現路徑壓縮

return root;

}int union(int x,int y)

//按秩合併,x的秩大說明高度比較高,更接近與根結點.

//所以將x作為y的根結點

if (rank[x]>rank[y])

else

father[x] = y;

} return 1;//返回1說明x和y不屬於乙個集合

}

並查集 並查集

本文參考了 挑戰程式設計競賽 和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 ...

並查集 程式自動分析

原題鏈結 規模太大,先用離散化縮小。考慮所有相等條件,把所有相等的變數 進同乙個集合中。考慮所有不等條件,若兩個變數處於同一集合中,則證明無法同時滿足這兩個條件。實現 include define n 100000 10 using namespace std int n,m int a 2 n f...

並查集 程式自動分析

給你兩個邏輯關係,判斷是否有衝突 先將兩個邏輯分開來看,前乙個邏輯存在那麼後乙個邏輯一定不存在,如果存在那麼答案就錯誤了,可以用並查集維護,詳細見 define fre yes include include include const int n 1000005 struct message ar...