为什么Dijkstra算法中的reducekey需要O(logN)时间?

时间:2013-11-14 05:45:14

标签: algorithm heap priority-queue dijkstra decrease-key

更新部分,

for all neighbors w of u:
    if dist[w] > dist[u] + l(u,w)
        dist[w] = dist[u] + l(u,w)
        prev[w] = u
        decreasekey(H,w)

这里,w是节点的ID,我认为它应该像pair(ID,key),哪个键是dist [ID]。 如果是这样,在优先级队列上找到ID为w的节点应该花费O(N)时间而不是O(logN)时间。 那么,为什么Dijkstra算法中的reducekey需要O(logN)时间?

3 个答案:

答案 0 :(得分:4)

用于Dijktra的堆实现与传统的优先级队列实现不同,因此内置的优先级队列库对您没有帮助。唯一的解决方案是实现堆并跟踪数组中堆中每个顶点的位置。当你插入或删除到堆中时,你需要更新指向顶点的指针。当你必须在堆中执行reduceKey时,你可以在堆中直接定位顶点,并且你可以在该位置更新Key的值。使用Heapify重新排序堆(需要O(logn))。

答案 1 :(得分:0)

你说优先级队列中的减少键需要O(N)时间是正确的。因此,为了使算法在O(nlogn)时间运行,您可以选择以下两个选项之一:

  1. 实现一个优先级队列,您将在其中存储节点的位置。这种类型的优先级队列支持在O(log n)时间内删除节点。您可以找到一个实现(在java中)here。和使用此IndexMinPriorityQueue here的dijkstra算法代码。

  2. 将新值插入优先级队列而不是reduceKey操作。但是,最差情况下的空间使用量将增加到O(M),而之前为O(N),其中M是边数。您可以验证此算法是否也可以使用。事实上,这是大多数应用中的首选方法,其中图中的边数很小,可以适合内存。

    for(all neighbors w of u){
        if (dist[w] > dist[u] + l(u,w)) {
            dist[w] = dist[u] + l(u,w);
            prev[w] = u;
            insert(H,w);
        }
    }
    

答案 2 :(得分:-1)

在堆中,reduceKey始终为O(logN)。 Proof