Python 迪克斯特拉’;s算法

Python 迪克斯特拉’;s算法,python,algorithm,dijkstra,Python,Algorithm,Dijkstra,在阅读Dijkstra算法时,我发现应该实现一个最小堆。我尝试实现一个最小堆,该算法有效,但当我没有使用最小堆函数,而是在索引0处弹出顶点时,它也有效 我很困惑,为什么我们要在下一步探索堆中的所有顶点时,总是选择具有最小距离的顶点 例如: from heapq import heappop, heappush from math import inf graph = { 'A': [('B', 10), ('C', 3)], 'C': [('D', 2)],

在阅读Dijkstra算法时,我发现应该实现一个最小堆。我尝试实现一个最小堆,该算法有效,但当我没有使用最小堆函数,而是在索引0处弹出顶点时,它也有效

我很困惑,为什么我们要在下一步探索堆中的所有顶点时,总是选择具有最小距离的顶点

例如:

from heapq import heappop, heappush
from math import inf

graph = {
        'A': [('B', 10), ('C', 3)],
        'C': [('D', 2)],
        'D': [('E', 10)],
        'E': [('A', 7)],
        'B': [('C', 3), ('D', 2)]
    }


def dijkstras(graph, start):
  distances = {}
  
  for vertex in graph:
    distances[vertex] = inf
    
  distances[start] = 0
  vertices_to_explore = [(0, start)]
  while vertices_to_explore:
    current_distance, current_vertex = heappop(vertices_to_explore) # this piece of code
    #current_distance, current_vertex = vertices_to_explore.pop(0) # vs. this piece of code
    for neighbor, edge_weight in graph[current_vertex]:
      new_distance = current_distance + edge_weight
      
      if new_distance < distances[neighbor]:
        distances[neighbor] = new_distance
        heappush(vertices_to_explore, (new_distance, neighbor))
        
  return distances
        
distances_from_d = dijkstras(graph, 'D')
print("\n\nShortest Distances: {0}".format(distances_from_d))

从heapq导入heappop、heappush
从数学导入inf
图={
“A”:[('B',10),('C',3)],
'C':[('D',2)],
“D”:[('E',10)],
'E':[('A',7)],
‘B’:[('C',3),('D',2)]
}
def dijkstras(图表,开始):
距离={}
对于图形中的顶点:
距离[顶点]=inf
距离[起点]=0
顶点\u到\u探索=[(0,开始)]
当你探索时:
当前距离,当前顶点=heappop(顶点到探索)#这段代码
#当前距离,当前顶点=顶点到探索。pop(0)#与这段代码
对于邻居,图[当前顶点]中的边权重:
新距离=当前距离+边权重
如果新的_距离<距离[邻居]:
距离[邻居]=新距离
heappush(顶点到探索,(新的距离,邻居))
返回距离
距离d=dijkstras(图“d”)
打印(“\n\n最短距离:{0}”。格式(距离从)
当pop(0)的工作原理相同时,为什么要使用heappop。。。是因为运行时间吗?如果是这样,为什么它运行得更快


感谢

由于Dijkstra算法以贪婪的方式工作,我们使用min heap并在每一步取距离最小的顶点;没有比当前步距最近顶点的路径更短的路径。这是真实的,因为所有距离都是正的


在上面的代码中,常规未排序列表的
pop(0)
与heap的
heappop()
的工作原理相同,这与作为输入的图形上的重合有关(而与算法无关)。

该算法使用
顶点来探索.pop(0)
纯粹是运气使然。在最小堆中,最小的条目始终位于零位置。因此,如果
toexplore
是一个适当的堆,那么返回的元素是相同的,如果使用
pop(0)
heappop
,则没有matther


重要的是之后会发生什么
heappop
将维护heap属性<代码>弹出(0)不会执行此操作。您的图(以及堆)足够小,因此对于这两种方法,堆上的操作几乎相同。但是,一旦图形增长,堆的非堆性将破坏算法,并且
pop(0)
变量将返回错误的结果。

我们实现最小项的minheaps的方法在概率上将更接近索引0。。这意味着对于小的输入集,在索引0处弹出可能会接近最小值,如果heap push重新调整列表,那么idk,但是如果没有heappop,它将不会给您任何保证,而且肯定不再是dijkstras算法。(它甚至可能无法保证正常工作,但在我有时间验证之前,这只是猜测)


它可能更快,因为零位的pop可以在O(1)时间内完成(可能根据实现进行摊销),而heappop只保证O(logn)。但是,对于非常大的图,heappop可能会让您更快地找到最短路径(并保证正确性),从而在检查顶点总数的一小部分后终止算法。因为虽然检查所有顶点和边确实是最坏的情况,但最好的情况要好得多。

运行时是可以用编译器测量的,也许是应该测量的。如果它们在时间上有所区别,那么它们的工作原理就不一样了。它们可能有相同的结果,但我敢打赌一个专门处理堆,而另一个处理列表。