連通的定義:從A定點出發能到達B定點,則稱A-B連通
連通的基本性質:
- 自反性:A一定連通A(ps:自己可以和自己PY交易)
- 對稱性:如果A和B連通,則B和A也連通(無向的情況下)
- 傳遞性:如果A連通B,B連通C,則A連通C
樹:
- 大小(size):樹的節點數量
- 深度(depth):某個節點到根節點的鏈接路徑的數量
- 高度(height):樹所有節點中深度最大的值
森林的構造(目標:深度儘量小,樹儘量少):
- quick-find
- quick-union
- 加權quick-union
- 路徑壓縮
實現
- quick-find算法(所有具有連通關係的觸點都指向終觸點,查找觸點很快,但連通觸點較慢)
class UF {
int[] id;
int count;
UF(int N) {
id = new int[N];
count = N;
}
//將所有連通觸點指向最後的觸點
int find(int p) {
return id[p];
}
void union(int p, int q) {
int pID = find(p);//獲取起觸點
int qID = find(q);//獲取終觸點
if (pID == qID) {//如果已經連通,結束
return;
}
for (int i = 0; i < id.length; i++) {//遍歷所有觸點
if (id[i] == pID) {//如果有觸點指向起觸點,說明起觸點之前已經和其他觸點連接
id[i] = qID; //將所有指向起觸點的觸點指向終觸點
count--;//連通數量減一
}
}
}
boolean connection(int p, int q) {
return id[p] == id[q];
}
int count() {
return count;
}
}
- quick-union(所有具有連通關係的觸點都指向自己的終觸點,連通觸點很快,但查找觸點較慢)
class UF1 {
int[] id;
int count;
UF1(int N) {
id = new int[N];
count = N;
}
//查找觸點的根觸點,類似遞歸回溯
int find(int p) {
while(p!=id[p]) p = id[p];
return id[p];
}
void union(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot) {
return;
}
id[pRoot] = qRoot;//直接將新節點指向根節點
}
boolean connection(int p, int q) {
return id[p] == id[q];
}
int count() {
return count;
}
}
- 加權quick-union(在quick-union的基礎上將小樹掛在根節點上,而不是掛在子樹上,減少了數的深度,最常用)
package chapter1_5;
/**
* @author : jeasion
* @name
* @comment
* @return
*/
public class WeightQuickUnion {
int[] id;
int count;
int[] size;
public WeightQuickUnion(int N) {
id = new int[N];
size = new int[N];
count = N;
for (int i = 0; i < id.length; i++) {
id[i] = i;
size[i] = 1;
}
}
void union(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot) {
return;
}
//如果p樹的size小於q樹的size,說明q樹比p樹大,則將p樹掛到p樹上
if (size[pRoot] <= size[qRoot]) {
//將p樹的根節點qRoot賦給q樹的根節點,使q樹成爲p樹根節點的直接子節點
id[pRoot] = qRoot;
size[qRoot] += size[pRoot];
} else {
id[qRoot] = pRoot;
size[qRoot] += size[pRoot];
}
}
int find(int p) {
while (p != id[p])
p = id[p];
return id[p];
}
boolean connection(int p, int q) {
return id[p] == id[q];
}
int count() {
return count;
}
}
- 路徑壓縮(將所有節點鏈接到一個根節點,樹上完全扁平的,所有節點的深度都是1,樹的高度也爲1)
實現:在查找find()的同時直接將節點鏈接到根節點,最優算法(PS:我也不知道爲啥好像不實用)