這是圖算法的第四篇文章 圖解:如何實現最小生成樹算法
文章目錄:數組
今天咱們考慮的模型是加權無向圖
,問題是如何獲取它的一幅最小生成樹!首先,咱們給出最小生成樹的定義:微信
圖的生成樹是它的一棵含有其全部頂點的無環連通子圖。一幅加權圖的最小生成樹(MST)是它的一棵權值(樹中全部邊的權值之和)最小的生成樹。數據結構
如圖所示:code
首先,咱們給出一些約定來簡化問題(這並不會影響咱們理解問題)對象
簡而言之,咱們的討論對象是一幅權重各不相同的加權無向圖,任務是求最小生成樹的每條邊。接下來,咱們一塊兒思考如何實現這個算法!blog
1)咱們的任務是求得最小生成樹的每條邊,也就是我只要肯定了這些邊,天然而然也就惟一肯定了最小生成樹;那麼,一棵最小生成樹有多少條邊呢?咱們先來回顧一下樹
的兩個性質:排序
由於一共有V
個頂點,生成樹的邊剛好鏈接全部頂點(很少很多),因此生成樹一定有V-1
條邊。好了,恭喜你!🙃到這裏咱們已經前進了一小步!索引
2)接下來,我說一句話你看是否是對的:隊列
只要找到屬於最小生成樹的
V-1
條邊(不管什麼手段),也就解決了這個問題
你確定會說,這不是顯然的嗎?對!但這個是咱們向前走的基本思想。記牢了🤓
3)接下來,咱們就要尋找一種條件,只要一條邊知足這個條件,那麼咱們就可以斷言這條邊確定在最小生成樹中。一旦存在,咱們就能夠經過創造這種條件找到屬於最小生成樹的邊,將它標記;反覆創造上述條件,就能夠反覆地標記邊;直到咱們標記了V-1
條邊! 你是否是驚奇地發現:咱們已經成功地解決了這個問題!
4)咱們的任務變成了如何尋找與製造這種條件。站在巨人的肩膀上,咱們只須要理解就好了😂。這個條件,咱們稱之爲切分定理。
6)咱們隨意將一幅加權圖分爲兩個非空的集合,橫跨兩個集合的一條邊被稱爲橫切邊。而橫切邊中最短的那個一定屬於最小生成樹! 如圖所示:
全部的灰色頂點是一個集合,全部的白色頂點是另一個集合,橫跨兩個集合的全部的邊稱爲橫切邊(用紅色標出);其中權重最小的橫切邊一定屬於最小生成樹!
這個定理其實很容易想明白,由於這兩個集合之間必需要存在且只能存在一條邊;若是存在的不是這條最短橫切邊,那它就不是最小生成樹了!請注意一條很重要的性質:這種劃分是任意的!
——————咱們隨便怎麼劃分都無所謂!這就爲處理問題帶來了很強的靈活性!
7)咱們隨後介紹一種通用的算法思想:貪心算法(其實咱們在前文已經接觸過)。
使用切分定理找到最小生成樹的一條邊,不斷重複直到找到最小生成樹的全部邊(
V-1
條便可)
這是一幅貪心算法的執行過程,每次都是將全部頂點分紅兩個集合(注意:這是任意的!!),而後取最小的橫切邊加入最小生成樹。如此反覆,最終就達到了咱們的目的!
8)接下來再日後,咱們將真正地實現這種算法,而不是隻停留在思想上(talk is cheap,show me the code!😍)
1)咱們接着剛纔的思路繼續,咱們面臨着兩個問題:切分
與找到最小橫切邊
;對於切分,因爲是隨意的,因此仍是很容易實現的;另外一個問題:怎樣很天然地找到最小的橫切邊呢?
2)一個比較容易想到的解決方案是:
按照邊的權重順序(從小到大)處理他們;
首先,將最小的邊加入最小生成樹,而後從小到大依次加入邊,(注意:待加入的邊不能和已經加入的邊構成環);一直重複上述過程直到樹中含有V-1
條邊爲止
3)如今咱們仔細思考一下這個方法。只要待加入的邊和已經加入的邊沒有構成環,就說明這條邊是一條橫切邊
,同時,得益於咱們加入的順序(從小到大),咱們能夠肯定這條待加入的邊是最小橫切邊,那麼它必定屬於最小生成樹,將它加入也就沒有什麼毛病了。來看一下下面的過程:
咱們在實現的時候使用了一條優先隊列
來將邊按照權重排序;用前幾篇文章中實現的判斷無向圖連通性的類判斷是否連通;用一條隊列來保存最小生成樹的全部邊;就能夠很容易實現Kruskal算法
。
Prim算法
的思想與Kruskal算法
乍一看有所不一樣,可是最終你會發現,只是在尋找最小權重的橫切邊這裏使用了不一樣的 策略罷了。
1)咱們考慮這樣一種方案:維護一棵生長中的樹
A
)添加到最小生成樹中2)這個過程比Kruskal
更加簡明——————與最小生成樹相連的權重最小的一條邊;咱們把已經在樹中的點記爲集合A,全部沒有在樹中的頂點記爲集合B,顯然咱們選擇的那條邊就是最小橫切邊!
3)雖然過程比較簡明,可是實現的代碼卻不簡單,咱們須要:
marked[]
,若是頂點 v
在樹中,那麼 marked[v]
的值爲true
mst
來保存最小生成樹中的邊MinPQ<Edge>
來根據權重比較全部邊具體的操做過程以下:
4)到這兒,咱們已經實現了Prim算法
,它被稱爲 Prim算法的延時實現
;可是,還有能夠改進的地方,咱們能夠經過一些改進————刪除一些冗餘的信息,從而獲得Prim算法的即時實現
。
5)可是,在這篇文章中,咱們就不加以介紹了;它的思想和延時實現一致,目標一樣是找到與最小生成樹相連的權重最小的一條邊,只不過實現方法更加靈活罷了!
此次和往常不一樣,我並無在文章中間摻雜算法的具體實現,個人想法是把它真正的思路講明白(但願我講的沒有讓你失望🤔);可是,代碼仍是要有的,我將它們放在了這裏,具體來講書籍算法4上面都有!!
Kruskal算法
的實現Prim
算法的實現如何實現一個加權邊
如何實現加權無向圖
Kruskal算法
的實現
Prim
算法的實現(兩張圖片)
碼字繪圖不易,若是以爲本文對你有幫助,還請不要白嫖,關注、點贊、在看都是對小超創做的一種承認!
歡迎你們關注個人公衆號:小超說 ,以後我會繼續創做算法與數據結構以及計算機基礎知識的文章。也能夠加我微信chao_hey(備註:職業-城市) ,咱們一塊兒交流,一塊兒進步!
本文參考:《算法》(第四版),圖片來源於此