Python 实现Dijkstra(迪杰斯特拉)最短路径算法

本文的算法思想来自于知乎的一篇文章。大家可以点击链接去看看,会有意外收获哦。😎

Dijkstra 算法

Dijkstra是一个经典的贪心算法

时间复杂度是 O ( E l o g E ) O(ElogE) O(ElogE),其中 E E E 是节点数的最大值。

基本思想

  1. 通过Dijkstra计算图G中的最短路径时,需要指定一个起点D(即从顶点D开始计算)。

  2. 此外,引进两个数组S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点D的距离)。

  3. 初始时,数组S中只有起点D;数组U中是除起点D之外的顶点,并且数组U中记录各顶点到起点D的距离。如果顶点与起点D不相邻,距离为无穷大。

  4. 然后,从数组U中找出路径最短的顶点K,并将其加入到数组S中;同时,从数组U中移除顶点K。接着,更新数组U中的各顶点到起点D的距离(即更新与K相连的边到起点的距离,在通过K与不通过K二者之间寻找较小值)。

  5. 重复第4步操作,直到遍历完所有顶点。

上面这幅图来自于B站的一个视频。大家可以点击链接去看看,会有意外收获哦。😎

构造图

def create_graph():
    edges = []
    for i in range(9):
        edges.append([])
        for j in range(9):
            edges[i].append(0 if j==i else float('inf'))

    edges[0][1] = 4
    edges[0][7] = 8
    edges[1][0] = 4
    edges[1][2] = 8
    edges[1][7] = 3
    edges[2][1] = 8
    edges[2][3] = 7
    edges[2][5] = 4
    edges[2][8] = 2
    edges[3][2] = 7
    edges[3][4] = 9
    edges[3][5] = 14
    edges[4][3] = 9
    edges[4][5] = 10
    edges[5][2] = 4
    edges[5][3] = 14
    edges[5][4] = 10
    edges[5][6] = 2
    edges[6][5] = 2
    edges[6][7] = 6
    edges[6][8] = 6
    edges[7][0] = 8
    edges[7][1] = 3
    edges[7][6] = 6
    edges[7][8] = 1
    edges[8][2] = 2
    edges[8][6] = 6
    edges[8][7] = 1
    return edges

本例计算 0 → 4 的最短距离

graph = create_graph()
graph
[[0, 4, inf, inf, inf, inf, inf, 8, inf],
 [4, 0, 8, inf, inf, inf, inf, 3, inf],
 [inf, 8, 0, 7, inf, 4, inf, inf, 2],
 [inf, inf, 7, 0, 9, 14, inf, inf, inf],
 [inf, inf, inf, 9, 0, 10, inf, inf, inf],
 [inf, inf, 4, 14, 10, 0, 2, inf, inf],
 [inf, inf, inf, inf, inf, 2, 0, 6, 6],
 [8, 3, inf, inf, inf, inf, 6, 0, 1],
 [inf, inf, 2, inf, inf, inf, 6, 1, 0]]
# 计算字典中values中最小值所在的所有键值对
def get_min_value_pairs(dic):
    min_value = min(dic.values())
    # 下面这条语句可以找到代表min_value的多个key
    keys =  [k for k, v in dic.items() if v == min_value]
    # 返回所有的最小值的键值对
    return [(k, dic[k]) for k in keys]
def Dijkstra(start, end, graph):
    nodes_num = len(graph)
    S = {} # 已计算出起点到定点最短路径的定点集合
    U = {} # 未计算出起点到定点最短路径的定点集合
    # 键值对 4:8 表示起点到定点4的最短距离为8
    # 初始化 S 和 U
    S[start] = 0 # 起点到自己的最短距离为 0 
    for i in range(nodes_num):
        U[i] = graph[start][i]
    # 开始计算
    while len(U) > 0:
        # 在 U 中寻找到起点距离最短的节点,将其插入 S 中,并在 U 中移除
        min_dis_node, min_dis = get_min_value_pairs(U)[0]
        S[min_dis_node] = min_dis
        U.pop(min_dis_node)
        # 更新 U 中与新插入到 S 中的点对其相邻点到起点的距离值
        for key in list(U.keys()):
            if graph[min_dis_node][key] != float('inf'): # 找到与新插入点相连的顶点
                U[key] = min(U[key], min_dis + graph[min_dis_node][key])
    return S
pairs = Dijkstra(0, 4, graph)
print(pairs)
print('0→4 的最短距离为 {0}'.format(pairs[4]))
{0: 0, 1: 4, 7: 7, 8: 8, 2: 10, 6: 13, 5: 14, 3: 17, 4: 24}
0→4 的最短距离为 24
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迪杰斯特拉最短路径算法是一种经典的单源最短路径算法,用于解决带权重的有向图或无向图中,从一个源点到其他所有顶点的最短路径问题。 算法的基本思想是通过逐步扩展离源点越来越近的顶点的方式,逐步确定源点到其他顶点的最短路径。具体实现时,需要维护两个集合S和V-S,其中S表示已经确定最短路径的顶点集合,V-S表示还未确定最短路径的顶点集合。初始时,S中只包含源点,V-S包含其他所有顶点。然后,每次从V-S中选择一个距离源点最近的顶点u加入到S中,并更新源点到其它顶点的距离。 下面是Python实现迪杰斯特拉最短路径算法的代码,以邻接矩阵表示的有向图为例: ```python import sys def dijkstra(graph, src): n = len(graph) dist = [sys.maxsize] * n # 记录源点到各个顶点的距离 visited = [False] * n # 标记顶点是否已加入S集合 dist[src] = 0 # 初始化源点到自身的距离为0 for _ in range(n): # 找到距离源点最近的未加入S集合的顶点 u = -1 min_dist = sys.maxsize for i in range(n): if not visited[i] and dist[i] < min_dist: u = i min_dist = dist[i] if u == -1: break visited[u] = True # 更新源点到所有邻居顶点的距离 for v in range(n): if not visited[v] and graph[u][v] != 0: dist[v] = min(dist[v], dist[u] + graph[u][v]) return dist # 有向图的邻接矩阵表示 graph = [[0, 10, 3, 0, 0], [0, 0, 1, 2, 0], [0, 4, 0, 8, 2], [0, 0, 0, 0, 7], [0, 0, 0, 9, 0]] print(dijkstra(graph, 0)) # 输出从源点0到其他各个顶点的最短距离 ``` 该代码中,dijkstra函数的参数graph是邻接矩阵表示的有向图,src是源点的索引。在dijkstra函数中,首先初始化源点到各个顶点的距离dist和标记顶点是否已加入S集合的visited数组。然后,在每一轮循环中,找到距离源点最近的未加入S集合的顶点u,并将其加入S集合中。然后,遍历源点的所有邻居顶点v,更新源点到v的距离。最后返回源点到其他所有顶点的最短距离dist。 运行上述代码,输出结果为:[0, 7, 3, 10, 5],表示源点0到其他各个顶点的最短距离。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值