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

yangkuang發表於2021-05-22

一、介紹

  1. 背景
    前面將到並查集基於size的優化,其實仔細想想,還是有可以優化的地方;size[i]是指以i為根節點樹的節點數;是將節點數量多的樹的根節點向節點數好的樹的根節點連線,在一般情況下是得到了優化,但是這裡就存在問題了,當出現:節點數多的樹它的高度非常高的時候,size的優化方式就不太高效了。
  2. rank
    rank[i]:是用來記錄以i為根節點的樹的高度(樹的層數),其本質是陣列。

二、邏輯

並查集本質是樹,當樹的高度(層數)越高在對數的操作其複雜度會越高,rank的目的就是降低在並(union)過程中並查集的高度;在並(union)過程中使用rank來記錄合併的兩棵樹的高度,將rank值小的樹的根節點指向rank值大的根節點。如下圖:
連線2,4( union(4,2) )
並查集系列之「基於rank的優化」

方法一:

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

方法二:

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

很明顯方法二比方法一更優
方法二:正是基於rank的優化
具體邏輯如下:

rank[7] = 2
rank[8] = 3
並查集系列之「基於rank的優化」

此時只需要將rank[7]樹的根節點指向rank[8]樹的節點
合併後,如下:
此時整個並查集rank[8] = 3,高度不變
並查集系列之「基於rank的優化」

三、程式碼實現

#include<cassert>

using namespace std;
namespace UF4 {
    class UnionFind4 {
    private:
         // 我們的第二版Union-Find, 使用一個陣列構建一棵指向父節點的樹
        // parent[i]表示第i個元素所指向的父節點 
        int *parent;
        int *rank;
        int count; //資料個數

     public:
        UnionFind4(int count) {
            parent = new int[count];
            rank = new int[count];
            this->count = count;
            //初始化
            for (int i = 0; i < count; i++) {
                parent[i] = i;
             }
         }
      //解構函式
        ~UnionFind4() {
            delete parent;
            delete rank;
  }

        // 查詢過程, 查詢元素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);
  }

rank核心部分:

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

相關文章