python实现Dijkstra算法求最短路径

前言

最近在考研复习,刚好学到图这一章了,然后也是学到关于图最难的几个部分了,一个是最小生成树(Prim算法和Kruskal算法),还一个就是最短距离问题了(Dijkstra算法和Floyd算法),我感觉前三个算法都还蛮好理解,就是最后一个Floyd有点没整明白,前三个算法基本上都用到贪心的思想,Prim每次都选择当前未使用的消耗最小的顶点(选点);Kruskal每次都是当前未使用的权值最小的边(选边);Dijkstra的思想和Prim的思想大致一直。

这里我就直接贴出源码了,python实现的,有兴趣的可以运行试试(反正考研也不会考python代码python实现Dijkstra算法求最短路径_第1张图片

Dijkstra算法求最短路径

# -*- coding: UTF-8 -*-
'''
   *****************LLL*********************
   * @Project :leetcode                       
   * @File    :lll_107Dijkstra算法求解最短路径.py                  
   * @IDE     :PyCharm             
   * @Author  :LLL                         
   * @Date    :2022/6/1 9:22             
   *****************************************
'''


def dijkstra_min_distance(start, target, graph):
    if start not in graph['V'] or target not in graph['V']: return '无效起点或终点!'

    visited = {}  # 记录顶点的访问情况
    dist = {}  # 记录最短距离
    path = [start]  # 记录最短路径上的每一个顶点
    V, E = graph['V'], graph['E']
    for node in V:
        visited[node] = 0  # 0表示没有访问 1表示已访问
        dist[node] = -1  # -1表示无限远
    dist[start] = 0  # 到自己的距离为0
    visited[start] = 1

    # 初始化到各顶点的距离
    for e in E:
        if e[0] == start:
            dist[e[1]] = E[e]

    # while not all(visited.values()):  # 直到访问完所有顶点 求到所有顶点的最短距离
    while not visited[target]:  # 仅求到终点的距离
        # 在所有可达的但未访问的顶点中,寻找距离最近的一个
        cur_E_li = [(e, E[e]) for e in E if visited[e[0]] and not visited[e[1]]]  # 所有可达但未访问的顶点
        cur_E_li.sort(key=lambda a: a[1])  # 按照距离进行排序
        print(cur_E_li)
        min_edge_w = cur_E_li[0]  # 第一个就是距离最短的那一个
        new_start_node = min_edge_w[0][1]

        # 刷新最短距离
        for node in dist:
            new_edge = (new_start_node, node)
            if new_edge in E:
                if dist[node] == -1:
                    dist[node] = dist[new_start_node] + E[new_edge]
                else:
                    dist[node] = min(dist[node], dist[new_start_node] + E[new_edge])

        # 更新visited
        visited[new_start_node] = 1
        path.append(new_start_node)  # 将当前节点更新到最短路径上

    return path, dist[target]


if __name__ == '__main__':
    V = {1, 2, 3, 4, 5}  # 顶点集

    E = {  # 边集
        (1, 2): 10,  # (起点,终点):权值
        (1, 5): 5,
        (2, 3): 1,
        (2, 5): 2,
        (3, 4): 4,
        (4, 1): 7,
        (4, 3): 6,
        (5, 2): 3,
        (5, 3): 9,
        (5, 4): 2,
    }
    graph = {
        'V': V,
        'E': E
    }

    print(dijkstra_min_distance(1, 4, graph))

Prim算法求最小生成树

# -*- coding: UTF-8 -*-
'''
   *****************LLL*********************
   * @Project :leetcode                       
   * @File    :lll_108Prim算法求最小生成树.py                  
   * @IDE     :PyCharm             
   * @Author  :LLL                         
   * @Date    :2022/6/1 18:58             
   *****************************************
'''

# prim算法
'''
核心:初始时从图中任取一顶点加入树T,此时树中只含有一个顶点,之后
选择一个与当前T中顶点集合距离最近的顶点,并将该顶点加入树T中,直到
所有顶点都被加入树T。
'''
from math import inf

def prim_min_span_tree(graph):
    visited = {node: 0 for node in graph}  # 用于表示一个顶点是否被访问
    root = 1  # 任意取一个顶点
    visited[root] = 1
    T_w = {}

    while not all(visited.values()):  # 只要不是所有的顶点被访问了,就一直进行下去

        # 查找与树T距离最近,但未被访问的顶点
        not_visited_nodes = {node for node in graph if not visited[node]}  # 未被访问的顶点
        visited_nodes = {node for node in graph if visited[node]}  # 树T

        min_distance = inf
        min_node = None
        min_edge = None

        # 求到树T距离最近的节点
        for t in visited_nodes:
            for node in not_visited_nodes:
                cur_edge = '-'.join(map(str, sorted((t, node))))
                cur_w = W.get(cur_edge, -1)  # 当前边的权重
                if cur_w != -1 and cur_w < min_distance:
                    min_distance = cur_w
                    min_node = node
                    min_edge = cur_edge

        print(f'当前距离树T最近的节点:{min_node},权重为:{min_distance}')
        T_w[min_edge] = min_distance  # 添加到树T的权重记录表中
        visited[min_node] = 1  # 更新当前节点为已访问
    print(T_w)


if __name__ == '__main__':
    # 邻接表法表示图
    graph = {
        1: {2, 3, 4},
        2: {1, 3, 5},
        3: {1, 2, 4, 5, 6},
        4: {1, 3, 6},
        5: {2, 3, 6},
        6: {3, 4, 5}
    }

    W = {
        '1-2': 6,
        '1-3': 1,
        '1-4': 5,
        '2-3': 5,
        '2-5': 3,
        '3-4': 5,
        '3-5': 6,
        '3-6': 4,
        '4-6': 2,
        '5-6': 6
    }  # 权重
    print(prim_min_span_tree(graph))

 同步更新于个人博客系统:python实现Dijkstra算法求最短路径

你可能感兴趣的:(图,算法,图论,数据结构)