看圖輕鬆理解並查集
前言
推出一個新系列,《看圖輕鬆理解資料結構和演算法》,主要使用圖片來描述常見的資料結構和演算法,輕鬆閱讀並理解掌握。本系列包括各種堆、各種佇列、各種列表、各種樹、各種圖、各種排序等等幾十篇的樣子。
並查集
並查集(Disjoint Set)是一種用於處理不相交集合的資料結構,顧名思義,通過它可以對集合進行合併和查詢操作,從而實現元素分組的管理。並查集其中一個典型應用就是在無向圖中判斷任意兩個頂點是否連通。
集合
在數學上,集合被定義為由一個或多個確定的元素所構成的整體,簡稱集(Set)。集合內的物件稱為該集合的元素,集合的元素都具有某種相同的性質。比如“成語大全”集合,它就包含一心一意、三心二意等等所有成語。對於集合A,如果元素a是集合A的元素,則稱a屬於A,記為
不相交集合
不相交集合是指兩個集合沒有公共的元素,反之如果兩個集合有相同的元素則說明存在交集。對於兩個集合A與B,如果,即A與B相交為空集,則稱A與B不相交。比如{1, 2, 3}集合和{4, 5, 6}集合就是不相交集合。
主要操作
- 初始化操作,把每個元素初始化為一個集合,根節點父節點都為其本身,O(n)時間複雜度。
- 查詢操作,查詢某個元素所在的集合,集合由根節點表示,時間複雜度最好情況為O(1),而最壞的情況為O(n),有一些優化措施。
- 合併操作,將兩個元素所在的集合合併為一個集合,合併前需判斷兩個元素是否屬於同一集合,只有屬於不同集合才執行合併,時間複雜度最好情況為O(1),而最壞的情況為O(n)。
實現方案
並查集的實現方案有很多種,常用的實現方式是通過陣列來描述樹結構,從而實現並查集資料結構。其中每個集合都用一棵樹來表示,樹的每個節點代表集合中的一個元素,樹的結構通過父指標來表示。比如下圖,長度為7的陣列,陣列值為-1的表示自己為根節點,同時也用它代表集合,正數的值表示它的父節點元素的索引。array[1]=2,說明它的父節點是元素2,array[3]=4,說明它的父節點為元素4。
初始化操作
假如有7個元素,初始化操作即是將每個元素初始化為一個集合,用長度為7的陣列來表示,陣列中每個元素的值都為-1,-1表示自己是根節點,下標值用於表示集合,比如0表示集合0,1表示集合1等等。
合併操作
合併操作即是將兩個集合合併到一起,如果要合併下標為1和2的元素,則先分別找這兩個元素對應的集合,元素1的集合為1,
元素2的集合為2,
選擇元素2作為元素1的父節點,且元素2作為新的集合。此時,元素1和元素2都屬於集合2。
同樣地,對元素3和元素4進行合併,結果如下,此時,元素3和元素4都屬於集合4。
接著對元素1和元素3也進行合併,需要先分別找出元素1和元素3所在的集合,如果屬於同一個集合則不必執行合併,反之如果屬於不同的集合,則需要執行合併操作。從元素1開始,因為它的值為2,,說明它的父節點是元素2,
所以往元素2繼續查詢,到達元素2後發現值為-1,說明元素2就是根節點,所以集合2即是元素1所在的集合。
繼續找元素3所在的集合,從元素3開始,因為它的值為4,說明它的父節點是元素4,
所以往元素4繼續查詢,到達元素4後發現值為-1,說明元素4就是根節點,所以集合4即是元素3所在的集合。
兩個元素分別屬於不同的集合,於是兩個集合執行合併操作,原來的集合。選擇元素4作為父節點,元素4作為合併後的集合。此時,集合4包含了元素1、2、3、4。
查詢操作
查詢操作用於查詢某個元素所在的集合。如果要查詢元素1所在的集合,那麼從元素1開始,因為元素1的值為2,所以往元素2繼續找,
元素2的值為4,則繼續往元素4查詢,
元素4的值為-1,說明它是根節點,即是要找的集合,所以元素1屬於集合4。
路徑壓縮
路徑壓縮主要用於解決合併後樹的高度增加的問題,樹的高度變高的話查詢效率就會變低。比如繼續將元素5和元素4合併,結果樹就變成如下,此時對於這棵樹來說,其實元素1、2、3、4都可以直接指向元素5。
於是就會在執行查詢操作的過程中增加一些判斷,用於壓縮路徑,這樣當下一次查詢時就可以在更矮的樹中查詢了。比如現在查詢元素1,需要從元素1開始,通過元素2,再到元素4,最後才能找到元素5。
而路徑壓縮會在第一次查詢元素1完成後將樹調整為如下圖,其實邏輯很簡單,就是將元素1在查詢的過程中走過的元素統統都指向根節點。
-------------推薦閱讀------------
我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)
跟我交流,向我提問:
歡迎關注: