1. 程式人生 > >並查集的樹形實現(C++)(轉載)

並查集的樹形實現(C++)(轉載)

摘要:本文介紹了通用並查集的樹形實現,通過壓縮路徑和維持數的平衡,可以保證

查詢和合並的平均時間複雜度為O(1)!

關鍵字:並查集,UnionFind,樹形

並查集基本知識參見博文《並查集的陣列實現》。在並查集的樹形實現中,使用樹狀結構來組織一個

集合,多個集合之間組成森林。

合併兩個集合即合併兩棵樹T1和T2時,只要將兩棵樹中的一棵作為另外一棵的子樹。為了維護數的

平衡,即減少深度較深的節點的個數,可以把節點較少的數作為節點較深的樹的子樹。具體實現就是把一棵

樹的根節點作為另外一棵樹的根節點的子樹!

查詢某個節點所屬的集合時,找到該節點所在樹的樹根即可,同時,可以將查詢經過的所有節點的父

節點都設定為根,以方便下一次的查詢,這種策略雖然耗費了時間,但是可以使查詢的平均時間複雜度

為O(1)!

基於以上思想的並查集樹形實現C++原始碼如下:

 *並查集的樹形實現
 */

#include <iostream>

using namespace std;

#define N 10000

struct Node
{
      int parent; //父節點編號
      int count; //集合中元素的個數
};

Node UnionFindSet[N];

void uf_init(int n); //初始化
int uf_find(int x); //查詢元素,返回集合根節點編號
void uf_merge(int x, int y); //合併元素所在的集合樹

int main(int argc, char* *argv)
{
      int n = 20;
      uf_init(n);
      uf_merge(1, 5);
      uf_merge(10, 13);
      uf_merge(15, 17);
      uf_merge(1, 13);
      uf_merge(5, 17);
      uf_merge(19, 18);
      if(uf_find(1) == uf_find(15))
      {
            cout<<"success1"<<endl;
      }
      if(uf_find(13) == uf_find(17))
      {
            cout<<"success2"<<endl;
      }
      if(uf_find(19) != uf_find(17))
      {
            cout<<"success3"<<endl;
      }
      system("pause");
      return 0;
}

void uf_init(int n)
{
      //時間複雜度O(N)
      for(int i = 0; i < n; ++i)
      {
            UnionFindSet[i].count = 1;
            UnionFindSet[i].parent = i;
      }
}

int uf_find(int x) //x >= 0 && x <n
{
      //使用路徑壓縮之後的平均時間複雜度為O(1)
      int i = x;
      while(i != UnionFindSet[i].parent)
            i = UnionFindSet[i].parent;

      //壓縮路徑,將尋找X時經過的所有節點的父節點設為集合的根節點,方便下次查詢
    int j = x;
      while(j != i)
      {
            int tmp = UnionFindSet[j].parent;
            UnionFindSet[j].parent = i;
            j = tmp;
      }
      return i;
}

void uf_merge(int x, int y)
{

      //平均時間複雜度為O(1);

      //尋找樹根(集合表示符)
      x = uf_find(x);
      y = uf_find(y);
      if(y == x) return;

    //將小樹掛到大的樹下面,可以減少較深節點的數目,維持樹的平衡,以便高效查詢
      if(UnionFindSet[x].count > UnionFindSet[y].count)
      {
            UnionFindSet[y].parent = x;
            UnionFindSet[x].count += UnionFindSet[y].count;
      }
      else
      {
            UnionFindSet[x].parent = y;
            UnionFindSet[y].count += UnionFindSet[x].count;
      }

}