乙個集合s,集合中乙個元素a。a的等價類是s的乙個子集,該子集包含所有與a有關係的元素。
等價類形成是對s的乙個劃分且s中的每乙個成員恰好出現在乙個等價類中。這樣,判斷a與b是否有關係,
只需要判斷a與b是否在乙個等價類中即可。
對於集合s劃分,取任意兩個等價類,si與sj,如果si∩sj = ∅,則稱這些集合不相交。
對於不相交集,有兩種操作,union/find操作。find操作找包含給定元素的集合(等價類)名字。
union把兩個等價類合併成乙個新的等價類。
資料結構:採用樹來表示每乙個集合(等價類),因為樹上的元素都有乙個共同的根。
union(x, y),將x,y合併成乙個新的等價類,且x做為根。
這樣的構造方法,最壞情況下可以構建一課高度為n-1的樹,即union(7,8), union(6,7), union(5,6)……
這使得find操作在n-1次操作下才能找到樹根,執行時間o(n)
將上述森林用陣列表示,約定陣列1-8個元素對應的值代表其父親,例如元素8對應的值為7,表示其父親為7。
而5對應的值為0,表示5本身就是樹根。
這樣找樹根就是乙個遞迴過程,如:find(8), 父親為7, 執行find(7),父親為5,執行find(5),對應值為0,表示5為樹根,遞迴結束,
這樣即找到8所在等價類的樹根為5。判斷6,8是否有關係,即find(8) == find(6)是否成立。
typedef int settype;
typedef int elementtype;
typedef int* disjset;
disjset initialize(int num)
void destroy(disjset s)
void union(disjset s, settype root1, settype root2)
settype find(disjset s, elementtype x)
int main()
為了避免樹的深度過大,可以每次讓深度大的樹做為新根,這樣減少樹深度增加速率。
那麼就需要記住當前根的深度,而由於我們只採用了乙個陣列,所以,可以讓根的值為負值,代表深度。
這樣,根節點的值為-1,表示深度為-1。
對於上述情形,執行union(4,5)。按照之前的union操作,得到結果為:
優化後結果
對應優化後結果的陣列如下:
}對於比較深的樹,find操作還是比較耗時的,要一步一步遞迴直至樹根。
執行一次find(8)操作。由於元素8所在樹的樹根為5,所以執行find後,陣列要變成。
這樣,當進行下一次呼叫find(8)的時候,能夠快速找到8對應的樹根。
settype find(disjset s, elementtype x)
不相交集應用 kruskal演算法
問題描述 已知含有n個頂點的帶權連通無向圖,採用鄰接矩陣儲存,鄰接矩陣以三元組的形式給出,只給出不包括主對角線元素在內的下三角形部分的元素,且不包括不相鄰的頂點對。分別採用prim演算法和kruskal演算法,求該連通圖的最小生成樹的權值之和。輸入形式 第一行給出結點個數n和三元組的個數count,...
不相交集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.那麼我們需要等價類的概念...