一、介紹
並查集裡的 find 函式里可以進行路徑壓縮,是為了更快速的查詢一個點的根節點。對於一個集合樹來說,它的根節點下面可以依附著許多的節點,因此,我們可以嘗試在 find 的過程中,從底向上,如果此時訪問的節點不是根節點的話,那麼我們可以把這個節點儘量的往上挪一挪,減少數的層數,這個過程就叫做路徑壓縮。
通俗的說就是把find過程中“查詢節點”的路勁變短,讓find能更快的更高效。
二、邏輯
例如:find( 4 )
我們需要從下到上的找到根節點,當這條路勁很長,邏輯上花費的時間就會多一些
在路勁壓縮的這個過程需要不斷去查詢自己的父親節點, 直到到達根節點,而根節點的特點: parent[p] == p
不斷的將節點4網上挪一挪使用:
parent[p] = parent[parent[p]];
最後就完成了路徑壓縮:
二、程式碼實現
#include<cassert>
using namespace std;
namespace UF4 {
class UnionFind5 {
private:
// 我們的第二版Union-Find, 使用一個陣列構建一棵指向父節點的樹
// parent[i]表示第i個元素所指向的父節點
int *parent;
int *rank;
int count; //資料個數
public:
UnionFind5(int count) {
parent = new int[count];
rank = new int[count];
this->count = count;
//初始化
for (int i = 0; i < count; i++) {
parent[i] = i;
}
}
~UnionFind5() {
delete parent;
delete rank;
}
// 查詢過程, 查詢元素p所對應的集合編號
// O(h)複雜度, h為樹的高度
int find(int p) {
assert(p >= 0 && p <= count);
// 不斷去查詢自己的父親節點, 直到到達根節點
// 根節點的特點: parent[p] == p
while (p != parent[p])
parent[p] = parent[parent[p]];
p = parent[p];
return p;
//遞迴演算法
// if (p != parent[p])
// parent[p] = find(p);
// return parent[p];
}
// 檢視元素p和元素q是否所屬一個集合
// O(h)複雜度, h為樹的高度
bool isConnected(int p, int q) {
return find(p) == find(q);
}
// 合併元素p和元素q所屬的集合
// O(h)複雜度, h為樹的高度
void unionElments(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot)
return;
if (rank[pRoot] > rank[qRoot]) {
parent[pRoot] = qRoot;
}
else if (rank[pRoot] < rank[qRoot]) {
parent[qRoot] = pRoot;
}
else {//rank[pRoot] == rank[qRoot]
parent[qRoot] = pRoot;
rank[qRoot] = +1;
}
}
};
}
(圖片來源:慕課網課程《演算法與資料結構》)
本作品採用《CC 協議》,轉載必須註明作者和本文連結