📜  Dijkstra 的最短路径算法 |贪婪算法7(1)

📅  最后修改于: 2023-12-03 15:30:27.239000             🧑  作者: Mango

Dijkstra 的最短路径算法 | 贪婪算法

简述

Dijkstra 的最短路径算法是一种用于求图中两个节点之间的最短路径的算法,它属于贪心算法的一种。Dijkstra 算法可以处理带权有向图和无向图,但是不能处理负权边。该算法以起点为基础,从起点开始往外扩散,直到扩散到终点为止。在扩散的过程中,每个节点都记录了到起点的最短距离。

算法流程
  1. 初始化:将起点的距离设为 0,将其它节点的距离设为无穷大。
  2. 从起点开始,将与起点相邻的节点的距离设为相邻边的权重。
  3. 重复以下操作,直到扩散到终点:
    1. 在所有未标记的节点中,选择到起点距离最短的节点作为当前节点。
    2. 对当前节点的所有未标记的邻居节点,计算出到这些邻居节点的距离。
    3. 如果计算出的距离比已有距离小,则更新该节点的距离。
    4. 将该节点标记为已访问过。
代码实现
import sys

class Dijkstra:

    def __init__(self, graph, start):
        self.graph = graph
        self.start = start
        self.dist = {node: sys.maxsize for node in graph}
        self.dist[start] = 0
        self.visited = set()

    def find_shortest_path(self):
        """
        执行最短路径算法并返回从起点到每个节点的最短距离。
        """
        while len(self.visited) < len(self.graph):
            node, dist = self.find_next_node()
            self.visited.add(node)

            for neighbour, cost in self.graph[node].items():
                new_dist = dist + cost
                if new_dist < self.dist[neighbour]:
                    self.dist[neighbour] = new_dist

        return self.dist

    def find_next_node(self):
        """
        返回当前未访问过节点中,到起点距离最短的节点。
        """
        min_dist = sys.maxsize
        min_node = None

        for node, dist in self.dist.items():
            if node not in self.visited and dist <= min_dist:
                min_dist = dist
                min_node = node

        return min_node, min_dist
测试样例

假设有如下的无向图:

Graph

我们想求从节点 A 到 E 的最短路径。

graph = {
    'A': {'B': 4, 'C': 3},
    'B': {'A': 4, 'C': 2, 'D': 5},
    'C': {'A': 3, 'B': 2, 'D': 1, 'E': 7},
    'D': {'B': 5, 'C': 1, 'E': 2},
    'E': {'C': 7, 'D': 2}
}

dijkstra = Dijkstra(graph, 'A')
distances = dijkstra.find_shortest_path()

我们可以得到从 A 到每个节点的最短距离如下:

{
    'A': 0, 
    'B': 4, 
    'C': 3, 
    'D': 4, 
    'E': 6
}
总结

Dijkstra 的最短路径算法是一种经典的贪心算法,用于求图中两个节点之间的最短路径。该算法以起点为基础,从起点开始往外扩散,直到扩散到终点为止。在扩散的过程中,每个节点都记录了到起点的最短距离。该算法的时间复杂度为 $O(|V|^2)$ 或 $O(|E|\log(|V|))$,其中 $|V|$ 表示节点数,$|E|$ 表示边数。