Python 实现 Dijkstra 最短路径算法:矩阵与字典两种方案

Ruby
Ruby
发布时间:2026-10-11 | 2人浏览过
原创

本文介绍如何使用 Python 实现 Dijkstra 最短路径算法。通过邻接矩阵和字典两种数据结构,分别演示了如何计算单源到所有节点的最短路径。文章包含完整的代码示例,对比了矩阵与字典在空间占用和实现逻辑上的差异,并详细解析了路径回溯与距离更新的核心步骤。

算法核心逻辑与数据结构选择

Dijkstra 算法用于计算图中一个节点到其余所有节点的最短路径。在 Python 中,图的存储通常有两种方式:邻接矩阵和邻接字典(或邻接表)。邻接矩阵适合节点密集且数量较少的场景,而字典实现则在处理稀疏图时能显著节省空间。

算法的基本流程包括:初始化所有节点的距离为无穷大(源点为 0),每次从未处理的节点中选取距离最小的节点,更新其邻居节点的距离,并记录路径的前驱节点。当所有节点都被处理后,即可通过前驱节点反向回溯得到完整路径。

基于邻接矩阵的实现

使用二维列表(矩阵)存储图结构时,索引直接对应节点编号。这种方法直观,但需要预先定义节点数量,且对于稀疏图会浪费大量空间存储无效连接(通常用无穷大表示)。

在代码实现中,我们定义了一个无穷大常量 inf(示例中为 999999)来表示不可达。算法维护两个关键数组:path_array 记录当前已知的最短距离,path_parent 记录到达该节点的前驱节点,用于后续路径重构。

_=inf=999999#inf
 
def Dijkstra_all_minpath(start,matrix):
 length=len(matrix)#该图的节点数
 path_array=[]
 temp_array=[]
 path_array.extend(matrix[start])#深复制
 temp_array.extend(matrix[start])#深复制
 temp_array[start] = inf#临时数组会把处理过的节点的值变成inf,表示不是最小权值的节点了
 already_traversal=[start]#start已处理
 path_parent=[start]*length#用于画路径,记录此路径中该节点的父节点
 while(len(already_traversal)<length):
  i= temp_array.index(min(temp_array))#找最小权值的节点的坐标
  temp_array[i]=inf
  path=[]#用于画路径
  path.append(str(i))
  k=i
  while(path_parent[k]!=start):#找该节点的父节点添加到path,直到父节点是start
   path.append(str(path_parent[k]))
   k=path_parent[k]
  path.append(str(start))
  path.reverse()#path反序产生路径
  print(str(i)+':','->'.join(path))#打印路径
  already_traversal.append(i)#该索引已经处理了
  for j in range(length):#这个不用多说了吧
   if j not in already_traversal:
    if (path_array[i]+matrix[i][j])<path_array[j]:
     path_array[j] = temp_array[j] =path_array[i]+matrix[i][j]
     path_parent[j]=i#说明父节点是i
 return path_array
 
#领接矩阵
adjacency_matrix=[[0,10,_,30,100],
     [10,0,50,_,_],
     [_,50,0,20,10],
     [30,_,20,0,60],
     [100,_,10,60,0]
     ]
print(Dijkstra_all_minpath(4,adjacency_matrix))

矩阵实现要点

  • 距离更新:遍历所有未处理节点,若通过当前最小节点 i 到达节点 j 的距离更短,则更新 path_array[j] 和 path_parent[j]。
  • 路径回溯:通过 path_parent 数组从目标节点反向追踪至起点,生成路径字符串。
  • 输出格式:直接打印节点及其对应的最短路径,并返回所有节点的距离列表。

基于字典的优化实现

对于节点数量不确定或图结构稀疏的情况,使用字典(嵌套字典)存储图结构更为灵活。字典实现避免了预先分配大量空间,且能更清晰地表达节点间的连接关系。

在字典实现中,path_graph 是一个字典,键为节点,值为当前最短距离。算法逻辑与矩阵实现类似,但遍历邻居节点时,需要检查字典中是否存在该连接。

def Dijkstra_all_minpath_for_graph(start,graph):
 inf = 999999 # inf
 length=len(graph)
 path_graph={k:inf for k in graph.keys()}
 already_traversal=set()
 path_graph[start]=0
 min_node=start#初始化最小权值点
 already_traversal.add(min_node)#把找到的最小节点添加进去
 path_parent={k:start for k in graph.keys()}
 while(len(already_traversal)<=length):
  p = min_node
  if p!=start:
   path = []
   path.append(str(p))
   while (path_parent[p] != start):#找该节点的父节点添加到path,直到父节点是start
    path.append(str(path_parent[p]))
    p=path_parent[p]
   path.append(str(start))
   path.reverse()#反序
   print(str(min_node) + ':', '->'.join(path))#打印
  if(len(already_traversal)==length):break
  for k in path_graph.keys():#更新距离
   if k not in already_traversal:
    if k in graph[min_node].keys() and (path_graph[min_node]+graph[min_node][k])<path_graph[k]:
     path_graph[k]=path_graph[min_node]+graph[min_node][k]
     path_parent[k]=min_node
  min_value=inf
  for k in path_graph.keys():#找最小节点
   if k not in already_traversal:
    if path_graph[k]<min_value:
     min_node=k
     min_value=path_graph[k]
  already_traversal.add(min_node)#把找到最小节点添加进去
 return path_graph
adjacency_graph={0:{1:10,3:30,4:100},
     1:{0:10,2:50},
     2:{1:50,3:20,4:10},
     3:{0:30,2:20,4:60},
     4:{0:100,2:10,3:60}}
print(Dijkstra_all_minpath_for_graph(4,adjacency_graph))

字典实现要点

  • 动态更新:通过 path_graph.keys() 遍历所有节点,检查当前最小节点 min_node 的邻居字典中是否存在该节点。
  • 空间效率:仅存储实际存在的边,对于稀疏图,空间复杂度从 O(V^2) 降低到 O(V+E)。
  • 输出格式:返回一个字典,键为节点,值为最短距离,便于后续程序处理。

两种实现对比

矩阵实现适合节点数量固定且较少的场景,代码逻辑直接,但空间利用率低。字典实现则更加灵活,适合节点数量动态变化或图结构稀疏的场景,空间效率更高。在实际应用中,应根据具体需求选择合适的存储结构。

无论使用哪种方式,Dijkstra 算法的核心在于不断选取当前距离最小的未处理节点,并更新其邻居的距离。通过记录前驱节点,可以高效地回溯出完整路径。

以上就是 Python 矩阵与字典实现最短路径算法的详细内容,更多关于 Python 算法、Dijkstra 算法、邻接矩阵和字典实现的相关资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表