並查集系列之「基於size的優化」

yangkuang發表於2021-05-21

一、介紹及邏輯

  1. 介紹
    在上一小節我們使用指標的方法將每一個元素都看作是一個節點,並且是節點指向另一個節點(包括自己),在這一小節中我們將在此基礎上進行優化。
    先來介紹一下什麼是”size”
    size : size[i] 是指用來記錄以i為根節點的樹所包含的節點個數,本質是一個陣列

  2. 邏輯
    先來看看下面的圖片:
    現在需要將4,2連線起來,該怎麼連?

並查集系列之「基於sz的優化」

方法一:如下圖

並查集系列之「基於sz的優化」

方法二:如下圖

並查集系列之「基於sz的優化」

很容易看出方法二更優,樹的高度越高,對計算機的消耗也會越大,所以很明顯方法二是有3層,而方法一有4層(但有大量的資料時,效能差別就會明顯); 所以我們使用sz陣列,就是在維護方法二。

二、程式碼實現

#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 協議》,轉載必須註明作者和本文連結

相關文章