並查集與kruskal最小生成樹

2021-06-11 15:57:27 字數 1576 閱讀 1244

1、 概述

並查集(disjoint set或者union-find set)是一種樹型的資料結構,常用於處理一些不相交集合(disjoint sets)的合併及查詢問題。

a.乙個集合是一棵樹,

b.根節點下標代表集合名稱,根節點的父為為負數,絕對值表示集合中的元素個數。

並查集的重要知識點:a.加權規則,即並兩個沒有交集的集合,元素個數少的集合加到元素個數多的集合裡

b.並集合後,為了改進樹的效能,使用摺疊規則來「壓縮路徑」。雖然增加了完成所有單個元素搜尋的時間,幾乎增加一倍。但是,他能減少最壞情況下一系列 搜尋操作所需時間

2、 基本操作

並查集是一種非常簡單的資料結構,它主要涉及3個基本操作,分別為:

a. 合併兩個不相交集合union(root1,root2)

b.    find(x):搜尋單元素x所在的集合,並返回該集合的名字

c.  ufsets(s):建構函式,將並查集中s個元素初始化為s個只有乙個單元素的子集合

(1) 合併兩個不相交集合(union(x,y))

合併操作很簡單:先設定乙個陣列father[x],表示x的「父親」的編號。那麼,合併兩個不相交集合的方法就是,找到其中乙個集合最父親的父親(也就是最久遠的祖先),將另外乙個集合的最久遠的祖先的父親指向它。

上圖為兩個不相交集合,b圖為合併後father(b):=father(g)

(2) 判斷兩個元素是否屬於同一集合(find_set(x))

本操作可轉換為尋找兩個元素的最久遠祖先是否相同。可以採用遞迴實現。

3、 優化

(1) find_set(x)時,路徑壓縮

尋找祖先時,我們一般採用遞迴查詢,但是當元素很多亦或是整棵樹變為一條鏈時,每次find_set(x)都是o(n)的複雜度。為了避免這種情況,我們需對路徑進行壓縮,即當我們經過」遞推」找到祖先節點後,」回溯」的時候順便將它的子孫節點都直接指向祖先,這樣以後再次find_set(x)時複雜度就變成o(1)了,如下圖所示。可見,路徑壓縮方便了以後的查詢。

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

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

4、 程式設計實現

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;

} }

4.並查集的重要應用:等價類的劃分

最小生成樹 kruskal 並查集

題目描述 如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz 輸入輸出格式 輸入格式 第一行包含兩個整數n m,表示該圖共有n個結點和m條無向邊。n 5000,m 200000 接下來m行每行包含三個整數xi yi zi,表示有一條長度為zi的無向邊連線結點xi yi 輸出格式 輸出...

Kruskal演算法(貪心 並查集 最小生成樹)

kruskal演算法 克魯斯卡爾 演算法 的高效實現需要一種稱作並查集的結構。我們在這裡不介紹並查集,只介紹kruskal演算法的基本思想和證明,實現留在以後討論。kruskal演算法的過程 1 將全部邊按照權值由小到大排序。2 按順序 邊權由小到大的順序 考慮每條邊,只要這條邊和我們已經選擇的邊不...

Kruskal演算法(貪心 並查集 最小生成樹)

2016年04月16日 17 34 35 kruskal演算法的高效實現需要一種稱作並查集的結構。我們在這裡不介紹並查集,只介紹kruskal演算法的基本思想和證明,實現留在以後討論。kruskal演算法的過程 1 將全部邊按照權值由小到大排序。2 按順序 邊權由小到大的順序 考慮每條邊,只要這條邊...