1. 簡述
並查集是一種樹型的資料結構,用於處理一些不相交集合(Disjoint Sets)的合并及查詢問題。常常在使用中以森林來表示。
需要實現的操作有:合并兩個集合,判斷兩個元素是否屬於一個集合。
這裡介紹的主要是普通的並查集,很多情況下使用的並查集是需要擴充的,根據使用方式的不同,有很多差別,這裡僅僅是最基本的演算法。
2. 複雜度
T=O(n*α(n)) , 其中α(x),對於x=宇宙中原子數之和,α(x)不大於4。事實上,路經壓縮後的並查集的複雜度是一個很小的常數。
3. 虛擬碼
沒有使用路徑壓縮和啟發學習法的方法。
// 初始化並查集#define N 100int father[N];void init() { for(int i=0; i<N; i++) father[i] = i;}// 合并兩個元素所在的集合
void union(int x,int y) {
x = getfather(x);
y = getfather(y);
if(x!= y)
father[x]=y;
}
// 判斷兩個元素是否屬於同一個集合
bool same(int x,int y) {
return getfather(x)==getfather(y);
}
// 擷取根結點
int getfather(int x) {
while(x != father[x])
x = father[x];
return x;
}
使用路徑壓縮,改進getfather。
// 擷取根結點
int getfather(int x) {
if(x != father[x])
father[x] = getfather(father[x]); // 路徑壓縮修改的是father數組 return father[x];
}
另外,還可以改進union,把數量少的集合合并到數量大的集合中,不過這就要記錄每個集合中的元素數量,相當於增加了O(N)的儲存空間,而且在getfather中也應該保持對元素數量的維護,相對代碼複雜度偏高,而且感覺效能提升不多,這裡就不寫了。
4. 參考資料
維基百科