Python 删除节点时执行Dijkstra算法时出错

Python 删除节点时执行Dijkstra算法时出错,python,graph,tree,shortest-path,dijkstra,Python,Graph,Tree,Shortest Path,Dijkstra,我试图实现Dijkstra算法,如下所示: from collections import defaultdict class Graph: def __init__(self): self.nodes = set() self.edges = defaultdict(list) self.distances = {} def add_node(self, value): self.nodes.add(value)

我试图实现Dijkstra算法,如下所示:

from collections import defaultdict
class Graph:
    def __init__(self):
        self.nodes = set()
        self.edges = defaultdict(list)
        self.distances = {}

    def add_node(self, value):
        self.nodes.add(value)

    def add_edge(self, from_node, to_node, distance):
        self.edges[from_node].append(to_node)
        self.edges[to_node].append(from_node)
        self.distances[(from_node, to_node)] = distance


def dijsktra(graph, initial):
    visited = {initial: 0}
    path = {}

    nodes = set(graph.nodes)

    while nodes: 
        min_node = None
        for node in nodes:
            if node in visited:
                if min_node is None:
                    min_node = node
                elif visited[node] < visited[min_node]:
                    min_node = node

        if min_node is None:
            break

        
        nodes.remove(min_node)
        current_weight = visited[min_node]

        for edge in graph.edges[min_node]:
    
            weight = current_weight + graph.distances[(min_node, edge)]
            if edge not in visited or weight < visited[edge]:
                visited[edge] = weight
                path[edge] = min_node


    return visited, path
print(g.nodes)
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 
 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}

print(g.distances)
{(1, 7): 2, (1, 2): 2, (2, 1): 1, (2, 3): 4, (3, 2): 2, (3, 9): 2, (5, 11): 1, (5, 6): 1, 
 (6, 5): 3, (6, 12): 2, (7, 1): 1, (7, 13): 3, (9, 3): 4, (9, 15): 1, (11, 5): 3, (11, 17): 
 3, (11, 12): 2, (12, 6): 1, (12, 11): 1, (12, 18): 2, (13, 7): 2, (13, 14): 2, (14, 13): 3, 
 (14, 20): 1, (14, 15): 1, (15, 9): 2, (15, 14): 2, (15, 21): 2, (15, 16): 4, (16, 15): 1, 
 (16, 22): 1, (16, 17): 3, (17, 11): 1, (17, 16): 4, (17, 18): 2, (18, 12): 2, (18, 17): 3, 
 (18, 24): 1, (20, 14): 2, (20, 26): 1, (20, 21): 2, (21, 15): 1, (21, 20): 1, (21, 27): 1, 
 (21, 22): 1, (22, 16): 4, (22, 21): 2, (24, 18): 2, (24, 30): 1, (25, 31): 1, (25, 26): 1, 
 (26, 20): 1, (26, 25): 2, (26, 27): 1, (27, 21): 2, (27, 26): 1, (27, 33): 4, (30, 24): 1, 
 (30, 36): 1, (31, 25): 2, (33, 27): 1, (33, 34): 2, (34, 33): 4, (34, 35): 2, (35, 34): 2, 
 (35, 36): 1, (36, 30): 1, (36, 35): 2}
但我在执行时遇到了一个错误。似乎是由于删除了
None
。我已尝试通过
inf
更改
None
。仍然得到相同的错误。我现在该怎么办?
以下是函数执行和错误:

visited,path = dijsktra(g,0)

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-44-c4a3ba9a32e3> in <module>
----> 1 parent,path=dijsktra(g,0)

<ipython-input-25-cd9030508fd7> in dijsktra(graph, initial)
     34 
     35 
---> 36         nodes.remove(min_node)
     37         current_weight = visited[min_node]
     38 

KeyError: None
访问,路径=dijsktra(g,0)
---------------------------------------------------------------------------
KeyError回溯(最近一次呼叫最后一次)
在里面
---->1父级,路径=dijsktra(g,0)
在dijsktra中(图形,首字母)
34
35
--->36个节点。移除(最小节点)
37当前权重=访问量[最小节点]
38
KeyError:无
如何删除该错误?请任何人解决这个问题。这会很有帮助。
谢谢大家!

