並查集結構可以用於:
(1)檢查兩個元素是否屬於同乙個集合:
比如對於圖1這個例子來說,如果我們想要檢查節點d和節點e是否屬於同乙個集合,可以這樣操作:
d節點往上找其父節點,一直往上找,直到某個節點的父節點是其本身,此時停止(找到了節點a);
e節點也按照相同的步驟往上找其父節點,找到節點a;
如果這兩個節點往上找到的最終父節點相同,那麼可以說它們是屬於同乙個集合的。
(2)可以把兩個元素各自屬於的集合合併在一起:
比如對於圖2這個例子,怎樣將兩個集合合併在一起呢?
首先我們算一下集合1中節點的個數,是3。然後我們再計算集合2中的節點個數,是2。哪乙個集合的元素個數少,就把那個集合掛接在集合元素個數多的集合上面。
首先我們先定義乙個節點的類:
public static class node
}
然後開始定義並查集結構:
public static class unionfindset
// 這裡給出的節點是儲存在list裡面的
public void makeset(listnodes)
} // 這個函式用於尋找某個節點的最終節點(遞迴版本)
public node findheadrecur(node node)
node father = fathermap.get(node);
if (father != node)
fathermap.put(node, father);
return father;
} // 非遞迴版本findhead函式,這個很清晰,就是模擬了遞迴過程入棧和出棧的過程
public node findheadnonrecur(node node)
stackstack = new stack();
node cur = node;
node father = null;
father = fathermap.get(cur);
while (cur != father)
fathermap.put(cur, father);
while (!stack.isempty())
return father;
} // 看兩個元素是否屬於同乙個集合,只需要看它們的父節點是否為同乙個節點
public boolean issameset(node a, node b)
// 合併兩個集合,看集合的元素個數
public void union(node a, node b)
node afather = findheadrecur(a);
node bfather = findheadrecur(b);
if (afather != bfather) else
}} }
並查集可以延伸至島問題的求解
什麼是島問題?下面先介紹一下島問題的基本解法,之後會延伸出使用並查集來解決分塊矩陣的島問題
比如,乙個矩陣只有0和1兩種值,每個位置都可以和自己的上下左右四個位置相連。如果有一片1連在一起,則這個部分稱為乙個島。問,給定乙個矩陣,求這個矩陣中有多少個島?
比如給定的矩陣是這樣的:
可以看到,這個矩陣的島的數量是3個。
可以使用乙個感染函式遞迴地求解,感染函式每次遇到乙個1,都將其變成2,然後在看這個1的上下左右有沒有1,有的話也標記為2,這樣就不會重複地計算已經統計過的1了。
列出**:
public static int containsisland(int matrix)
} return res; }
// 感染函式
public static void infect(int matrix, int m, int n, int i, int j)
matrix[i][j] = 2;
// 遞迴
infect(matrix, m, n, i + 1, j);
infect(matrix, m, n, i, j + 1);
infect(matrix, m, n, i - 1, j);
infect(matrix, m, n, i, j - 1);
}
這個解法適用於矩陣不是很大的情況。
如果矩陣很大,我們可以將矩陣分塊,先分別計算每乙個分塊兒矩陣中島的數量,以及需要留意它們的邊界資訊。
對於矩陣1,它有2兩個島;對於矩陣2,它也有兩個島。所以島的數量暫時先為4個。
然後,比較兩個矩陣相鄰邊界的資訊,如圖5中藍色部分。
對於過程1:相鄰部分都為1,且a與c之前並沒有合併過(並查集),可以合併(使用並查集中的union方法),此時島的數量 = 4 - 1 = 3。
對於過程2:相鄰部分都為1,但是a與c之前合併過(並查集中的issameset方法),此時島的數量不變。
對於過程3:相鄰部分有0,跳過。
對於過程4,相鄰部分都為1,且b與c之前並沒有合併過(並查集),可以合併(使用並查集中的union方法),此時島的數量 = 3 - 1 = 2。
過程5與過程3相同。
所以最終島的總數為2。
以上是我對演算法學習的乙個歸納與總結,水平有限望理解,如有錯誤請指出。
參考:左程雲《演算法班課程》
資料結構與演算法之並查集
並查集 union find 是一種高效的資料結構,主要的操作有 為方便敘述,把所有元素視作點,元素之間的關係視作線,存在聯絡便存在關係 需要注意的是,這裡的關係應當是1.自反的,2.對稱的,3.傳遞的 所謂合併,便是將兩個點之間 畫 一條線。又上邊的定義不難理解相連的若干點之間互相存在關係,這樣我...
演算法基礎之資料結構 並查集
題目 合併計算 一共有 n 個數,編號是 1 n,最開始每個數各自在乙個集合中。現在要進行 m 個操作,操作共有兩種 m a b,將編號為 a 和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作 q a b,詢問編號為 a 和 b 的兩個數是否在同乙個集合中 輸入格式 第一...
資料結構之並查集
並查集 union find sets 是一種簡單的用途廣泛的集合.並查集是若干個不相交集合,能夠實現較快的合併和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數 最小公共祖先 帶限制的作業排序,還有最完美的應用 實現kruskar演算法求最小生成樹。其實,這一部分 演算法導論 講的很精...