並查集 一點小的感悟

2021-05-26 02:15:09 字數 1313 閱讀 8169

最近在做acm題,遇到了乙個叫做並查集的東西,於是從網上找了一些資料,順便自己總結了一些,希望對大家和自己都有用~~

(一)什麼叫做並查集

英文:disjoint set,即「不相交集合」

將編號分別為1…n的n個物件劃分為不相交集合,在每個集合中,選擇其中某個元素代表所在集合。

常見兩種操作:

1、n合併兩個集合

2、n查詢某元素屬於哪個集合

例如,並查集一般用陣列來實現,用陣列的下標序號作為其元素的代號,其中的每個元素都屬於乙個集合,初始條件下每個元素所屬的集合中只有其乙個元素,例如對於元素i來說,其所屬的集合為set[i],在實際應用中要將各個集合進行合併,用編號最小的元素的下標作為整個集合的代號。

n  用編號最小的元素標記所在集合;

n  定義乙個陣列 set[1..n] ,其中set[i] 表示元素i 所在的集合;

例如上圖中,目前元素1、3、7都屬於集合1,也就是set[1]=set[3]=set[7]=1;同理,元素2、5、9、10都屬於集合2,等等。用數學語言描述,不相交的集合共有四個: , , ,

上面的演算法的實現過程如下:

其中,左圖表示查詢相應元素所在的集合,右圖表示將兩個集合相合併,當然前提條件是引數a,b分別表示的是集合。其複雜度不難計算出來:右圖中的演算法包括乙個迴圈,此迴圈的複雜度為o(n),當元素的個數很少是還能接受,但是當元素的個數很多時,其運算速度很難讓人接受。

為了改進合併演算法,將元素用樹的形式表示出來:

n  每個集合用一棵「有根樹」表示

n  定義陣列 set[1..n]

n  set[i] = i , 則i表示本集合,並是集合對應樹的根

n  set[i] = j, j<>i, 則 j 是 i 的父節點.

下面是其演算法

從樹中的每個節點開始順著其父節點向上查詢,直到找到其相應的根節點。

由於合併的時候是隨機合併的,因此容易形成左偏樹或者右偏樹,這樣不利於降低查詢演算法的複雜度,為了節省演算法開銷,作如下的改進。

n  方法:將深度小的樹合併到深度大的樹

n  實現:假設兩棵樹的深度分別為h1和h2, 則合併後的樹的高度h是:

n  max(h1,h2), if h1<>h2.

n  n  效果:任意順序的合併操作以後,包含k個節點的樹的最大高度不超過

其演算法如下所示:

為了進一步優化演算法,可以進行路徑壓縮:

n  思想:每次查詢的時候,如果路徑較長,則修改資訊,以便下次查詢的時候速度更快

n  步驟:

n  第一步,找到根結點

n  第二步,修改查詢路徑上的所有節點,將它們都指向根結點

演算法如下:

一點小感悟

今天去了華為的機試,說實話,題目不是很難,但是自己並沒有發揮的很好,只寫出來一題半,第一題非常簡單 兩個兩位數a,b,輸出乙個四位數,將a的十位和個位放到c的十位和百位上,b的十位和個位放到c的個位和千位上,直接轉化為字串拼接一下就行。第二題有點難度 給出1,3,9,27,81,這幾個數,輸入1 1...

一點小感悟

最近看題的時間多了,感覺回到了大一學c語言的時候,那時不會c,只能用筆算,只能自己想,但是數又很大完全用筆算 是不可能的,只能找到數中的規律,找到公式的遞推式才能解決,後來有了dp的概念,那時就更加頭疼,概念更加的抽象 不再是簡單的數學公式,變成了有意義的生活問題,這中間必須有乙個裝換,從生活問題到...

workerman 最近的一點小感悟

最近在研究workerman,遇到不懂的就去群裡請教 沒看完文件,一些後面會遇到的問題都可以在文件找到答案 首先,測試伺服器上已經裝好了lamp,檢測一下pcntl posix擴充套件 root myserver php m grep pcntl root myserver php m grep p...