在第24章第658页CLRS第三版中的DIJKSTRA伪代码中,在内部循环中,在从新添加的顶点放松相邻边缘时,为什么在已经从队列中取消并添加到最短路径的边缘上允许放松到树?
while(Q not empty){
u = extractMin from Q;
Add S to the shortest path tree;
for each vertex v adjacent to u
relax(u,v,w)
}
为什么内部循环不检查顶点是否已经是最短路径树的一部分,如
while(Q not empty){
u = extractMin from Q;
Add S to the shortest path tree;
for each vertex v adjacent to u
if v is in Q
then relax(u,v,w)
}
哪种方法正确?
答案 0 :(得分:1)
relax
做的第一件事就是检查
if v.d > u.d + w(u,v)
如果v
已在最短路径树上,则检查将始终失败,relax
将不会继续。 if v is in Q
检查将是多余的。
但是,如果if v is in Q
在算法的具体实现中比if v.d > u.d + w(u,v)
快得多,包括它可能是一个有用的优化。
答案 1 :(得分:0)
这两种方法在功能上都是正确的。但是,您的版本不如CLRS版本优化。
你不想做if v is in Q
因为那是一个O(log n)操作,而if v.d > u.d + w(u, v)
是O(1)。在算法的开头,Q包含 all 图中的顶点。因此,对于一个非常大的稀疏连接图表,您的版本最终会比CLRS更糟糕。
然而,你的问题并非完全没有价值。在CLRS中对Dijkstra算法的解释有点令人困惑,这实际上是我带到了这个讨论主题。查看第658页的伪代码:
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S = 0
3 Q = G.V
4 while Q not empty
5 u = EXTRACT-MIN(Q)
6 add u to S
7 for each vertex v in G.Adj[u]
8 RELAX(u, v, w)
有人想知道维持S的重点是什么?如果我们通过删除第2行和第6行完全取消它,算法仍然有效,并且在它完成之后,您可以通过跟随前导指针(已经存储在每个顶点中)向后通过图形来打印最短路径(第601页上的使用PRINT-PATH(G, s, v)
,如第647页所述。 S似乎更多地用作解释工具,以说明Dijkstra是一种贪婪的算法,但在实际的图形实现中,在我看来它是不需要的。