一. DJKSTRA算法概述
我們可以將地圖抽象為Graph的數據結構,然后利用Graph的廣度優先遍歷算法(Breadth-First Search, BFS)解決無權重的High-Level的地圖級別的規划。但是實際應用場景中,地圖中各個路徑所代表的Graph的邊的權重都是不同的,比如距離長的Edge權重就應該比較低;交通擁堵的Edge權重就應該低等等。對於有權重的Graph如何進行最短路徑規划呢,Dijkstra算法可以解決這個問題。
Dijkstra算法是一種有權圖(Graph)的單源最短路徑求解算法,給定一個起點,使用Dijkstra算法可以得到起點到其它所有節點的最短路徑。Dijkstra算法要求圖(Graph)中所有邊的權重都為非負值,只有保證了這個條件才能該算法的適用性和正確性。
算法思想:偷個懶,摘自百度百科
二. 示例問題
給出如下帶權重的圖,求從A到G的最短路徑
第一步:
構建一個記錄最短路徑和距離並用來計算權重的表格。初始化這個表格,除了起點A,已知距離為0,其它距離初始化為無窮大。
A | B | C | D | E | F | G |
0 | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ |
第二步:
以A為起點,可以得到從A出發的幾條邊,更新最短距離,並標記A為已計算過最小路徑
找到:
A - B; 權重8
A - D; 權重10
A - E; 權重12
第三步:
遍歷上一步找出的幾條路徑,選擇最短路徑,並計算其臨邊的所有路徑,更新表格,並標記B為已找過的頂點
找到:
A - B - C 14
A - B - F 20
第四步:不斷重復第三步,直到所有頂點都找完為止
第五步:得到結果 A - B - F - G
三. Python代碼實現
1 #!/usr/bin/python3 2 # -*- coding: utf-8 -*- 3 # @author: Asp1rant 4 5 6 def djkstra(graph, start, end): 7 path_set = set() # 已求的路徑集合 8 priority_dic = {} 9 for k in graph.keys(): 10 priority_dic[k] = [9999, False, ""] # 權重表構建為一個3維數組,分別是:最小路徑代價,是否計算過最小邊,最小路徑 11 priority_dic[start][0] = 0 12 13 # 判斷權重表中所有路點是否添加完畢 14 def isSelectAll(): 15 ret = True 16 for val in priority_dic.values(): 17 if not val[1]: 18 ret = False 19 break 20 return ret 21 22 while not isSelectAll(): 23 find_point = start 24 find_path = start 25 min_distance = 9999 26 for path in path_set: 27 end_point = path[-1] 28 path_distance = priority_dic[end_point][0] 29 if path_distance < min_distance and not priority_dic[end_point][1]: 30 find_point = end_point 31 find_path = path 32 min_distance = path_distance 33 find_distance = priority_dic[find_point][0] 34 neighbors = graph[find_point] 35 for k in neighbors.keys(): 36 p = find_path + "-" + k 37 weight = find_distance + neighbors[k] 38 path_set.add(p) 39 if weight < priority_dic[k][0]: 40 priority_dic[k][0] = weight 41 priority_dic[k][2] = p 42 priority_dic[find_point][1] = True 43 44 return priority_dic[end] 45 46 47 if __name__ == '__main__': 48 # 用於測試的圖 49 graph = { 50 "A": {"B": 8, "D": 10, "E": 12}, 51 "B": {"C": 6, "F": 12}, 52 "C": {"F": 8}, 53 "D": {"E": 10, "G": 30}, 54 "E": {"F": 10}, 55 "F": {"G": 12}, 56 "G": {} 57 } 58 result = djkstra(graph, "A", "G") 59 print(result)
輸出結果:
[32, True, 'A-B-F-G']