圖論最小生成樹
前言
推出一個新系列,《看圖輕鬆理解資料結構和演算法》,主要使用圖片來描述常見的資料結構和演算法,輕鬆閱讀並理解掌握。本系列包括各種堆、各種佇列、各種列表、各種樹、各種圖、各種排序等等幾十篇的樣子。
最小生成樹
最小生成樹(Minimum Spanning Tree),簡稱MST,更詳細點叫最小權重生成樹,是一副連通加權無向圖中一棵權值最小的生成樹。對於圖,在完全連通的情況下,則擁有生成樹。而如果圖不連通的話,則擁有多棵生成子樹,構成生成森林。
最小生成樹正式的定義為:給定一個無向圖,表示連線頂點a與頂點b的邊,有,而表示該邊的權重,若存在T為E的子集(即)且 (V, T) 為樹,使得
的最小,則此T為G的最小生成樹。
利用最小生成樹解決實際問題的例子有很多,比如某個鎮有十幾個小村莊,現要在這些村莊中構建一個通訊網路,將每個村莊都連線起來,如何走線能最節省電纜?這就可以用最小生成樹解決。
Prim演算法
Prim(普里姆)演算法是一種用於求解最小生成樹的演算法,通過此演算法能搜尋到圖邊集合中某個特定的子集,該子集構成的樹能連通圖的所有頂點,而且所有邊的權重之和最小。該演算法於1930年由捷克數學家沃伊捷赫·亞爾尼克(Vojtěch Jarník)發現;並在1957年由美國電腦科學家羅伯特·普里姆(Robert C. Prim)獨立發現;1959年,艾茲格·迪科斯徹再次發現了該演算法。
Prim的主要思想是:從圖中任意一個頂點開始,每次選擇與當前頂點集距離最近的頂點,將對應的邊加入到樹中,直至所有頂點被處理完。
演算法步驟
- 對於一個加權連通圖,其頂點集合為V,邊集合為E;
- 從集合V中任選一個頂點作為初始頂點,將該頂點標為已處理;
- 已處理的所有頂點可以看成是一個集合T,計算所有與集合T中相連線的頂點的距離,選擇距離最短的頂點,將其標記為已處理,並記錄最短距離的邊;
- 不斷計算已處理的頂點集合T和未處理的頂點的距離,每次選出距離最短的頂點標為已處理,同時記錄最短距離的邊,直至所有頂點都處理完。
- 最終,所有記錄的最短距離的邊構成的樹,即是最小生成樹。
Prim過程
假如我們現在有一個7個頂點的無向加權圖,結構如下圖,分別用0-6來表示圖的每個頂點,每條邊上的數字為對應的權重。
為了記錄過程狀態,引入如下表格,第一列“頂點”表示圖的頂點,分別為0到6;第二列“處理標識”表示對應頂點是否已處理,未處理狀態為F,已處理狀態為T;第三列“權重”表示頂點到頂點的權重,初始值為INF;第四列“頂點”用於描述最小生成樹,與第一列的“頂點”組合成最小生成樹的邊,初始值為-1。
現在我們隨便選一個頂點3作為初始頂點,將該頂點標記為已處理T,並且權重置為0,因為自己對自己的權重為0。
此時已處理集合為{3},檢測與頂點3相鄰的頂點,先檢查(3,1)邊的權重,權重設為4,最小生成樹另外一個頂點設為3,表示頂點1到頂點3的邊。
繼續檢查(3,2)邊的權重,權重設為4,最小生成樹另外一個頂點設為3,表示頂點2到頂點3的邊。
類似地,檢查(3,4)邊的權重,權重設為5,最小生成樹另外一個頂點設為3。
檢查(3,5)邊的權重,權重設為1,最小生成樹另外一個頂點設為3。
對於已處理集合為{3},相鄰的所有頂點中,找出權重最小的邊,即權重為1的邊(3,5),將頂點5的處理標識設為T,並將其加入到已處理集合中,此時集合為{3,5}。
對於集合{3,5},檢測與它們相鄰的頂點,這裡注意到因為頂點3上一輪已經檢測過了,不必再針對頂點3進行權重檢測了,但頂點5能更新之前的權重(可以這樣想一下:頂點3到頂點2的權重如果為4,而頂點5到頂點2的權重為2,那麼就取權重小的)。於是,檢查(5,2)邊的權重,權重設為2,最小生成樹另外一個頂點設為5,表示頂點2到頂點5的邊。
接著檢測(5,3)邊,因為3的處理標識為T,屬於已處理集合內的元素,不必檢測。
繼續檢測(5,6)邊,權重設為3,最小生成樹另外一個頂點設為5,表示頂點6到頂點5的邊。
對於已處理集合為{3,5},相鄰的所有頂點中(即除了處理狀態為T的其他頂點),找出權重最小的邊,
所以要找的邊是權重為2的邊(2,5),將頂點2的處理標識設為T,並將其加入到已處理集合中,此時集合為{2,3,5}。
對於集合{2,3,5},檢測與它們相鄰的頂點,其中頂點3和頂點5上一輪已經檢測過了不必再針對它們進行權重檢測了。於是檢查(0,2)邊的權重,權重設為5,最小生成樹另外一個頂點設為2,表示頂點2到頂點0的邊。
繼續檢測(1,2)邊,權重設為1,最小生成樹另外一個頂點設為2。
接著檢測(2,3)邊,因為3的處理標識為T,屬於已處理集合內的元素,不必檢測。
繼續檢測(4,2)邊,此時權重為8,而上一輪檢測的權重為5,8>5,所以不更新權重,最小生成樹另外一個頂點也不更新。這種情況其實就是前面檢測頂點3到頂點4的權重更小,也就是說頂點3到頂點4更近,對於集合{2,3,5}來說,到頂點4的權重應該取更小的5。
接著檢測(2,5)邊,因為5的處理標識為T,屬於已處理集合內的元素,不必檢測。
對於已處理集合為{2,,3,5},相鄰的所有頂點中(即除了處理狀態為T的其他頂點),找出權重最小的邊,
所以要找的邊是權重為1的邊(2,1),將頂點1的處理標識設為T,並將其加入到已處理集合中,此時集合為{1,2,3,5}。
類似地,針對集合{1,2,3,5}進行檢測,找到與該集合相連的最小權重的邊,記錄下對應的邊和權重,然後將對應頂點加入到集合中。此輪找到的最小權重為3,對應的邊為(0,1),則已處理集合變為{0,1,2,3,5}。
繼續地,針對集合{0,1,2,3,5}進行檢測。此輪找到的最小權重為3,對應的邊為(5,6),則已處理集合變為{0,1,2,3,5,6}。
最後,針對集合{0,1,2,3,5,6}進行檢測。此輪找到的最小權重為3,對應的邊為(4,6),則已處理集合變為{0,1,2,3,4,5,6}。
此時,所有頂點都已經被處理完了,至此最小生成樹的查詢工作已經執行完畢。根據第一列的“頂點”和第四列的“頂點”,我們就能夠描述出最小生成樹了,結果如下。
-------------推薦閱讀------------
我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)
跟我交流,向我提問:
歡迎關注: