在 python 中使用堆来提高 Dijkstra 算法的性能?
下面是我使用堆(对于无向图)对 Dijkstra 算法的实现。
这对于大小合理的图形来说效果很好,但是我对重新计算连接到新探索的节点的节点的贪婪标准的代码不满意。
在这里,我迭代了堆中的所有项目,这看起来并没有很好地利用数据结构。有没有更好的方法来实现这一目标?
图是一个字典,其中包含每个节点(键)与其连接的节点列表以及边的长度。 graph[v]
返回 [[w_1, l_1],...,[w_k, l_k]]
,其中 v
之间有一条边对于 1 到 k 之间的所有 i
,w_i
的长度为 l_i
。有点像邻接表。
shortestPath = {1: 0} # Length of the shortest pass from s (labelled 1) to v (v's label = key)
def createHeap():
# Heap contains the greedy criterion for an edge and the label of it's head vertex
heap = []
for k, v in graph.items():
if k in shortestPath:
continue # Ignoring starting vertex
bestScore = 1000000
for (w, length) in v:
if w in shortestPath:
greedyScore = shortestPath[w] + length
if greedyScore < bestScore:
bestScore = greedyScore
hq.heappush(heap, (bestScore, k)) # bestScore used as heap key
return heap
def dijkstra():
heap = createHeap()
for _ in range(n - 1): # For every vertex in graph (other than starting vertex 1)
greedyScore, w = hq.heappop(heap) # Next vertex to be processed
shortestPath[w] = greedyScore
for [v, length] in graph[w]: # Finds the new crossing edges and re-evaluates greedy criterion
if v not in shortestPath:
for item in heap: # better implementation ?
if item[1] == v:
oldScore = item[0]
heap.remove(item)
hq.heapify(heap)
newScore = min(oldScore, greedyScore + length)
hq.heappush(heap, (newScore, v))
dijsktra()
Below is my implementation for Dijkstra's algorithm using heaps (for undirected graphs).
This works just fine for reasonably sized graphs however I am not satisfied by my code for recalculating greedy criterion of nodes connected to the newly explored node.
Here I iterate over all of the items in the heap which doesn't look like a good use of the data structure. Is there a better way to achieve this ?
The graph
is a dictionary which contains for each node (key) a list of nodes connected to it and the length of the edge.graph[v]
returns [[w_1, l_1],...,[w_k, l_k]]
where there is an edge between v
and w_i
of length l_i
for all i
s between 1 and k. Sort of like an adjacency list.
shortestPath = {1: 0} # Length of the shortest pass from s (labelled 1) to v (v's label = key)
def createHeap():
# Heap contains the greedy criterion for an edge and the label of it's head vertex
heap = []
for k, v in graph.items():
if k in shortestPath:
continue # Ignoring starting vertex
bestScore = 1000000
for (w, length) in v:
if w in shortestPath:
greedyScore = shortestPath[w] + length
if greedyScore < bestScore:
bestScore = greedyScore
hq.heappush(heap, (bestScore, k)) # bestScore used as heap key
return heap
def dijkstra():
heap = createHeap()
for _ in range(n - 1): # For every vertex in graph (other than starting vertex 1)
greedyScore, w = hq.heappop(heap) # Next vertex to be processed
shortestPath[w] = greedyScore
for [v, length] in graph[w]: # Finds the new crossing edges and re-evaluates greedy criterion
if v not in shortestPath:
for item in heap: # better implementation ?
if item[1] == v:
oldScore = item[0]
heap.remove(item)
hq.heapify(heap)
newScore = min(oldScore, greedyScore + length)
hq.heappush(heap, (newScore, v))
dijsktra()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Dijkstra的算法有几种替代实现,但是它们都不需要通过堆迭代,也不需要从中删除任意节点,也不需要重复重新使用它。所有这些动作都杀死了堆打算给予的绩效收益。
我还建议避免全球变量。而是将需要的内容作为参数传递,然后让函数
dijkstra
返回结果结果。这是您可以用于
Graph
数据结构的可能实现之一:示例呼叫:
输出:
There are several alternative implementations of Dijkstra's algorithm, but none of them need to iterate through the heap, nor remove arbitrary nodes from it, nor re-heapify it repeatedly. All those actions kill the performance benefit that a heap is intended to give.
I would also advise to avoid global variables. Instead pass what is needed as arguments, and let the function
dijkstra
return the results.Here is one of the possible implementations you could use for your
graph
data structure:Example call:
Output: