Dijkstra在python中的算法

时间:2014-04-06 17:09:55

标签: python algorithm dijkstra

我正在尝试使用数组在python中实现Dijkstra的算法。这是我的实施。

def extract(Q, w):
        m=0
        minimum=w[0]
        for i in range(len(w)):
                if w[i]<minimum:
                        minimum=w[i]
                        m=i
        return m, Q[m]
def dijkstra(G, s, t='B'):
   Q=[s]
   p={s:None}
   w=[0]
   d={}
        for i in G:
                d[i]=float('inf')
                Q.append(i)
                w.append(d[i])
        d[s]=0
        S=[]
        n=len(Q)
        while Q:
                u=extract(Q,w)[1]
                S.append(u)
                #w.remove(extract(Q, d, w)[0])
                Q.remove(u)
                for v in G[u]:
                        if d[v]>=d[u]+G[u][v]:
                                d[v]=d[u]+G[u][v]
                                p[v]=u
        return d, p
B='B'
A='A'
D='D'
G='G'
E='E'
C='C'
F='F'
G={B:{A:5, D:1, G:2}, A:{B:5, D:3, E:12, F:5}, D:{B:1, G:1, E:1, A:3}, G:{B:2, D:1, C:2}, C:{G:2, E:1, F:16}, E:{A:12, D:1, C:1, F:2}, F:{A:5, E:2, C:16}}
print "Assuming the start vertex to be B:"
print "Shortest distances", dijkstra(G, B)[0]
print "Parents", dijkstra(G, B)[1]

我希望答案是:

Assuming the start vertex to be B:
Shortest distances {'A': 4, 'C': 4, 'B': 0, 'E': 2, 'D': 1, 'G': 2, 'F': 4}
Parents {'A': 'D', 'C': 'G', 'B': None, 'E': 'D', 'D': 'B', 'G': 'D', 'F': 'E'}

然而,我得到的答案是:

Assuming the start vertex to be B:
Shortest distances {'A': 4, 'C': 4, 'B': 0, 'E': 2, 'D': 1, 'G': 2, 'F': 10}
Parents {'A': 'D', 'C': 'G', 'B': None, 'E': 'D', 'D': 'B', 'G': 'D', 'F': 'A'}.

对于节点F,程序给出了错误的答案。有人可以告诉我为什么吗?

11 个答案:

答案 0 :(得分:25)

正如其他人所指出的,由于没有使用可理解的变量名,几乎不可能调试你的代码。

根据关于Dijkstra算法的wiki文章,可以按照这些方式(以及其他一百万种方式)实现它:

nodes = ('A', 'B', 'C', 'D', 'E', 'F', 'G')
distances = {
    'B': {'A': 5, 'D': 1, 'G': 2},
    'A': {'B': 5, 'D': 3, 'E': 12, 'F' :5},
    'D': {'B': 1, 'G': 1, 'E': 1, 'A': 3},
    'G': {'B': 2, 'D': 1, 'C': 2},
    'C': {'G': 2, 'E': 1, 'F': 16},
    'E': {'A': 12, 'D': 1, 'C': 1, 'F': 2},
    'F': {'A': 5, 'E': 2, 'C': 16}}

unvisited = {node: None for node in nodes} #using None as +inf
visited = {}
current = 'B'
currentDistance = 0
unvisited[current] = currentDistance

while True:
    for neighbour, distance in distances[current].items():
        if neighbour not in unvisited: continue
        newDistance = currentDistance + distance
        if unvisited[neighbour] is None or unvisited[neighbour] > newDistance:
            unvisited[neighbour] = newDistance
    visited[current] = currentDistance
    del unvisited[current]
    if not unvisited: break
    candidates = [node for node in unvisited.items() if node[1]]
    current, currentDistance = sorted(candidates, key = lambda x: x[1])[0]

print(visited)

这段代码比必要的更加冗长,我希望将您的代码与我的代码进行比较,您可能会发现一些差异。

结果是:

