一. 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']