【问题标题】:Dijkstra’s algorithmDijkstra 算法
【发布时间】:2020-09-06 15:31:26
【问题描述】:

在阅读 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))

为什么在 pop(0) 工作时使用 heappop... 是因为运行时间?如果是,为什么它跑得更快?

谢谢

【问题讨论】:

  • 运行时间可以用编译器测量,也许你应该测量一些东西。如果它们在时间上有所不同,那么它们的工作方式就真的不一样了。他们可能有相同的结果,但我敢打赌,你一个专门研究堆,而另一个则处理列表。

标签: python algorithm dijkstra


【解决方案1】:

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

在上面的代码中,常规未排序列表的pop(0) 与堆的heappop() 的工作方式相同,这与作为输入给出的图形的巧合有关(与算法无关)。

【讨论】:

    【解决方案2】:

    算法与vertices_to_explore.pop(0) 一起工作的原因纯属运气。在最小堆中,最小的条目总是在位置 0。因此,如果vertices_to_explore 是一个正确的堆,则返回的元素是相同的,无论您使用的是pop(0) 还是heappop

    重要的是在那之后会发生什么。 heappop 将维护堆属性。 pop(0) 不会那样做。您的图表(以及堆)足够小,以至于两种方法在堆上的操作几乎相同。但是一旦你的图增长,你的堆的非堆将破坏算法,pop(0) 变体将返回错误的结果。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2021-03-13
        • 2011-06-27
        • 2021-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多