{'E': 2, 'D': 1, 'G': 2, 'F': 4, 'A': 4, 'C': 3, 'B': 0}

答案 1 :(得分:9)

我用更详细的形式写了它,以使新手读者更清楚:

from collections import defaultdict


def get_shortest_path(weighted_graph, start, end):
    """
    Calculate the shortest path for a directed weighted graph.

    Node can be virtually any hashable datatype.

    :param start: starting node
    :param end: ending node
    :param weighted_graph: {"node1": {"node2": "weight", ...}, ...}
    :return: ["START", ... nodes between ..., "END"] or None, if there is no
            path
    """

    # We always need to visit the start
    nodes_to_visit = {start}
    visited_nodes = set()
    distance_from_start = defaultdict(lambda: float("inf"))
    # Distance from start to start is 0
    distance_from_start[start] = 0
    tentative_parents = {}

    while nodes_to_visit:
        # The next node should be the one with the smallest weight
        current = min(
            [(distance_from_start[node], node) for node in nodes_to_visit]
        )[1]

        # The end was reached
        if current == end:
            break

        nodes_to_visit.discard(current)
        visited_nodes.add(current)

        for neighbour, distance in weighted_graph[current]:
            if neighbour in visited_nodes:
                continue
            neighbour_distance = distance_from_start[current] + distance
            if neighbour_distance < distance_from_start[neighbour]:
                distance_from_start[neighbour] = neighbour_distance
                tentative_parents[neighbour] = current
                nodes_to_visit.add(neighbour)

    return _deconstruct_path(tentative_parents, end)


def _deconstruct_path(tentative_parents, end):
    if end not in tentative_parents:
        return None
    cursor = end
    path = []
    while cursor:
        path.append(cursor)
        cursor = tentative_parents.get(cursor)
    return list(reversed(path))

答案 2 :(得分:8)

这不是我的答案 - 我的教授比我的尝试更有效率。这是他的方法,显然使用辅助函数来完成重复任务

def dijkstra(graph, source):

    vertices, edges = graph
    dist = dict()
    previous = dict()

    for vertex in vertices:
        dist[vertex] = float("inf")
        previous[vertex] = None

    dist[source] = 0
    Q = set(vertices)

    while len(Q) > 0:
        u = minimum_distance(dist, Q)
        print('Currently considering', u, 'with a distance of', dist[u])
        Q.remove(u)

        if dist[u] == float('inf'):
            break

        n = get_neighbours(graph, u)
        for vertex in n:
            alt = dist[u] + dist_between(graph, u, vertex)
            if alt < dist[vertex]:
                dist[vertex] = alt
                previous[vertex] = u

    return previous

给出图表

  

