一、介紹
在並查集的Union( ) 中使用指標,將每一個元素看作是一個節點,並將每一個節點都指向一個節點(可以是其他節點或節點本身)即Quick Union;使用這種方法在後續可以更好的對並查集進行最佳化。
二、 Union的表示方法及邏輯
在Quick Find下的union時間複雜度為( O(n) )
將每一個元素看作是一個節點,如下圖:
初始化一樣,每一個元素是一個集合
並且每一個元素指向自己
下面我們將4,3連線( union(4, 3) )
再繼續:將3,和8連線(union(3, 8) )
將6,5進行連線( union(6, 5) )
這裡注意:我們將9,4連線( union(9, 4) )
我們是將9指向8節點(這樣更最佳化),在邏輯上就是9,和4連線上了
再看這裡,同樣的邏輯,將其中一方的根節點指向另一個的根節點
連線6,2 ( union(6, 2) )
連線後:
最佳化後的表示方法及邏輯就是這樣。
三、程式碼實現
我先看union部分:
// 合併元素p和元素q所屬的集合
// O(h)複雜度, h為樹的高度
void unionElments(int p, int q) { //union在c++中是關鍵字
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot)
return;
parent[pRoot] = qRoot;
}
下面是完整程式碼:
#include<cassert>
using namespace std;
namespace UF2 {
class UnionFind2 {
private:
// 我們的第二版Union-Find, 使用一個陣列構建一棵指向父節點的樹
// parent[i]表示第i個元素所指向的父節點
int *parent;
int count; //資料個數
public:
UnionFind2(int count) {
parent = new int[count];
this->count = count;
//初始化
for (int i = 0; i < count; i++) {
parent[i] = i;
}
}
//解構函式
~UnionFind2() {
delete parent;
}
// 查詢過程, 查詢元素p所對應的集合編號
// O(h)複雜度, h為樹的高度
int find(int p) {
assert(p >= 0 && p <= count);
// 不斷去查詢自己的父親節點, 直到到達根節點
// 根節點的特點: parent[p] == p
while (p != parent[p])
p = parent[p];
return 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;
parent[pRoot] = qRoot;
}
};
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結