並查集java實現
並查集定義
並查集是一種樹型的資料結構,用於處理一些不相交集合(disjoint sets)的合併及查詢問題。常常在使用中以森林來表示。
借鑑一個看到的故事
江湖上散落著各式各樣的大俠,有上千個之多。他們沒有什麼正當職業,整天揹著劍在外面走來走去,碰到和自己不是一路人的,就免不了要打一架。但大俠們有一個優點就是講義氣,絕對不打自己的朋友。而且他們信奉“朋友的朋友就是我的朋友”,只要是能通過朋友關係串聯起來的,不管拐了多少個彎,都認為是自己人。這樣一來,江湖上就形成了一個一個的幫派,通過兩兩之間的朋友關係串聯起來。而不在同一個幫派的人,無論如何都無法通過朋友關係連起來,於是就可以放心往死了打。但是兩個原本互不相識的人,如何判斷是否屬於一個朋友圈呢?
我們可以在每個朋友圈內推舉出一個比較有名望的人,作為該圈子的代表人物。這樣,每個圈子就可以這樣命名“中國同胞隊”美國同胞隊”……兩人只要互相對一下自己的隊長是不是同一個人,就可以確定敵友關係了。
但是還有問題啊,大俠們只知道自己直接的朋友是誰,很多人壓根就不認識隊長要判斷自己的隊長是誰,只能漫無目的的通過朋友的朋友關係問下去:“你是不是隊長?你是不是隊長?”這樣,想打一架得先問個幾十年,餓都餓死了,受不了。這樣一來,隊長面子上也掛不住了,不僅效率太低,還有可能陷入無限迴圈中。
於是隊長下令,重新組隊。隊內所有人實行分等級制度,形成樹狀結構,我隊長就是根節點,下面分別是二級隊員、三級隊員。每個人只要記住自己的上級是誰就行了。遇到判斷敵友的時候,只要一層層向上問,直到最高層,就可以在短時間內確定隊長是誰了。由於我們關心的只是兩個人之間是否是一個幫派的,至於他們是如何通過朋友關係相關聯的,以及每個圈子內部的結構是怎樣的,甚至隊長是誰,都不重要了。所以我們可以放任隊長隨意重新組隊,只要不搞錯敵友關係就好了。於是,門派產生了。
程式碼實現:
在程式碼中,通常使用一個 parent陣列表示所有元素,陣列下標表示具體每一個元素,每個陣列值表示該元素對應的父節點(也就是它的上級),如果該元素是根節點或者是單獨的節點,該元素的值為自己本身,如 parent[3] = 3
例子:
public class QuickFindUF {
private int[] parent = new int[5]; //定義長度為5的陣列,表示每個元素
public void init() { //初始化陣列,開始時,每個元素指向自己
for(int i = 0; i < parent.length; i++) {
parent[i] = i;
}
}
private int root(int i) { //找到節點i的根節點
while(i != parent[i]) {
i = parent[i];
}
return i;
}
public void union(int p, int q) { //快速合併p q兩個節點:先找到兩個根節點,然後將其中一個根節點指向另一個根節點
int proot = root(p);
int qroot = root(q);
parent[proot] = qroot;
}
public boolean connected(int p, int q) { //判斷節點p和q是否相連
return root(p) == root(q);
}
public static void main(String[] args) {
init();
union(0, 2);
union(1, 4);
}
}
典型應用:
並查集常常用來判斷在一個圖中是否存在迴路(是否可以生成樹),以及用來判斷圖的聯通性問題
在本問題中, 樹指的是一個連通且無環的無向圖。
輸入一個圖,該圖由一個有著N個節點 (節點值不重複1, 2, ..., N) 的樹及一條附加的邊構成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬於樹中已存在的邊。
結果圖是一個以邊
組成的二維陣列。每一個邊
的元素是一對[u, v]
,滿足 u < v
,表示連線頂點u
和v
的無向圖的邊。
返回一條可以刪去的邊,使得結果圖是一個有著N個節點的樹。如果有多個答案,則返回二維陣列中最後出現的邊。答案邊 [u, v]
應滿足相同的格式 u < v
。
示例 1:
輸入: [[1,2], [1,3], [2,3]]
輸出: [2,3]
解釋: 給定的無向圖為:
1
/ \
2 - 3
示例 2:
輸入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
輸出: [1,4]
解釋: 給定的無向圖為:
5 - 1 - 2
| |
4 - 3
注意:
- 輸入的二維陣列大小在 3 到 1000。
- 二維陣列中的整數在1到N之間,其中N是輸入陣列的大小。
class Solution { public int[] parent; public int[] findRedundantConnection(int[][] edges) { parent = new int[edges.length + 1]; init(edges.length); for(int i = 0; i < edges.length; i++) { if(connected(edges[i][0], edges[i][1])) { return edges[i]; } else { union(edges[i][0], edges[i][1]); } } return edges[edges.length]; } private int root(int i) { while(i != parent[i]) { i = parent[i]; } return i; } public boolean connected(int p, int q) { return root(p) == root(q); } public void union(int p, int q) { int proot = root(p); int qroot = root(q); parent[proot] = qroot; } public void init(int N) { for(int i = 1; i <= N; i++) { parent[i] = i; } } }
相關文章
- 並查集-Java實現並查集Java
- 並查集(一)並查集的幾種實現並查集
- 並查集的概念與演算法實現並查集演算法
- 並查集到帶權並查集並查集
- 查並集
- 【並查集】【帶偏移的並查集】食物鏈並查集
- 簡單易懂的並查集演算法以及並查集實戰演練並查集演算法
- 並查集(小白)並查集
- [leetcode] 並查集(Ⅱ)LeetCode並查集
- [leetcode] 並查集(Ⅲ)LeetCode並查集
- [leetcode] 並查集(Ⅰ)LeetCode並查集
- 3.1並查集並查集
- 並查集應用並查集
- 寫模板, 並查集。並查集
- 並查集的使用並查集
- 並查集跳躍並查集
- 各種並查集並查集
- 淺談並查集並查集
- 食物鏈(並查集)並查集
- 並查集(Union Find)並查集
- The Door Problem 並查集並查集
- 並查集練習並查集
- 並查集(二)並查集的演算法應用案例上並查集演算法
- 並查集演算法Union-Find的思想、實現以及應用並查集演算法
- 並查集題目合集並查集
- 並查集深度應用並查集
- 【轉】種類並查集並查集
- The Suspects-並查集(4)並查集
- 並查集擴充套件並查集套件
- (Day3)並查集並查集
- 並查集演算法並查集演算法
- 並查集在實際問題中的應用並查集
- 專題五 並查集【Kuangbin】並查集
- 並查集の進階用法並查集
- 並查集(UnionFind)技巧總結並查集
- 關於並查集問題並查集
- 並查集的應用2並查集
- [複習] 種類並查集並查集