更新部分,
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)时间?
答案 0 :(得分:4)
用于Dijktra的堆实现与传统的优先级队列实现不同,因此内置的优先级队列库对您没有帮助。唯一的解决方案是实现堆并跟踪数组中堆中每个顶点的位置。当你插入或删除到堆中时,你需要更新指向顶点的指针。当你必须在堆中执行reduceKey时,你可以在堆中直接定位顶点,并且你可以在该位置更新Key的值。使用Heapify重新排序堆(需要O(logn))。
答案 1 :(得分:0)
你说优先级队列中的减少键需要O(N)
时间是正确的。因此,为了使算法在O(nlogn)
时间运行,您可以选择以下两个选项之一:
实现一个优先级队列,您将在其中存储节点的位置。这种类型的优先级队列支持在O(log n)
时间内删除节点。您可以找到一个实现(在java中)here。和使用此IndexMinPriorityQueue here的dijkstra算法代码。
将新值插入优先级队列而不是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