狄克斯特拉算法(Dijkstra’s algorithm)
找出最快的路徑使用算法——狄克斯特拉算法(Dijkstra’s algorithm)。
使用狄克斯特拉算法
步驟
(1) 找出最便宜的節點,即可在最短時間內前往的節點。
(2) 對於該節點的鄰居,檢查是否有前往它們的更短路徑,如果有,就更新其開銷。
(3) 重復這個過程,直到對圖中的每個節點都這樣做了。
(4) 計算最終路徑。
術語
權重(weight):
狄克斯特拉算法用於每條邊都有關聯數字的圖,這些數字稱為權重(weight)。
加權圖/非加權圖(weighted graph)
帶權重的圖稱為加權圖( weighted graph),不帶權重的圖稱為非加權圖(unweighted graph)。
要計算非加權圖中的最短路徑,可使用廣度優先搜索。要計算加權圖中的最短路徑,可使用狄克斯特拉算法。
環
可從一個節點出發,走一圈后又回到這個節點。
無向圖意味着兩個節點彼此指向對方,其實就是環!
狄克斯特拉算法只適用於有向無環圖(directed acyclicgraph,DAG)。
負權邊
不能將狄克斯特拉算法用於包含負權邊的圖
狄克斯特拉算法這樣假設:對於處理過的海報節點,沒有前往該節點的更短路徑。這種假設僅在沒有負權邊時才成立。
實現
示例:求起點到終點的最短路徑
#創建所有節點和路徑的散列表 graph={'start': {'a': 6, 'b': 2}, 'a': {'fin': 1}, 'b': {'a': 3, 'fin': 5}, 'fin': {}} #創建已知節點花銷的散列表 costs={'a': 6, 'b': 2, 'fin': float("inf")} #float('inf') 表示正無窮 #儲存父節點的散列表 parents={'a': 'start', 'b': 'start', 'fin': None} #存儲已訪問過節點的列表 processed=[] #定義一個尋找最小花銷的函數 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 node = find_lowest_cost_node(costs) #找到花銷最小的節點 while node is not None: #這個while循環在所有節點都被處理過后結束 cost = costs[node] neighbors = graph[node] for n in neighbors.keys(): #遍歷當前節點的所有鄰居 new_cost = cost + neighbors[n] #該節點到達該鄰居的花銷總和 if costs[n] > new_cost: #如果經當前節點前往該鄰居更近 costs[n] = new_cost #更新該鄰居的花銷 parents[n] = node #同時將該鄰居的父節點設置為當前節點 processed.append(node) #將當前節點標記為處理過 node = find_lowest_cost_node(costs) #找出接下來要處理的節點,並循環 print(parents)
小結
- 廣度優先搜索用於在非加權圖中查找最短路徑。
- 狄克斯特拉算法用於在加權圖中查找最短路徑。
- 僅當權重為正時狄克斯特拉算法才管用。
- 如果圖中包含負權邊,請使用貝爾曼福德算法