算法圖解-狄克斯特拉算法

  • 在之前的廣度優(yōu)先搜索中,可以找出了從A點到B點的最短路徑秤掌。


    0-1
  • 這是最短路徑闻鉴,因為段數(shù)最少——只有三段,但不一定是最快路徑瓶竭。如果給這些路段加上時間渠羞,你將發(fā)現(xiàn)有更快的路徑。


    0-2
  • 之前用了廣度優(yōu)先搜索荧恍,它找出的是段數(shù)最少的路徑(如第一個圖所示)如果你要找出最快的路徑(如第二個圖所示)送巡,該如何辦呢盒卸?為此,可使用另一種算法——狄克斯特拉算法(Dijkstra’s algorithm)
  1. 使用狄克斯特拉算法
    1-1

    其中每個數(shù)字表示的都是時間淮腾,單位分鐘谷朝。為找出從起點到終點耗時最短的路徑武花,你將使用
    狄克斯特拉算法。
    如果你使用廣度優(yōu)先搜索专钉,將得到下面這條段數(shù)最少的路徑。
    1-2

    這條路徑耗時7分鐘站叼。下面來看看能否找到耗時更短的路徑尽楔!狄克斯特拉算法包含4個步驟第练。
    (1) 找出“最便宜”的節(jié)點,即可在最短時間內到達的節(jié)點呕寝。
    (2) 更新該節(jié)點的鄰居的開銷婴梧,其含義將稍后介紹。
    (3) 重復這個過程怔球,直到對圖中的每個節(jié)點都這樣做了浮还。
    (4) 計算最終路徑钧舌。
    第一步:找出最便宜的節(jié)點。你站在起點崭歧,不知道該前往節(jié)點A還是前往節(jié)點B撞牢。前往這兩
    個節(jié)點都要多長時間呢?
    1-3
    1-4

前往節(jié)點A需要6分鐘,而前往節(jié)點B需要2分鐘畜挥。至于前往其他節(jié)點,你還不知道需要多長時間躯泰。
由于你還不知道前往終點需要多長時間麦向,因此你假設為無窮大(這樣做的原因你馬上就會明白)。節(jié)點B是最近的——2分鐘就能達到话告。
第二步:計算經節(jié)點B前往其各個鄰居所需的時間秀撇。

1-5

你剛找到了一條前往節(jié)點A的更短路徑呵燕!直接前往節(jié)點A需要6分鐘件相。
1-6

但經由節(jié)點B前往節(jié)點A只需5分鐘夜矗!
1-7

對于節(jié)點B的鄰居紊撕,如果找到前往它的更短路徑,就更新其開銷对扶。在這里浪南,你找到了:

  • 前往節(jié)點A的更短路徑(時間從6分鐘縮短到5分鐘);
  • 前往終點的更短路徑(時間從無窮大縮短到7分鐘)骡送。

第三步:重復絮记!
重復第一步:找出可在最短時間內前往的節(jié)點怨愤。你對節(jié)點B執(zhí)行了第二步,除節(jié)點B外憔四,可
在最短時間內前往的節(jié)點是節(jié)點A。

1-8

重復第二步:更新節(jié)點A的所有鄰居的開銷甸赃。
1-9

你發(fā)現(xiàn)前往終點的時間為6分鐘埠对!
你對每個節(jié)點都運行了狄克斯特拉算法(無需對終點這樣做)〔锰妫現(xiàn)在,你知道:

  • 前往節(jié)點B需要2分鐘襟沮;
  • 前往節(jié)點A需要5分鐘昌腰;
  • 前往終點需要6分鐘。
    1-10

    廣度優(yōu)先搜索查找的是兩點之間的最短路徑固灵,“最短路徑”的意思是
    段數(shù)最少巫玻。在狄克斯特拉算法中祠汇,給每段都分配了一個數(shù)字或權重,因此狄克斯特拉算法找出
    的是總權重最小的路徑徒扶。
    對比
  1. 術語
    狄克斯特拉算法用于每條邊都有關聯(lián)數(shù)字的圖姜骡,這些數(shù)字稱為權重(weight)屿良。
    2-1

    帶權重的圖稱為加權圖(weighted graph)尘惧,不帶權重的圖稱為非加權圖(unweighted graph)。
    2-2

    要計算非加權圖中的最短路徑啥么,可使用廣度優(yōu)先搜索悬荣。要計算加權圖中的最短路徑,可使用狄克斯特拉算法践叠。圖還可能有環(huán)嚼蚀,而環(huán)類似下面這樣。
    2-3

    2-4