编辑:
下面是我用来生成
g.nodes
g.distance
的代码的示例,我认为您的
dijskstra
函数没有正确实现算法。通常初始化
dist
(距离)字典,其中键是图形的节点值,其值初始化为无穷大(或合适的大值),但初始化为0的初始节点除外。此字典表示每个节点与初始节点的初始距离。然后,每个循环迭代都会查找一个未访问的节点(所有节点最初都是该节点),以查找距离初始节点最小的节点)。第一次通过循环时,这将是初始节点本身。然后从未访问的节点中删除该节点,并更新从该节点到与该节点相邻的所有节点的距离。最后,所有节点都从未访问的节点列表中删除,我们就完成了。我已经修改了函数返回的内容。由于不再存在已访问字典的概念,因此它返回
dist
字典,给出到每个节点的距离:

从集合导入defaultdict
类图:
定义初始化(自):
self.nodes=set()
self.edges=defaultdict(列表)
self.distance={}
def add_节点(自身,值):
self.nodes.add(值)
def添加_边(自身、从_节点、到_节点、距离):
self.edges[来自\u节点].追加(到\u节点)
self.edges[到\节点].append(从\节点)
自身距离[(从节点到节点)]=距离
自身距离[(到_节点,从_节点)]=距离
def dijsktra(图表,首字母):#应该是dijkstra
节点=集合(graph.nodes)#未列出的节点
路径={}
dist={node:9999999999用于nodes}中的节点#假设这大于任何实际距离
距离[初始值]=0
while nodes:#我们仍然有未列出的节点
最小节点=无
对于节点中的节点:
如果最小节点为无:
最小节点=节点
elif dist[节点]
印刷品:

({1: 0, 2: 1, 3: 2, 4: 3}, {2: 1, 3: 1, 4: 3})
更新

我想我会添加一个更有效的修改版本。我们不是让所有节点最初都在要处理的节点的“未访问列表”中,而是维护一个节点列表,该列表中的节点与初始节点的最终距离已计算,但其相邻节点尚未处理。从该列表中,我们始终希望选择与初始节点的距离具有最小值的节点。为了实现这一点,每个节点现在都是一个元组,由其与初始节点的距离及其节点值组成。这些节点在自动生成具有最小值的节点的中进行维护:

从集合导入defaultdict
从heapq导入heappop、heappush
类图:
定义初始化(自):
self.nodes=set()
self.edges=defaultdict(列表)
self.distance={}
def add_节点(自身,值):
self.nodes.add(值)
def添加_边(自身、从_节点、到_节点、距离):
self.edges[来自\u节点].追加(到\u节点)
self.edges[到\节点].append(从\节点)
自身距离[(从节点到节点)]=距离
自身距离[(到_节点,从_节点)]=距离
def dijkstra(图表,首字母):#应该是dijkstra
访问=设置()
路径={}
优先级_队列=[]
无穷大=浮点('inf')
距离={node:graph.nodes}
距离[初始值]=0
heappush(优先级队列,(0,初始值))#(成本,初始值)
当优先权在队列中时:
_,min_node=heappop(优先级队列)
已访问。添加(最小节点)
当前重量=距离[最小节点]
对于图中的边。边[min_node]:#这实际上是一个节点,而不是边
如果访问了edge in:
持续
权重=当前权重+图形距离[(最小节点,边)]
如果重量<距离[边缘]:
距离[边缘]=重量
路径[边]=最小节点
heappush(优先级队列(权重、边))
返回距离、路径
g=图()
g、 添加_节点(1)
g、 添加_节点(2)
g、 添加_节点(3)
g、 添加_节点(4)
g、 添加_边(1、2、1)
g、 添加_边(1、3、2)
g、 添加_边(2、4、5)
g、 添加_边(3、4、1)
印刷品(dijkstra(g,1))

您确定复制的代码正确吗?由于前面的
break
语句,如果它实际上处于所显示的嵌套级别,
minu code
似乎不可能为None。而且,我看不出你会如何摆脱这种困境