Dijkstra的最短路径算法

时间:2014-01-10 21:43:33

标签: algorithm dijkstra

CLRS中的Dijkstra算法,第59页在第7行中有以下代码:

for each vertex v \in Adj[u]

此行选择迭代节点v的所有邻居。此处的节点v是算法当前正在处理并添加到最短路径树的节点。 然而,在v的那些邻居中,已经在集合S中的那些邻居在&完成,和那些 S中的节点正在形成最短路径树T. 集合S中的任何节点都不能具有比T中已经存在的路径短的路径到v。 否则,该路径将一直遍历到那时。

所以,第7行不应该更好

for each vertex v \in Adj[u] \intersect Q   // Q = V \ S

或同样地

for each vertex v \in Adj[u]\S 

// ===========================

添加解释:

处理完毕后(已处理=设置距离和父矢量 所有直接邻居的条目)节点u并将其添加到树中, 节点u离源最近。如果有一个off-tree节点 因此,通过它在源和之间存在一条较短的路径。 ü,节点z将在u之前处理。

// ======================

附加2:对Javier下面有用答案的冗长评论:

将图中的所有边放在一个数组中,说“EDGES” - 一个边,一个数组条目。 每个数组条目保存边(u,v),边权重和2个指针 - 一个到节点u,一个到节点v。

图表仍然表示为邻接列表。

Adj [u]仍然是一个链表 - 但是,这个链表在一个数组结构上。 此时,此列表中的节点值是与该边对应的EDGES的索引。

因此,例如,Node u有2个链接事件: (你,x)& (U,Y)。 Edge(u,x)位于EDGES的第23个单元格,(u,y)位于第5个单元格。 然后,Adj [u]是长度为2的链表,该列表中的节点为23和5. Say,Adj [u] [0] .edgesIndex = 23和Adj [u] [1] .edgesIndex = 5。这里,对于Adj [x]的链表中的一些i,Adj [x] [i] .edgesIndex = 23。 (Adj [j] [i],作为链表中的节点,还有“next”和“prev”字段。)

并且,EDGES [23]对Adj [u]的相应条目(u,x)有一个引用,而Adj [x]的条目另一个引用。我按原样离开第7行,但这一次,在我处理了该循环中的边(u,v)之后(我已经从Adj [u]中发现了这个边缘),我从链接列表中删除了该边缘Adj [u],从那里我转到相应的EDGES条目,该条目具有对应的Adj [x] [i]条目的引用。我删除所有 - EDGES [23],Adj [u] [0]和Adj [x] [i](无论我在那里。)对于所有数组结构,我可以在每个边缘的恒定时间内处理所有这些。

仍然是邻接列表表示,可以从(u,v)跟踪(v,u)的位置并在恒定时间移除它们,现在仅在该交叉点的边缘处理我正在寻找渐近的使用的内存量相同,时间效率更高。

// ====================

附加3:

纠正上述附加2中的一件事:

我写的内容可能需要更多 - 而不是没有它的算法:

删除Adj [u]和Adj [x]中链接列表中的链接,以及相应的链接 EDGES条目,所有这些中的直接内存查找不太可能 占用较少的CPU周期,而不是放松算法中的边缘。

它仍会检查每个边缘(u,v)一次而不是两次 - 一次用于(u,v),一次用于(v,u),并且与没有它的算法明显处于相同的渐近时间。但是绝对没什么收获 处理时间和使用的内存成本更高。

另一种选择是: 添加一行类似

的内容
if (v \in S) then continue; 

作为for循环的第一个。这可以通过将S维持为来实现 布尔值的S [| V |]数组,并在每个顶点相应时设置其值 添加到设置S--这基本上是哈维尔在他的ans中所说的。

1 个答案:

答案 0 :(得分:1)

Adj[u]Q相交是正确的,但这不是一个好主意,因为最后,您需要迭代Adj[i]的所有元素。我认为没有办法解决这个问题。

只有你能找到一种有效地交叉这两个 VERY 的方法,即比O(n)更好的方法,它才有效。

您实现的一个很好的增强功能是标记所有已结算的节点,然后如果节点v已确定,则可以忽略内部循环的其余部分。