Python Heapq模块和字典之间存在奇怪的干扰

Python Heapq模块和字典之间存在奇怪的干扰,python,python-2.7,dictionary,heapq,Python,Python 2.7,Dictionary,Heapq,一方面,我有一个griddefaultdict,它存储网格上每个节点的相邻节点及其权重(在下面的示例中都是1) 另一方面,我有一个Djisktra函数,用于计算网格上两个节点之间的最短路径。该算法使用了heapq模块,运行非常良好 import heapq def Dijkstra(s, e, grid): #startpoint, endpoint, grid visited = set() distances = {s: 0} p = {} queue

一方面,我有一个
grid
defaultdict,它存储网格上每个节点的相邻节点及其权重(在下面的示例中都是1)

另一方面,我有一个
Djisktra
函数,用于计算网格上两个节点之间的最短路径。该算法使用了
heapq
模块,运行非常良好

import heapq

def Dijkstra(s, e, grid): #startpoint, endpoint, grid
    visited = set()
    distances = {s: 0} 
    p = {} 
    queue = [(0, s)] 

    while queue != []:

        weight, node = heappop(queue) 
        if node in visited: 
            continue

        visited.add(node) 

        for n_weight, n_node in grid[node]: 
            if n_node in visited: 
                continue

            total = weight + n_weight 

            if n_node not in distances or distances[n_node] > total: 

                distances[n_node] = total
                heappush(queue, (total, n_node))
                p[n_node] = node
问题:多次调用Djikstra函数时,
heappush
是。。。在
网格
字典中无缘无故添加新键

这是一个MCVE:

from collections import defaultdict

# Creating the dictionnary
grid = defaultdict(list) 
N = 4
kernel = (-N-1, -N, -N+1, -1, 1, N-1, N, N+1)

for i in range(N*N): 
    for n in kernel:
        if i > N and i < (N*N) - 1 - N and (i%N) > 0 and (i%N) < N - 1:
            grid[i].append((1, i+n))



# Calling Djikstra multiple times
keys = [*range(N*N)]

while keys:

    k1, k2 = random.sample(keys, 2)

    Dijkstra(k1, k2, grid) 

    keys.remove(k1)
    keys.remove(k2)
…在多次调用
Djikstra
函数后:

dict_keys([5, 6, 9, 10, 4, 0, 1, 2, 8, 3, 7, 11, 12, 13, 14, 15])
多次调用
Djikstra
函数而不调用
heappush
(仅在末尾注释heappush):

问题

  • 我怎样才能避免这种奇怪的行为

请注意,我使用的是Python 2.7,不能使用numpy。

我可以复制并修复。问题在于构建
网格的方式:在示例中,它包含的值不在-4到0和16到20之间的键中。所以你把那些不远处的节点推到头部,然后弹出它们

最后,对n_权重执行
,网格中的n_节点[node]:
其中
节点
网格
中不存在。由于
grid
是一个默认dict,因此会自动插入一个新节点,并将空列表作为值

修复是微不足道的(至少对于示例数据而言):它足以确保作为值添加的所有节点都以具有模的键的形式存在:

for i in range(N*N): 
    for n in kernel:
        grid[i].append((1, (i+n + N + 1)%(N*N)))
但即使对于真实数据,也不难确保网格值中存在的所有节点也存在于键中


顺便说一句,如果
grid
是一个简单的
dict
,那么在
grid[node]

@solub上的
KeyError
会立即出现错误:
heapq
defaultdict
之间没有交互,唯一的问题是您将一个意外的网格传递给了
Dijkstra
函数。无论如何,谢谢你的投票:-)
dict_keys([5, 6, 9, 10, 4, 0, 1, 2, 8, 3, 7, 11, 12, 13, 14, 15])
dict_keys([5, 6, 9, 10])
for i in range(N*N): 
    for n in kernel:
        grid[i].append((1, (i+n + N + 1)%(N*N)))