並查集系列之「路徑壓縮( path compression ) 」

ice_moss發表於2021-05-22

一、介紹

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

相關文章