3. 代碼實現(xiàn)

  • 以下面的圖為例


    3-1
  • 要編寫解決這個問題的代碼,需要三個散列表察藐。


    3-2
graph = {}
graph["start"] = {}
graph["start"]["a"] = 6
graph["start"]["b"] = 2
graph["a"] = {}
graph["a"]["fin"] = 1
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {}
# 創(chuàng)建開銷表的代碼如下:
infinity = float("inf")
costs = {}
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity
# 存放父節(jié)點的字典
parents = {}
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None
# 最后,你需要一個數(shù)組悴务,用于記錄處理過的節(jié)點讯檐,因為對于同一個節(jié)點,你不用處理多次别洪。
processed = []
# print(graph)
def find_lowest_cost_node(costs):
    "在未處理的節(jié)點中找出開銷最小的節(jié)點"
    lowest_cost = float("inf")
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost < lowest_cost and node not in processed:
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node
node = find_lowest_cost_node(costs)
while node is not None: # 這個while循環(huán)在所有節(jié)點都被處理過后結束
    cost = costs[node]
    neighbors = graph[node]
    for n in neighbors.keys(): # 遍歷當前節(jié)點的所有鄰居
        new_cost = cost + neighbors[n]
        if costs[n] > new_cost: # 如果經當前節(jié)點前往該鄰居更近
            costs[n] = new_cost # 就更新該鄰居的開銷
            parents[n] = node # 同時將該鄰居的父節(jié)點設置為當前節(jié)點
    processed.append(node) # 將當前節(jié)點標記為處理過
    node = find_lowest_cost_node(costs) # 找出接下來要處理的節(jié)點挖垛,并循環(huán)
print(processed)
  1. 小結
  • 廣度優(yōu)先搜索用于在非加權圖中查找最短路徑。
  • 狄克斯特拉算法用于在加權圖中查找最短路徑送矩。
  • 僅當權重為正時狄克斯特拉算法才管用哪替。
  • 如果圖中包含負權邊,請使用貝爾曼-福德算法晌块。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末摸袁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜂大,更是在濱河造成了極大的恐慌蝶怔,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澳叉,死亡現(xiàn)場離奇詭異成洗,居然都是意外死亡藏否,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門遥椿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冠场,“玉大人本砰,你說我怎么就攤上這事√蛑辏” “怎么了咖楣?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵诱贿,是天一觀的道長咕缎。 經常有香客問我料扰,道長晒杈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任帖努,我火速辦了婚禮粪般,結果婚禮上亩歹,老公的妹妹穿的比我還像新娘。我一直安慰自己小作,他們只是感情好顾稀,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氮块,像睡著了一般诡宗。 火紅的嫁衣襯著肌膚如雪塔沃。 梳的紋絲不亂的頭發(fā)上阳谍,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天矫夯,我揣著相機與錄音,去河邊找鬼训貌。 笑死,一個胖子當著我的面吹牛豺鼻,可吹牛的內容都是我干的。 我是一名探鬼主播谬莹,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼附帽,長吁一口氣:“原來是場噩夢啊……” “哼井誉!你這毒婦竟也來了?” 一聲冷哼從身側響起慢显,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤荚藻,失蹤者是張志新(化名)和其女友劉穎洁段,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾呻,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡写半,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叠蝇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片璃岳。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖悔捶,靈堂內的尸體忽然破棺而出铃慷,到底是詐尸還是另有隱情,我是刑警寧澤蜕该,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布犁柜,位于F島的核電站,受9級特大地震影響堂淡,放射性物質發(fā)生泄漏馋缅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一股囊、第九天 我趴在偏房一處隱蔽的房頂上張望袜匿。 院中可真熱鬧,春花似錦稚疹、人聲如沸居灯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怪嫌。三九已至,卻和暖如春柳沙,著一層夾襖步出監(jiān)牢的瞬間岩灭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工赂鲤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留噪径,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓数初,卻偏偏與公主長得像找爱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泡孩,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容