並查集系列之「思路最佳化」

ice_moss發表於2021-05-21

一、介紹

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

相關文章