一、介紹及邏輯
介紹
在上一小節我們使用指標的方法將每一個元素都看作是一個節點,並且是節點指向另一個節點(包括自己),在這一小節中我們將在此基礎上進行最佳化。
先來介紹一下什麼是”size”
size : size[i] 是指用來記錄以i為根節點的樹所包含的節點個數,本質是一個陣列邏輯
先來看看下面的圖片:
現在需要將4,2連線起來,該怎麼連?
方法一:如下圖
方法二:如下圖
很容易看出方法二更優,樹的高度越高,對計算機的消耗也會越大,所以很明顯方法二是有3層,而方法一有4層(一旦有大量的資料時,效能差別就會明顯); 所以我們使用size陣列,就是在維護方法二。
二、程式碼實現
#include<cassert>
using namespace std;
namespace UF3 {
class UnionFind2 {
private:
// 我們的第二版Union-Find, 使用一個陣列構建一棵指向父節點的樹
// parent[i]表示第i個元素所指向的父節點
int *parent;
int *size; //size用來記錄節點的個數
int count; //資料個數
public:
UnionFind2(int count) {
parent = new int[count];
size = new int[count];
this->count = count;
//初始化
for (int i = 0; i < count; i++) {
parent[i] = i;
size[i] = 1;
}
}
//解構函式
~UnionFind2() {
delete parent;
delete size;
}
// 查詢過程, 查詢元素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);
}
下面是size的核心:
// 合併元素p和元素q所屬的集合
// O(h)複雜度, h為樹的高度
void unionElments(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot)
return;
// 根據兩個元素所在樹的元素個數不同判斷合併方向
// 將元素個數少的集合合併到元素個數多的集合上
if(size[pRoot] < size[qRoot]) {
parent[pRoot] = qRoot;
size[qRoot] = +size[pRoot];
}
else { //size[pRoot] >= size[qRoot]
parent[qRoot] = pRoot;
size[pRoot] = +size[qRoot];
}
}
};
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結