我想使用堆来实现Djikstra算法,以解决挑战问题in this file at this page's module->用于编程项目的测试用例和数据集->编程问题9.8和10.8:实现Dijkstra的算法
我已经使用堆和朴素的方法实现了Djikstra算法。天真的方法适用于挑战问题,但使用堆的方法却有不同且错误的结果。
我创建了一个函数testcase(),它返回具有挑战问题的节点,顶点和权重的networkx图。 我将此testcase()返回的图传递给下面的Djikstra算法实现。
使用天真的实现的Djikstra算法:
%matplotlib inline
import networkx as nx
import heapq
import numpy as np
def undirected_djikstra_naive(DG, source, destination):
X = [source]
A = {}
A[source] = 0
all_nodes = list(DG.nodes)
minimum_2nd_overall = float('inf')
w_overall = float('inf')
print("Naive:")
while len(X) != len(all_nodes):
for edge in list(DG.edges):
if (edge[0] in X) and (edge[1] not in X):
edge_tail = edge[0]
edge_head = edge[1]
elif (edge[1] in X) and (edge[0] not in X):
edge_tail = edge[1]
edge_head = edge[0]
if ((edge_tail in X) and (edge_head not in X)) :
dji_greedy = A[edge_tail] + DG.edges[edge_tail, edge_head]['weight'] #djikstra's greedy criterion
if edge_head not in A:
A[edge_head] = dji_greedy
elif dji_greedy < A[edge_head]:
A[edge_head] = dji_greedy
if dji_greedy < minimum_2nd_overall:
minimum_2nd_overall = dji_greedy
w_overall = edge_head
minimum_2nd_overall = float('inf')
X.append(w_overall)
#print("Printing minimum distances from starting vertex {}".format(source))
B = []
for node in A:
if node in destination:
#print("Vertex {} is at distance {}".format(node, A[node]))
B.append([node, A[node]])
B = sorted(B)
return B
使用堆实现的Djikstra算法:
%matplotlib inline
import networkx as nx
import heapq
import numpy as np
def undirected_djikstra_heap(DG, source, destination):
#Heap implementation which does the following
#
# 1. For vertices in X, find all edges originating from them to all vertices not in X
# 2. Keep track of minimum value of len(w) + lwv
# 3. Return w, v and lwv
X = [source]
minHeap = []
heapq.heappush(minHeap, [0, source])
all_nodes = list(DG.nodes)
for node in all_nodes:
DG.nodes[node]['shortest_dist'] = float('inf')
print("Heap:")
while len(minHeap) != 0:
w = heapq.heappop(minHeap)
#print(minHeap)
X.append(w[1])
DG.nodes[w[1]]['shortest_dist'] = w[0]
for edge in list(DG.edges):
if (edge[0] == w[1]) and (edge[1] not in X):
edge_tail = edge[0]
edge_head = edge[1]
elif (edge[1] == w[1]) and (edge[0] not in X):
edge_tail = edge[1]
edge_head = edge[0]
else:
continue
if ((edge_tail == w[1]) and (edge_head not in X)) : # node that has just been popped should be the tail
dji_greedy = w[0] + DG.edges[edge_tail, edge_head]['weight'] #djikstra's greedy criterion
if len(minHeap) == 0:
heapq.heappush(minHeap, [dji_greedy, edge_head])
continue
singlenp = [i[1] for i in minHeap]
if edge_head not in singlenp:
heapq.heappush(minHeap, [dji_greedy, edge_head])
else:
dest_idx = singlenp.index(edge_head)
if dji_greedy < minHeap[dest_idx][0]:
minHeap[dest_idx] = minHeap[0]
heapq.heappop(minHeap)
heapq.heappush(minHeap, [dji_greedy, edge_head])
#print("Printing minimum distances from starting vertex \'{}\'".format(source))
B = []
for node in all_nodes:
if node in destination:
#print("Vertex {} is at distance {}".format(node, DG.nodes[node]['shortest_dist']))
B.append([node, DG.nodes[node]['shortest_dist']])
B = sorted(B)
return B
调用和声明算法:
challenge_graph_g = testcase()
start_vert = 1
dest_verts = challenge_graph_g.nodes
heap_dji = undirected_djikstra_heap(challenge_graph_g, start_vert, dest_verts)
naive_dji = undirected_djikstra_naive(challenge_graph_g, start_vert , dest_verts)
for a in range(len(dest_verts)):
assert heap_dji[a][1] == naive_dji[a][1], "Dist Mismatch at Vertex {} dist heap {}, Vertex {} dist naive {}".format(heap_dji[a][0], heap_dji[a][1], naive_dji[a][0], naive_dji[a][1])
我得到顶点2输出的断言错误,如下所示:
AssertionError:“顶点2”分区3428,“顶点2”原始2971处的Dist不匹配
我不了解我的堆实现失败的原因和地点。请帮忙。
在heapq上进行手动插入/删除操作后,堆化可迭代对象。在堆上进行minHeap [dest_idx] = minHeap [0]手动更新后执行了heapq.heapify(minHeap)。
修改后的代码:使用堆实现的Djikstra算法:
%matplotlib inline
import networkx as nx
import heapq
import numpy as np
def undirected_djikstra_heap(DG, source, destination):
#Heap implementation which does the following
#
# 1. For vertices in X, find all edges originating from them to all vertices not in X
# 2. Keep track of minimum value of len(w) + lwv
# 3. Return w, v and lwv
X = [source]
minHeap = []
heapq.heappush(minHeap, [0, source])
all_nodes = list(DG.nodes)
for node in all_nodes:
DG.nodes[node]['shortest_dist'] = float('inf')
print("Heap:")
while len(minHeap) != 0:
w = heapq.heappop(minHeap)
#print(minHeap)
X.append(w[1])
DG.nodes[w[1]]['shortest_dist'] = w[0]
for edge in list(DG.edges):
if (edge[0] == w[1]) and (edge[1] not in X):
edge_tail = edge[0]
edge_head = edge[1]
elif (edge[1] == w[1]) and (edge[0] not in X):
edge_tail = edge[1]
edge_head = edge[0]
else:
continue
if ((edge_tail == w[1]) and (edge_head not in X)) : # node that has just been popped should be the tail
dji_greedy = w[0] + DG.edges[edge_tail, edge_head]['weight'] #djikstra's greedy criterion
if len(minHeap) == 0:
heapq.heappush(minHeap, [dji_greedy, edge_head])
continue
singlenp = [i[1] for i in minHeap]
if edge_head not in singlenp:
heapq.heappush(minHeap, [dji_greedy, edge_head])
else:
dest_idx = singlenp.index(edge_head)
if dji_greedy < minHeap[dest_idx][0]:
minHeap[dest_idx] = minHeap[0]
heapq.heapify(minHeap) # Added this single line
heapq.heappop(minHeap)
heapq.heappush(minHeap, [dji_greedy, edge_head])
#print("Printing minimum distances from starting vertex \'{}\'".format(source))
B = []
for node in all_nodes:
if node in destination:
#print("Vertex {} is at distance {}".format(node, DG.nodes[node]['shortest_dist']))
B.append([node, DG.nodes[node]['shortest_dist']])
B = sorted(B)
return B
使用此修改后的代码,Djikstra算法的天真的实现和堆实现在挑战数据集上给出了相同的结果。