並查集(不相交集)

來源:互聯網
上載者:User

並查集一般以樹形結構儲存,多棵樹構成一個森林,每棵樹構成一個集合,樹中的每個節點就是該集合的元素,

找一個代表元素作為該樹(集合)的祖先。

 

並查集支援以下三種操作:

1、Make_Set(x) 把每一個元素初始化為一個集合

    初始化後每一個元素的父親節點是它本身,每一個元素的祖先節點也是它本身。

2、Find_Set(x) 尋找一個元素所在的集合

    尋找一個元素所在的集合,只要找到這個元素所在集合的祖先即可。判斷兩個元素是否屬於同一集合,只要看他們所在集合的祖先是否相同即可。

3、Union(x,y) 合并x,y所在的兩個集合

    合并兩個不相交集合操作很簡單:首先設定一個數組Father[x],表示x的"父親"的編號。那麼,合并兩個不相交集合的方法就是,找到其中一個集       合的祖先,將另外一個集合的祖先指向它。

 

並查集的最佳化

1、Find_Set(x)時 路徑壓縮

尋找祖先時我們一般採用遞迴尋找,但是當元素很多亦或是整棵樹變為一條鏈時,每次Find_Set(x)都是O(n)的複雜度,有沒有辦法減小這個複雜度呢?

答案是肯定的,這就是路徑壓縮,即當我們經過"遞推"找到祖先節點後,"迴歸"的時候順便將它的子孫節點都直接指向祖先,這樣以後再次Find_Set(x)時複雜度就變成O(1)了。

 

2、Union(x,y)時 按秩合并

即合并的時候將元素少的集合合并到元素多的集合中,這樣合并之後樹的高度會相對較小。

 

主要代碼實現

/* father[x]表示x的父節點 */<br />int father[MAX];<br />/* rank[x]表示x的秩 */<br />int rank[MAX];<br />/* 初始化集合 */<br />void Make_Set(int x)<br />{<br />father[x] = x;<br />rank[x] = 0;<br />}<br />/* 尋找x元素所在的集合,回溯時壓縮路徑 */<br />int Find_Set(int x)<br />{<br />if (x != father[x])<br />{<br />father[x] = Find_Set(father[x]);<br />}<br />return father[x];<br />}<br />/* 按秩合并x,y所在的集合 */<br />void Union(int x, int y)<br />{<br />x = Find_Set(x);<br />y = Find_Set(y);<br />if (x == y) return;<br />if (rank[x] > rank[y])<br />{<br />father[y] = x;<br />}<br />else<br />{<br />if (rank[x] == rank[y])<br />{<br />rank[y]++;<br />}<br />father[x] = y;<br />}<br />}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.