({&#39; A&#39;,&#39; B&#39;,&#39; C&#39;,&#39; D&#39;},{(&#39; A&# 39;,&#39; B&#39;,5),(&#39; B&#39;,&#39; A&#39;,5),(&#39; B&#39;,&#39; ; C&#39;,10),(&#39; B&#39;,&#39; D&#39;,6),(&#39; C&#39;,&#39; D&#39;, 2),(&#39; D&#39;,&#39; C&#39;,2)})

命令print(dijkstra(graph, 'A')产生

  

目前考虑A距离为0

     

目前考虑距离为5的B

     

目前正在考虑距离为11的D

     

目前考虑C距离为13

id est:

  

{&#39; C&#39;:&#39; D&#39;,&#39; D&#39;:&#39; B&#39;,&#39; A&#39;:无,&#39; B&#39;:&#39; A&#39;} =&gt;按随机顺序

答案 3 :(得分:0)

在extract中设置断点。您将看到从Q中删除条目但从w中删除。其他一切都是字典,但Q / W是一个配对阵列,你不能及时更新。你必须保持这两个同步,或用dict替换它们。特别说明:最后,在算法运行后,您可能希望将Q / w替换为边缘列表,并使用优先级队列(heapq模块)重新编码“extract”函数。

此外,您将看到w的源的权重始终为0,所有其他节点的权重为“inf”。您完全跳过了更新候选距离的关键步骤。

所以你基本上总是采取你遇到的第一条路径,而不是选择最短的路径。您稍后计算该路径的实际距离,因此返回的距离数组具有实际值,但它们是任意选择的,您没有理由期望它们是最短的。

在您(错误地)找到下一个节点后,您会查看其所有边缘。这应该是我在第二段中提到的关键步骤,您可以在其中更新下一个节点的候选项。相反,你做了一些完全不同的事情:你似乎正在循环所有以前的解决方案(保证正确,如果你正确实现dijkstra,应该保持独立),你从源 - &gt;当前寻找两步解决方案 - &GT;任何。查看这些的正确意图是将前一个路径中的下一个候选添加到下一个节点,但因为它们永远不会被添加,所以你不看(前一个最短路径)+(一步),你只看实际上是两个节点的解决方案。

所以基本上,你是从源代码循环遍历所有可能的双节点路径,以便找到最短路径。这是一个完整的错误,与dijkstra无关。但它几乎适用于你的微小图形,其中大多数正确的最短路径是两步路径。

(ps:我同意每个人关于你的变量名。如果你使用详细的名称来告诉那些变量代表什么,你会做得更好。在我分析你的代码之前我必须重命名它们。)

答案 4 :(得分:0)

import sys
import heapq

class Node:

     def __init__(self, name):
        self.name = name
        self.visited = False
        self.adjacenciesList = []
        self.predecessor = None
        self.mindistance = sys.maxsize    

    def __lt__(self, other):
        return self.mindistance < other.mindistance

class Edge:

    def __init__(self, weight, startvertex, endvertex):
        self.weight = weight
        self.startvertex = startvertex
        self.endvertex = endvertex

def calculateshortestpath(vertexlist, startvertex):
    q = []
    startvertex.mindistance = 0
    heapq.heappush(q, startvertex)

    while q:
        actualnode = heapq.heappop(q)
        for edge in actualnode.adjacenciesList:
            tempdist = edge.startvertex.mindistance + edge.weight
            if tempdist < edge.endvertex.mindistance:
                edge.endvertex.mindistance = tempdist
                edge.endvertex.predecessor = edge.startvertex
                heapq.heappush(q,edge.endvertex)
def getshortestpath(targetvertex):
    print("The value of it's minimum distance is: ",targetvertex.mindistance)
    node = targetvertex
    while node:
        print(node.name)
        node = node.predecessor

node1 = Node("A");
node2 = Node("B");
node3 = Node("C");
node4 = Node("D");
node5 = Node("E");
node6 = Node("F");
node7 = Node("G");
node8 = Node("H");

edge1 = Edge(5,node1,node2);
edge2 = Edge(8,node1,node8);
edge3 = Edge(9,node1,node5);
edge4 = Edge(15,node2,node4);
edge5 = Edge(12,node2,node3);
edge6 = Edge(4,node2,node8);
edge7 = Edge(7,node8,node3);
edge8 = Edge(6,node8,node6);
edge9 = Edge(5,node5,node8);
edge10 = Edge(4,node5,node6);
edge11 = Edge(20,node5,node7);
edge12 = Edge(1,node6,node3);
edge13 = Edge(13,node6,node7);
edge14 = Edge(3,node3,node4);
edge15 = Edge(11,node3,node7);
edge16 = Edge(9,node4,node7);

node1.adjacenciesList.append(edge1);
node1.adjacenciesList.append(edge2);
node1.adjacenciesList.append(edge3);
node2.adjacenciesList.append(edge4);
node2.adjacenciesList.append(edge5);
node2.adjacenciesList.append(edge6);
node8.adjacenciesList.append(edge7);
node8.adjacenciesList.append(edge8);
node5.adjacenciesList.append(edge9);
node5.adjacenciesList.append(edge10);
node5.adjacenciesList.append(edge11);
node6.adjacenciesList.append(edge12);
node6.adjacenciesList.append(edge13);
node3.adjacenciesList.append(edge14);
node3.adjacenciesList.append(edge15);
node4.adjacenciesList.append(edge16);

vertexlist = (node1,node2,node3,node4,node5,node6,node7,node8)

calculateshortestpath(vertexlist,node1)
getshortestpath(node7)

答案 5 :(得分:0)

此实现仅使用数组和堆ds。

import heapq as hq
import math

def dijkstra(G, s):
    n = len(G)
    visited = [False]*n
    weights = [math.inf]*n
    path = [None]*n
    queue = []
    weights[s] = 0
    hq.heappush(queue, (0, s))
    while len(queue) > 0:
        g, u = hq.heappop(queue)
        visited[u] = True
        for v, w in G[u]:
            if not visited[v]:
                f = g + w
                if f < weights[v]:
                    weights[v] = f
                    path[v] = u
                    hq.heappush(queue, (f, v))
    return path, weights

G = [[(1, 6), (3, 7)],
     [(2, 5), (3, 8), (4, -4)],
     [(1, -2), (4, 7)],
     [(2, -3), (4, 9)],
     [(0, 2)]]

print(dijkstra(G, 0))

我希望这可以对某人有所帮助,这有点迟了。

答案 6 :(得分:0)

我在我的博客rebrained.com上将维基百科描述分解为以下伪代码:

初始状态:

  1. 赋予节点两个属性-node.visited和node.distance
  2. 除了将起始节点设置为零之外,所有节点均设置node.distance = infinity
  3. 为所有节点设置node.visited = false
  4. 设置当前节点=起始节点。

当前节点循环:

  1. 如果当前节点=结束节点,则完成并返回current.distance&path
  2. 对于所有未访问的邻居,计算其暂定距离(current.distance +到邻居的边缘)。
  3. 如果暂定距离<邻居的设定距离,则将其覆盖。
  4. 设置current.isvisited = true。
  5. set current =最小的node.distance剩余未访问的节点

http://rebrained.com/?p=392

import sys
def shortestpath(graph,start,end,visited=[],distances={},predecessors={}):
    """Find the shortest path btw start & end nodes in a graph"""
    # detect if first time through, set current distance to zero
    if not visited: distances[start]=0
    # if we've found our end node, find the path to it, and return
    if start==end:
        path=[]
        while end != None:
            path.append(end)
            end=predecessors.get(end,None)
        return distances[start], path[::-1]
    # process neighbors as per algorithm, keep track of predecessors
    for neighbor in graph[start]:
        if neighbor not in visited:
            neighbordist = distances.get(neighbor,sys.maxint)
            tentativedist = distances[start] + graph[start][neighbor]
            if tentativedist < neighbordist:
                distances[neighbor] = tentativedist
                predecessors[neighbor]=start
    # neighbors processed, now mark the current node as visited 
    visited.append(start)
    # finds the closest unvisited node to the start 
    unvisiteds = dict((k, distances.get(k,sys.maxint)) for k in graph if k not in visited)
    closestnode = min(unvisiteds, key=unvisiteds.get)
    # now take the closest node and recurse, making it current 
    return shortestpath(graph,closestnode,end,visited,distances,predecessors)
if __name__ == "__main__":
    graph = {'a': {'w': 14, 'x': 7, 'y': 9},
            'b': {'w': 9, 'z': 6},
            'w': {'a': 14, 'b': 9, 'y': 2},
            'x': {'a': 7, 'y': 10, 'z': 15},
            'y': {'a': 9, 'w': 2, 'x': 10, 'z': 11},
            'z': {'b': 6, 'x': 15, 'y': 11}}
    print shortestpath(graph,'a','a')
    print shortestpath(graph,'a','b')
    """
    Expected Result:
        (0, ['a']) 
        (20, ['a', 'y', 'w', 'b'])
        """

答案 7 :(得分:0)

这是我使用min-priority-queue的Dijkstra算法的实现。希望你能。

from collections import defaultdict
from math import floor


class MinPQ:
    """
    each heap element is in form (key value, object handle), while heap
    operations works based on comparing key value and object handle points to
    the corresponding application object.
    """

    def __init__(self, array=[]):
        self._minheap = list(array)
        self._length = len(array)
        self._heapsize = 0
        self._build_min_heap()

    def _left(self, idx):
        return 2*idx+1

    def _right(self, idx):
        return 2*idx+2

    def _parent(self, idx):
        return floor((idx-1)/2)

    def _min_heapify(self, idx):
        left = self._left(idx)
        right = self._right(idx)
        min_idx = idx
        if left <= self._heapsize-1 and self._minheap[left] < self._minheap[min_idx]:
            min_idx = left
        if right <= self._heapsize-1 and self._minheap[right] < self._minheap[min_idx]:
            min_idx = right
        if min_idx != idx:
            self._minheap[idx], self._minheap[min_idx] = self._minheap[min_idx], self._minheap[idx]
            self._min_heapify(min_idx)

    def _build_min_heap(self):
        self._heapsize = self._length
        mid_id = int(self._heapsize-1)-1
        for i in range(mid_id, -1, -1):
            self._min_heapify(i)

    def decrease_key(self, idx, new_key):
        while idx > 0 and new_key < self._minheap[self._parent(idx)]:
            self._minheap[idx] = self._minheap[self._parent(idx)]
            idx = self._parent(idx)
        self._minheap[idx] = new_key

    def extract_min(self):
        minimum = self._minheap[0]
        self._minheap[0] = self._minheap[self._heapsize-1]
        self._heapsize = self._heapsize - 1
        self._min_heapify(0)
        return minimum

    def insert(self, item):
        self._minheap.append(item)
        self._heapsize = self._heapsize + 1
        self.decrease_key(self._heapsize-1, item)

    @property
    def minimum(self):
        return self._minheap[0]

    def is_empty(self):
        return self._heapsize == 0

    def __str__(self):
        return str(self._minheap)

    __repr__ = __str__

    def __len__(self):
        return self._heapsize


class DiGraph:
    def __init__(self, edges=None):
        self.adj_list = defaultdict(list)
        self.add_weighted_edges(edges)

    @property
    def nodes(self):
        nodes = set()
        nodes.update(self.adj_list.keys())
        for node in self.adj_list.keys():
            for neighbor, weight in self.adj_list[node]:
                nodes.add(neighbor)
        return list(nodes)

    def add_weighted_edges(self, edges):
        if edges is None:
            return None
        for edge in edges:
            self.add_weighted_edge(edge)

    def add_weighted_edge(self, edge):
        node1, node2, weight = edge
        self.adj_list[node1].append((node2, weight))

    def weight(self, tail, head):
        for node, weight in self.adj_list[tail]:
            if node == head:
                return weight
        return None


def relax(min_heapq, dist, graph, u, v):
    if dist[v] > dist[u] + graph.weight(u, v):
        dist[v] = dist[u] + graph.weight(u, v)
        min_heapq.insert((dist[v], v))


def dijkstra(graph, start):
    # initialize
    dist = dict.fromkeys(graph.nodes, float('inf'))
    dist[start] = 0
    min_heapq = MinPQ()
    min_heapq.insert((0, start))

    while not min_heapq.is_empty():
        distance, u = min_heapq.extract_min()
        # we may add a node multiple time in priority queue, but we process it
        # only once
        if distance > dist[u]:
            continue
        for neighbor, weight in graph.adj_list[u]:
            relax(min_heapq, dist, graph, u, neighbor)

    return dist

if __name__ == "__main__":
    edges = [('s', 't', 10), ('t', 'x', 1), ('s', 'y', 5), ('y', 't', 3), ('t', 'y', 2), 
             ('y', 'x', 9), ('y', 'z', 2), ('z', 's', 7), ('x', 'z', 4), ('z', 'x', 6)]
    digraph = DiGraph(edges)
    res = dijkstra(digraph, 's')
    print(res)

答案 8 :(得分:0)

我使用优先级队列实现Dijkstra。除此之外,我还自己实现了最小堆操作。希望对您有帮助。

from collections import defaultdict


class MinPQ:
    """
    each heap element is in form (key value, object handle), while heap
    operations works based on comparing key value and object handle points to
    the corresponding application object.
    """

    def __init__(self, array=[]):
        self._minheap = list(array)
        self._length = len(array)
        self._heapsize = 0
        self._build_min_heap()

    def _left(self, idx):
        return 2*idx+1

    def _right(self, idx):
        return 2*idx+2

    def _parent(self, idx):
        return int((idx-1)/2)

    def _min_heapify(self, idx):
        left = self._left(idx)
        right = self._right(idx)
        min_idx = idx
        if left <= self._heapsize-1 and self._minheap[left] < self._minheap[min_idx]:
            min_idx = left
        if right <= self._heapsize-1 and self._minheap[right] < self._minheap[min_idx]:
            min_idx = right
        if min_idx != idx:
            self._minheap[idx], self._minheap[min_idx] = self._minheap[min_idx], self._minheap[idx]
            self._min_heapify(min_idx)

    def _build_min_heap(self):
        self._heapsize = self._length
        mid_id = int((self._heapsize)/2)-1
        for i in range(mid_id, -1, -1):
            self._min_heapify(i)

    def decrease_key(self, idx, new_key):
        while idx > 0 and new_key < self._minheap[self._parent(idx)]:
            self._minheap[idx] = self._minheap[self._parent(idx)]
            idx = self._parent(idx)
        self._minheap[idx] = new_key

    def extract_min(self):
        if self._heapsize < 1:
            raise IndexError
        minimum = self._minheap[0]
        self._minheap[0] = self._minheap[self._heapsize-1]
        self._heapsize = self._heapsize - 1
        self._min_heapify(0)
        return minimum

    def insert(self, item):
        self._minheap.append(item)
        self._heapsize = self._heapsize + 1
        self.decrease_key(self._heapsize-1, item)

    @property
    def minimum(self):
        return self._minheap[0]

    def is_empty(self):
        return self._heapsize == 0

    def __str__(self):
        return str(self._minheap)

    __repr__ = __str__

    def __len__(self):
        return self._heapsize


class DiGraph:
    def __init__(self, edges=None):
        self.adj_list = defaultdict(list)
        self.add_weighted_edges(edges)

    @property
    def nodes(self):
        nodes = set()
        nodes.update(self.adj_list.keys())
        for node in self.adj_list.keys():
            for neighbor, weight in self.adj_list[node]:
                nodes.add(neighbor)
        return list(nodes)

    def add_weighted_edges(self, edges):
        if edges is None:
            return None
        for edge in edges:
            self.add_weighted_edge(edge)

    def add_weighted_edge(self, edge):
        node1, node2, weight = edge
        self.adj_list[node1].append((node2, weight))

    def weight(self, tail, head):
        for node, weight in self.adj_list[tail]:
            if node == head:
                return weight
        return None


def relax(min_heapq, dist, graph, u, v):
    if dist[v] > dist[u] + graph.weight(u, v):
        dist[v] = dist[u] + graph.weight(u, v)
        min_heapq.insert((dist[v], v))


def dijkstra(graph, start):
    # initialize
    dist = dict.fromkeys(graph.nodes, float('inf'))
    dist[start] = 0
    min_heapq = MinPQ()
    min_heapq.insert((0, start))

    while not min_heapq.is_empty():
        distance, u = min_heapq.extract_min()
        # we may add a node multiple time in priority queue, but we process it
        # only once
        if distance > dist[u]:
            continue
        for neighbor, weight in graph.adj_list[u]:
            relax(min_heapq, dist, graph, u, neighbor)

    return dist

答案 9 :(得分:0)

基于CLRS第二版的实施。第24.3章

d 是增量, p 是前辈

import heapq

def dijkstra(g, s, t):

    q = []
    d = {k: sys.maxint for k in g.keys()}
    p = {}

    d[s] = 0 
    heapq.heappush(q, (0, s))

    while q:
        last_w, curr_v = heapq.heappop(q)
        for n, n_w in g[curr_v]:
            cand_w = last_w + n_w # equivalent to d[curr_v] + n_w 
            # print d # uncomment to see how deltas are updated
            if cand_w < d[n]:
                d[n] = cand_w
                p[n] = curr_v
                heapq.heappush(q, (cand_w, n))

    print "predecessors: ", p 
    print "delta: ", d 
    return d[t]

def test():

    og = {}
    og["s"] = [("t", 10), ("y", 5)]
    og["t"] = [("y", 2), ("x", 1)]
    og["y"] = [("t", 3), ("x", 9), ("z", 2)]
    og["z"] = [("x", 6), ("s", 7)]
    og["x"] = [("z", 4)]

    assert dijkstra(og, "s", "x") == 9 


if __name__ == "__main__":
    test()

实施假定所有节点都表示为键。如果在 og 中未将说节点(例如,上例中的“ x”)定义为键,则增量 d 会丢失该键并检查 cand_w 无法正常工作。

答案 10 :(得分:0)

我需要一个能够返回路径的解决方案,因此我使用有关Dijkstra的多个问题/答案的想法来组成一个简单的类:

class Dijkstra:

    def __init__(self, vertices, graph):
        self.vertices = vertices  # ("A", "B", "C" ...)
        self.graph = graph  # {"A": {"B": 1}, "B": {"A": 3, "C": 5} ...}

    def find_route(self, start, end):
        unvisited = {n: float("inf") for n in self.vertices}
        unvisited[start] = 0  # set start vertex to 0
        visited = {}  # list of all visited nodes
        parents = {}  # predecessors
        while unvisited:
            min_vertex = min(unvisited, key=unvisited.get)  # get smallest distance
            for neighbour, _ in self.graph.get(min_vertex, {}).items():
                if neighbour in visited:
                    continue
                new_distance = unvisited[min_vertex] + self.graph[min_vertex].get(neighbour, float("inf"))
                if new_distance < unvisited[neighbour]:
                    unvisited[neighbour] = new_distance
                    parents[neighbour] = min_vertex
            visited[min_vertex] = unvisited[min_vertex]
            unvisited.pop(min_vertex)
            if min_vertex == end:
                break
        return parents, visited

    @staticmethod
    def generate_path(parents, start, end):
        path = [end]
        while True:
            key = parents[path[0]]
            path.insert(0, key)
            if key == start:
                break
        return path

图形和用法示例(使用此漂亮的tool生成绘图): enter image description here

input_vertices = ("A", "B", "C", "D", "E", "F", "G")
input_graph = {
    "A": {"B": 5, "D": 3, "E": 12, "F": 5},
    "B": {"A": 5, "D": 1, "G": 2},
    "C": {"E": 1, "F": 16, "G": 2},
    "D": {"A": 3, "B": 1, "E": 1, "G": 1},
    "E": {"A": 12, "C": 1, "D": 1, "F": 2},
    "F": {"A": 5, "C": 16, "E": 2},
    "G": {"B": 2, "C": 2, "D": 1}
}
start_vertex = "B"
end_vertex= "C"
dijkstra = Dijkstra(input_vertices, input_graph)
p, v = dijkstra.find_route(start_vertex, end_vertex)
print("Distance from %s to %s is: %.2f" % (start_vertex, end_vertex, v[end_vertex]))
se = dijkstra.generate_path(p, start_vertex, end_vertex)
print("Path from %s to %s is: %s" % (start_vertex, end_vertex, " -> ".join(se)))

输出

Distance from B to C is: 3.00
Path from B to C is: B -> D -> E -> C