理解Dijkstra算法

學習過最短路徑問題的人都不會不知道Dijkstra算法酥夭。這個算法適用于解決無負權圖的單源(且不管是否有向)最短路徑問題册赛。這篇小文來談談如何理解這一算法盒犹。

這里首先給出一個Python 3的代碼實現(xiàn)(以下代碼出自Python Algorithms一書牵祟,略有改動)痪蝇。

from heapq import heappush, heappop


def dijkstra(G, s):
    D, P, Q = {}, {}, [(0, None, s)]
    while Q:
        du, pu, u = heappop(Q)
        D[u], P[u] = du, pu
        for v in G[u]:
            if v not in D:
                heappush(Q, (du + G[u][v], u, v))
    return D, P

Dijkstra算法可以從很多角度去理解。我個人覺得最便于理解和記憶的角度喻旷,是將其視為一個圖遍歷算法生逸。這從上面的代碼中就能夠看出來。遍歷節(jié)點的算法都需要記錄“前線”且预,也就是所有已經(jīng)訪問過但沒有“完全考察”的節(jié)點槽袄。不同的遍歷算法,記錄“前線”所用的數(shù)據(jù)結構也不同锋谐。比如遍尺,BFS使用的是FIFO的隊列,DFS可以使用FILO的棧涮拗;而上面的代碼使用的則是一個優(yōu)先隊列乾戏。(實際上,如果待解決的圖的所有邊的權重都為同一正值的話多搀,那么就可以用BFS來解決歧蕉。換言之,BFS算法可以視為Dijkstra算法的一個特例康铭,是可以用于(實際上是最佳的)解決無權圖的單源最短路徑的算法。)

那么赌髓,怎么直觀地去理解Dijkstra算法所表示的這一遍歷過程呢从藤?比如說催跪,我們要解決的問題如果可以表現(xiàn)為下面這幅圖——這是幅無向無負權圖,其中S點表示起點夷野,每條邊的權重就是標注在旁邊的數(shù)字——那么怎么去表現(xiàn)Dijkstra算法所設定的遍歷呢懊蒸?

image

這里需要耍一個思維上的小花招:我們把每條邊想象成真實的路徑,然后把權重想象成對應路徑的長度悯搔。然后假設站在起點S的是旋渦鳴人骑丸。在0時刻,旋渦鳴人首先將起點S涂成黑色(在上面代碼中表現(xiàn)為D[s], P[s] = 0, None)妒貌,然后沿每條從S點出發(fā)的路徑——在上圖里就是SA通危、SB、SC三條邊——派出一名影分身灌曙。這些影分身的速度都一樣菊碟,每前進1個長度需花費1個單位的時間,所以在時刻7在刺、9逆害、14,這三個影分身分別依次到達C蚣驼、B魄幕、A點。每個影分身到達自己的目的地時颖杏,都會檢查該點有沒有被涂黑纯陨;如果已經(jīng)被涂黑,說明有別的影分身走了一條更短的路徑來過這個點输玷,那么這個后到的影分身就完成了自己的使命队丝,不用再考察已被涂黑的點的后續(xù)節(jié)點,可以“噗”地一下化成青煙消失了欲鹏;如果沒有被涂黑机久,那么說明這個影分身走的是起點S到該點的最短路徑,記下現(xiàn)在的時刻(也就是所循路徑的長度赔嚎,也即到S點的距離膘盖,D[u] = du)以及上一個節(jié)點(P[u] = pu),把這一點涂黑尤误,最后朝每條未被涂黑的鄰點派出新的影分身侠畔。例如上面的例子里,時刻9時损晤,有一個從起點S出發(fā)的影分身會到達B點软棺。由于B此時還是白色的,說明S到B的最短路徑的長度為9尤勋。涂黑B點喘落,然后朝A茵宪、E兩點各派出一名影分身(之所以不往C點派影分身,是因為C點已經(jīng)在時刻7被另一個從S點出發(fā)的影分身涂黑了瘦棋,也就是已經(jīng)在D這個dict里了)稀火。注意從B點往A點出發(fā)的影分身將在時刻11(=9+2)到達,早于從S點出發(fā)往A點去的那個影分身(他將在時刻14到達)赌朋,所以等后者到達時凰狞,會發(fā)現(xiàn)A點已經(jīng)是黑色的了。如此重復沛慢,直到所有的影分身都消失了赡若,也即所有從S點能夠到達的點都涂成了黑色(遍歷),也就是“前線”中不再有仍在路上的影分身(while Q不再繼續(xù))颠焦。這時候斩熊,所有被涂黑的點,都記錄下了涂黑的時刻(最短距離)和每一個中間節(jié)點(最短路徑)伐庭。

按照這種理解粉渠,那么算法中的優(yōu)先隊列其實可以看作是時間軸。每次往優(yōu)先隊列里push一個元素圾另,代表新派出一個影分身霸株;而每次從優(yōu)先隊列里pop出一個元素,則代表了某個影分身到達了其目的節(jié)點集乔。而且去件,這種思路還可以幫我們從直觀上理解Dijkstra算法的適用范圍:必須無負權邊,因為影分身所走路徑的長度不可能為負扰路;既可以是有向圖也可以是無向圖尤溜,影分身按照允許的方向走就行了。

以上就是我對Dijkstra算法的一點理解汗唱。希望能夠對學習算法的同學有點幫助宫莱。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哩罪,隨后出現(xiàn)的幾起案子授霸,更是在濱河造成了極大的恐慌,老刑警劉巖际插,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碘耳,死亡現(xiàn)場離奇詭異,居然都是意外死亡框弛,警方通過查閱死者的電腦和手機辛辨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人愉阎,你說我怎么就攤上這事绞蹦×Ψ埽” “怎么了榜旦?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長景殷。 經(jīng)常有香客問我溅呢,道長,這世上最難降的妖魔是什么猿挚? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任咐旧,我火速辦了婚禮,結果婚禮上绩蜻,老公的妹妹穿的比我還像新娘铣墨。我一直安慰自己,他們只是感情好办绝,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布伊约。 她就那樣靜靜地躺著,像睡著了一般孕蝉。 火紅的嫁衣襯著肌膚如雪屡律。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天降淮,我揣著相機與錄音超埋,去河邊找鬼。 笑死佳鳖,一個胖子當著我的面吹牛霍殴,可吹牛的內容都是我干的。 我是一名探鬼主播系吩,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼来庭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淑玫?” 一聲冷哼從身側響起巾腕,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎絮蒿,沒想到半個月后尊搬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡土涝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年佛寿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡冀泻,死狀恐怖常侣,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情弹渔,我是刑警寧澤胳施,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肢专,受9級特大地震影響舞肆,放射性物質發(fā)生泄漏。R本人自食惡果不足惜博杖,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一椿胯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剃根,春花似錦哩盲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舔糖,卻和暖如春娱两,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背金吗。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工十兢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摇庙。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓旱物,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卫袒。 傳聞我的和親對象是個殘疾皇子宵呛,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容