並查集是一種簡單的集合表示,它支持以下3種操作:
1)Union(S,Root1,Root2):把集合S中的子集合Root2併入子集合Root1。要求Root1和Root2互不相交,否則不執行合併。
2)Find(S,x):查找集合S中單元素x所在的子集合,並返回該子集合的名字。
3)Initial(S):將集合S中的每個元素都初始化爲只有一個單元素的子集合。
通常用樹(森林)的雙親表示法作爲並查集的存儲結構,每個子集合以一棵樹表示。所有表示子集合的樹,構成表示全集合的森林,存放在雙親表示數組內。通常用數組元素的下標代表元素名,用根結點的下標代表子集合名,根結點的雙親結點爲負數。
例如,若設有一個全集合爲S={0,1,2,3,4,5,6,7,8,9},初始化時每個元素自成一個單元素集合,每個子集合的數組值爲-1,如圖33-1所示。
圖33-1 並查集的初始化
經過一段時間的計算,這些子集合合併爲3個更大的子集合S1={0,6,7,8},S2={1,4,9},S3={2,3,5},此時並查集的屬性表示和存儲結構如圖33-2所示。
圖33-2 用樹表示並查集
爲了得到兩個子集合的並,只需將其中一個子集合根節點的雙親指針指向另一個集合的根節點。因此,S1∪S2可以有如圖33-3所示的表示。
圖33-3 S1∪S2可能的表示方法
在採用樹的雙親指針數組表示作爲並查集的存儲表示時,集合元素的編號從0到size-1。其中size是最大元素的個數。下面是並查集主要運算的實現。
並查集的結構定義:
#define SIZE 100
int UFSets[SIZE]; //集合元素數組(雙親指針數組)
並查集的初始化:
void Inital(int S[])
{
for(int i = 0; i < SIZE; ++i)
UFSets[i] = -1;
}
並查集的Find操作(查找並返回包含元素x的樹的根)
int Find(int UFSets[],int x)
{
while(UFSets[x] > 0)
x = S[x];
return x;
}
並查集的Union操作(兩個不相交的子集合的並集)
void Union(int S[],int Root1,int Root2)
{
S[Root2] = Root1;
}