1. 程式人生 > >Dijkstra演算法實現最快路徑

Dijkstra演算法實現最快路徑

       Dijkstra演算法是由荷蘭電腦科學家狄克斯特拉於1959 年提出的,因此又叫狄克斯特拉演算法。是從一個頂點到其餘各頂點的最短路徑演算法,解決的是有向圖中最短路徑問題。迪傑斯特拉演算法主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。

      下面,我用python來舉例詳細介紹這個演算法

     問題如下:

                    如圖所示(我們規定箭頭上的數字為時間)現有如下路徑圖,我們想盡快從起點到達終點,那也就是求最快路徑的問題了

接下來我們先把問題建模

這是GRAPH表,將該路徑描述用表格形式表現出來

graph = {}#定義鄰居表
graph["start"] = {}#起點的鄰居
graph["start"]["a"] = 6
graph["start"]["b"] = 2

graph["a"] = {}#a點的鄰居
graph["a"]["end"] = 1

graph["b"] = {}#b點的鄰居
graph["b"]["a"] = 3
graph["b"]["end"] = 5

graph["end"] = {}#終點沒有任何鄰居

然後是COSTS表,用於將起點到各個點的的開銷列出來,不能直接到達的,該事件設為無窮大(用“-”表示,後期再更改)

costs = {}#定義開銷表,即起點到其餘節點的開銷,不是直接到達的,就暫時用無窮大定義
costs["a"] = 6
costs["b"] = 2
costs["end"] = float("inf")#定義極大值

最後是PARENT表,用於記錄每個節點的父節點(父節點:如B被起點指向,則稱起點是B的父節點)(若有某個遠端節點(非起點指向)被兩個節點指向,則暫時不寫,用“-”表示)

parent = {}#定義父節點表,僅看只有一個父節點的節點,若有兩個父節點,則暫時定義為空
parent["a"] = "start"
parent["b"] = "start"
parent["end"] = None #終點節點(非遠端節點)在表中有兩個父節點,故暫時不填

至此,問題描述,建模完畢

我們先定義一個列表,用於儲存那些被處理的節點,防止重複處理

processed = [] #定義flag,用於標記某節點已被處理,防止多餘計算甚至死迴圈

接下來是具體演算法描述部分:

定義find_lowest_cost_node函式,傳入COSTS表,用於查詢當前未處理的,函式返回用時最少的下一節點,通俗點來說,就是把起點的子節點按用時情況,從小到達依次返回一個子節點(是返回一個節點,不是時間),思想是:每次定義一個無窮大,然後每次將起點的子節點遍歷,直到找出此時的用時最小的節點,思想類似氣泡排序中的找出最大/小值

#此函式的作用是依次獲取該起點能到的所有點,從小到大
def find_lowest_cost_node(costs):#找出到達開銷最小的節點
    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

 最關鍵的下面的演算法思想:

上一個函式將依次返回起點到另一個用時最少的節點,然後分如下幾步:

         1.記錄起點到該點的用時cost

         2.遍歷該節點的所有鄰居,分別得到該點到其各個鄰居的用時(比如B的一個鄰居A)

         3.在原始costs表中查詢到起點到A的開銷為6,就是程式碼中的costs[n],起點到B的開銷為2(也就是步驟1中cost)B到A的開銷為3,就是程式碼中的neighbirs[n],將costs[A]與cost+neighbirs[A]作比較,也就是(6與2+3作比較),後者小於前者,那麼就更新路徑(之前是起點直接到A,用時6,現在要想到達A,就起點先到B,然後B再到A,用時5,顯然後面這條路徑用時少一些,然後更新costs表和parent表)

def main():
    node = find_lowest_cost_node(costs)
    while node is not None:
        cost = costs[node]
        neighbors = graph[node]#獲取該node節點的鄰居
        for n in neighbors.keys():#將該節點的鄰居依次遍歷出來
            new_cost = cost+neighbors[n]#計算從當前節點到達其鄰居的開銷與其起點到其開銷的和
            if costs[n] > new_cost:#如果新開銷和比之前的開銷小,就更新開銷表和父節點表
                costs[n] = new_cost#將起點到該節點的開銷更新
                parent[n] = node#更新該節點的父節點,意味著從這條路徑過來花的時間最少
        processed.append(node)#將該節點標記為已處理節點
        node = find_lowest_cost_node(costs)#繼續找下一個未被處理的節點
    print(costs["end"])