定義:「合併集合」和「查詢集合中的元素」兩種操作的關於資料結構的一種演算法。
演算法:用集合中的某個元素來代表這個集合,該元素稱為集合的代表元。
乙個集合內的所有元素組織成以代表元為根的樹形結構。
對於每乙個元素 parent[x]指向x在樹形結構上的父親節點。如果x是根節點,則令parent[x] = x。
對於查詢操作,假設需要確定x所在的的集合,也就是確定集合的代表元。可以沿著parent[x]不斷在樹形結構中向上移動,直到到達根節點。
判斷兩個元素是否屬於同乙個集合,只需要看他們的代表元是否相同即可
包括對所有單個的資料建立乙個單獨的集合(即根據題目的意思自己建立的最多可能有的集合,為下面的合併查詢操作提供操作物件)
在每乙個單個的集合裡面,有三個東西。
集合所代表的資料。(這個初始值根據需要自己定義,不固定)
這個集合的層次通常用rank表示(一般來說,初始化的工作之一就是將每乙個集合裡的rank置為0)。
這個集合的類別parent(有的人也喜歡用set表示)(其實就是乙個指標,用來指示這個集合屬於那一類,合併過後的集合,他們的parent指向的最終值一定是相同的。)
(有的簡單題裡面集合的資料就是這個集合的標號,也就是說只包含2和3,1省略了)
初始化的時候,乙個集合的parent都是這個集合自己的標號。沒有跟它同類的集合,那麼這個集合的源頭只能是自己了。
(最簡單的集合就只含有這三個東西了,當然,複雜的集合就是把3指標這一項新增內容,如pku食物鏈那題,我們還可以新增enemy指標,表示這個物種集合的天敵集合;food指標,表示這個物種集合的食物集合。隨著指標的增加,並查集操作起來也變得複雜,題目也就顯得更難了)
對於合併操作,假設需要合併的兩個集合的代表元分別為x和y,則只需要令parent[x]= y或者parent[y]= x即可。為了使合併後的樹不產生退化,即使樹中左右子樹的深度差盡可能小,對於每乙個元素x,維護rank[x]為以x為根的子樹的深度。合併時,如果rank[x]
——結構體法——
#define max 10000
struct node
node[max];
/***查詢集合i(乙個元素是乙個集合)的源頭(遞迴實現)。
如果集合i的父親是自己,說明自己就是源頭,返回自己的標號;
否則查詢集合i的父親的源頭。
**/int get_parent(int x)
//合併集合
void union(int a,int b)
}
——陣列法——
int set[max];//集合index的類別,或者用parent表示
int rank[max];//集合index的層次,通常初始化為0
int data[max];//集合index的資料型別
//初始化集合
void make_set(int i)
//查詢集合i(乙個元素是乙個集合)的源頭(遞迴實現)
int find_set(int i)
//合併集合(將代表元合併即可)
void union(int i,int j)
}
並查集(合併,查詢)
並查集用於管理元素分組情況的資料結構,判斷某一組合是否存在於同一集合 擁有同一性質 樹形結構實現但非二叉樹,但是通過rank比較可以優化為類似平衡二叉樹 int par 1000000 int rank 1000000 統計樹的深度 int size 1000000 統計每一棵樹結點個數 void ...
並查集 合併集合,連通塊中點的數量
練習題 includeusing namespace std const int n 1e6 int n,m int p n 儲存每個點的祖宗節點 返回x的祖宗結點 路徑壓縮 int find int x int main return 0 給定乙個包含n個點 編號為1 n 的無向圖,初始時圖中沒有...
並查集合集
題目1 include include include include include includeusing namespace std const int maxn 1e6 10 int pre maxn maxx maxn num maxn int findfather int x whil...