等價關係:需要同時滿足下列三個性質的關係r
等價集合:如果乙個元素a 屬於集合s,則元素a的等價集合是集合s的乙個子集,它包含所有與元素a有等價關係的元素。
輸入資料最初是n個元素(元素也是乙個集合)的集合,其中每個集合只含有乙個元素,且互不相同,也不存在等價關係,使得這些集合互不相交,此時只能進行兩種運算:一種find操作,一種union操作。
find操作:返回包含給定元素的集合(等價集合)的名字
union操作:首先先判斷要進行此操作的兩個元素是否已經在同乙個等價集合中,若判斷兩個元素分別屬於不同的等價集合,則把含有a 和 b的兩個等價集合合併為乙個新的等價集合
注意:該演算法是動態的,因為在演算法的執行過程中,集合可以通過union操作而發生改變
基本資料結構:使用樹(tree)來表示乙個等價集合,乙個顆樹只有乙個根節點,所以等價集合的名字由根處的節點給出,同一顆樹上的節點具有共同的根節點,在執行find操作時,只要返回根節點資訊即可。注意:這裡指的樹不一定是二叉樹。由於只需要關心其父節點資訊,所以我們就可以使用乙個陣列來表示這棵樹,陣列的每個成員p[i]表示元素 i 的父親,如果 i 是根,那麼p[i] = 0。
那麼初始**如下:
for(i = 1; i <= 8; i++)
s[ i ] = 0;//代表每個元素集合互不相交
find操作**如下:
int find(int i, int s)
if(s [ i ] ==0)
return i;//返回此樹的根
else
return find(s[i], s);//否則不斷通過其父節點往上查詢,直至找到根
union(x, y)約定為y的根為x,union操作**如下:
void union(int s, int root1, int root2)
s [root2] = root1;
由於上面的合併是隨機的,這樣會存在乙個問題:這顆樹有時會退化為乙個鍊錶,導致find操作時間複雜度為o(n),因此我們需要按照一定的規則來進行合併:
按大小合併:使得總讓較小的樹成為較大的樹的子樹(根節點儲存節點個數的負值,初始時為-1)
void union(int s, int root1, int root2)
int temp;
temp = s[root1] + s[root2];
if(s[root1] < s[root2])
s[root2] = root1;
s[root1] = temp;
}else
s[root1] = root2;
s[root2] = temp;
}按高度合併:使得高度小的樹成為高度大的樹的子樹(根節點儲存高度的負值,初始時為0)
void union(int s, int root1, int root2)
if(s[root1] < s[root2])
s[root2] = root1;
}else
s[root1] = root2;
if(s[root1] == s[root2])
s[root2]--;
}路徑壓縮:從x到根的路徑上每乙個節點,都使它們的父節點變成根
find操作**如下:
int find(int i, int s)
if(s [ i ] <= 0)
return i;//返回此樹的根
else
return s[i] = find(s[i], s);//更新尋找根路徑上每乙個節點的父節點為根
並查集(不相交集合)
早上早早起來看kruscal的mst演算法,原來要用到不相交集合來實現。拿起 演算法導論 看完不相交集合這章,頓然茅塞頓開,終於完成並查集的基礎知識的學習。演算法導論 真是牛 不相交集合有兩種不同的實現,鍊錶表示和帶路徑壓縮的按秩合併策略。看到大家都比較喜歡用帶路徑壓縮的按秩合併策略,那麼我只認真研...
不相交集ADT
1.不相交集是解決等價關係的一種資料結構,執行合併和查詢的速度都非常快,m次執行合併和查詢的執行時間為 m logn 在乙個集合中,對於每一對元素 a,b a,b s,對於關係r如果滿足下面三個條件,則成關係r為等價關係 1 自反性 對於所有a s,ara 2 對稱性 arb當且僅當bra 3 傳遞...
不相交集ADT
首先我們必須明白不相交集這種資料結構是用來幹什麼的。不相交即主要用來實現動態等價問題的求解。動態 等價問題 這裡不再說明等價關係的概念,這個可以參考數理邏輯之類的書。假設我們有乙個集合和乙個等價關係 針對集合中的任意兩個元素 a 和 b,我們如何確定他們有等價關係 即a b.那麼我們需要等價類的概念...