演算法學習之 並查集

2021-10-08 23:24:46 字數 1321 閱讀 6710

並查集用於解決連線類問題,判斷網路中節點間的連線狀態。與路徑類問題相比,並查集只回答了節點之間是否連通,而具體的連通路徑並不能確定,因此並查集在某些場景下非常高效。

如前所述,此處的並查集實現只提供兩個介面:是否連線,元素合併。下面**使用乙個陣列來記錄每個元素所對應的類別,如果兩個元素的類別相同,則稱該兩個元素相互連線(屬於同一組),合併操作則是將兩個元素對應的類別修改一致。

//**中的引數皆為資料索引而非資料本身

class unionfind

else

}private:

//存放根節點陣列,mp_id[n]表示n索引所在元素的父節點,mp_id[n]表示元素指向自身即根節點

int* mp_id;

//元素所在樹節點數,mp_treecount[n]表示以n索引元素為根節點的樹中元素個數

int* mp_treecount;

//元素個數

int mp_count;

};

上面的實現很大程度上降低了合併操作的樹深度,但是樹的元素個數並不能完全反應樹的深度,對於元素個數很多但樹深度很小的樹,上述實現則會增加合併樹深度,下面使用mp_rank陣列來記錄樹的深度,實現並查集基於rank的優化。值得注意的是基於rank的優化程式執行時間上接近基於size的優化,甚至會略低於基於size的優化,因為元素個數很多但樹深度很小的樹並不會經常出現且基於rank的優化增加了每次合併的判斷次數,但是提高了程式的健壯性,總體來看這些微小的效率犧牲是值得的!

//基於rank(以元素為根節點所在樹的深度)優化

class unionfind

else if(mp_rank[pid]上面的優化全部是從合併過程中降低樹的深度來著手。鑑於我們關心的只是每個元素的根節點,在find查詢根節點的過程中還可以通過改變樹的結構來大幅降低樹的深度。在這裡路徑壓縮的基本思想是:在查詢根節點的過程中,如果當前節點不是根節點,那麼直接將當前節點掛接到父節點的父節點上(因為根節點父節點就是自身,所以父節點的父節點一定合法)。

//使用路徑壓縮進行優化(進行查詢根節點操作時上移節點減小樹的深度)

class unionfind

else if(mp_rank[pid]按照路徑壓縮的思路,最優的情況是:所有的樹深度都不超過2,樹中的所有元素都直接掛接在根節點上。下面的方法實現了該思路

int find(int n)

return mp_id[n];

}

但是,執行發現演算法的效率反而變低了,因為每次查詢每個節點都要進行遞迴,遞迴會降低效率。

並查集能夠非常高效的解決連線類問題,通過使用路徑壓縮,並查集的操作時間複雜度近似於o(1)。

演算法學習之並查集

並查集是一種樹型的結構,常常用來處理一些不相交的集合的合併和查詢問題。查詢 確定元素所在的集合。合併 將兩個集合合併成乙個集合。查詢v所在集合的根節點 int find int v 合併 void merge int x,int y 優化1 int find int x k x while k r ...

演算法學習 並查集

大家肯定有聽說過社交網路裡面的六人理論吧,說是可以通過六個人的聯絡認識世界上的任意乙個人。比如我想認識一下機械系的系花,我先找到機械系的朋友,然後通過朋友介紹認識。這樣可以發現我們的社交圈子其實是有部分重疊的。當然也有可能是我的圈子太小,根本沒有什麼朋友認識那個圈子裡面的人,也有很大可能是機械系花4...

演算法學習記錄 並查集

上大物學了會並查集,感覺挺簡單的,而且很好玩,繼dfs,bfs和floyd演算法外又學了一種求連通塊的演算法,綜合下來這幾種演算法各有優劣吧.並查集演算法詳解見此 模板如下 include using namespace std define maxn 100001 int father maxn ...