[英]Why does Dijkstra's algorithm need a priority queue when this regular queue version is also correct?
我已阅读以下内容,但请查看下面的代码。
我有两个版本的 dijkstra,一个带有 PQueue 的好版本,一个带有常规链表队列的坏版本。
public static void computeDijkstra(Vertex source) {
source.minDistance = 0.;
Queue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
// Queue<Vertex> vertexQueue = new LinkedList<Vertex>();
vertexQueue.add(source);
while (!vertexQueue.isEmpty()) {
Vertex fromVertex = vertexQueue.poll();
if (fromVertex.neighbors != null) {
for (Edge currentEdge : fromVertex.neighbors) {
Vertex toVertex = currentEdge.target;
if (currentEdge.weight + fromVertex.minDistance < toVertex.minDistance) {
toVertex.minDistance = currentEdge.weight + fromVertex.minDistance;
toVertex.previous = fromVertex;
vertexQueue.add(toVertex);
}
}
}
}
}
public static void computeDijkstraBad(Vertex source) {
source.minDistance = 0.;
// Queue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
Queue<Vertex> vertexQueue = new LinkedList<Vertex>();
vertexQueue.add(source);
while (!vertexQueue.isEmpty()) {
Vertex fromVertex = vertexQueue.poll();
if (fromVertex.neighbors != null) {
for (Edge currentEdge : fromVertex.neighbors) {
Vertex toVertex = currentEdge.target;
if (currentEdge.weight + fromVertex.minDistance < toVertex.minDistance) {
toVertex.minDistance = currentEdge.weight + fromVertex.minDistance;
toVertex.previous = fromVertex;
vertexQueue.add(toVertex);
}
}
}
}
}
我还使用如下文本文件创建图形
0, 1, 2, 3, 4, 5, 6 // vertices
0, 6 // from and to vertex
1, (2-5, 0-4, 4-6) // from vertex 1 it will have edge to 2 with weight 5 ...
0, (4-3, 3-7)
4, (2-11, 3-8)
3, (2-2, 5-5)
2, (6-2, 5-10)
5, (6-3)
两种实现都呈现以下[0, 3, 2, 6]
,这确实是从 0 到 6 的最短路径!
现在我们知道,如果使用 Simple BFS 来寻找正整数的最短距离,就会出现找不到最小路径的情况。 那么,有人可以给我一个反例,我的 Bad 实现将无法打印图表的正确路径。 随时以我使用的图形格式(示例文本文件格式)给我答案。
到目前为止,我所拥有的所有图表,两种实现都呈现了正确的结果。 这不应该发生,因为糟糕的实现是运行时 (E+V),我们知道如果没有至少 E log V,我们就找不到最短路径。
另一个例子,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
0, 10
0, (1-9, 2-10, 3-11)
1, (4-1, 5-7)
2, (4-4, 5-3, 6-5)
3, (5-1, 6-4)
4, (7-9, 8-14, 5-3)
5, (7-4, 8-5, 9-9, 6-2)
6, (8-2, 9-2)
7, (10-3)
8, (10-2)
9, (10-5)
两种实现都渲染 [0, 3, 5, 6, 8, 10],这是从 0-10 的正确最短路径。
我相信您给出的算法是正确的,但它不如 Dijkstra 的算法有效。
在高层次上,您的算法通过找到一个“活动”节点(距离已降低的节点),然后扫描出边以激活所有需要更新其距离的相邻节点来工作。 请注意,同一个节点可以被多次激活——事实上,一个节点可能会在每次其候选距离下降时被激活一次,这在算法的运行中可能会发生多次。 此外,如果候选距离多次下降,您实现的算法可能会将同一个节点多次放入队列,因此除了第一个之外的所有出队都可能是不必要的。 总体而言,我预计这会导致大图的运行时受到很大影响。
从某种意义上说,您实现的算法是最短路径算法,但它不是 Dijkstra 算法。 主要区别在于,Dijkstra 的算法使用优先级队列来确保每个节点出队和处理一次且恰好一次,从而提高了效率。
所以我想我能给出的最好答案是“你的算法不是 Dijkstra 算法的实现,Dijkstra 算法使用优先级队列的原因是为了避免像你的算法那样多次重新计算距离。”
你的算法会找到正确的结果,但你的方法正在做的是它扼杀了 Dijkstra 方法的效率。
示例:
考虑 3 个名为 AB C 的节点。
A->C :7
A->B :2
B->C :3
在您的坏方法中,您首先将 A 到 C 的最短路径设置为 7,然后在遍历时将其修改为 5 (A->BC)
在 Dijkstra 的方法中,根本不会遍历 A->C,因为在使用最小堆时,将首先遍历 A->B,将 B 标记为“已遍历”,然后将遍历 B->C ,并且,C 将被标记为“已遍历”。 现在,由于 C 已被标记为“已遍历”,因此永远不会检查路径 A->C(长度为 7)。
因此,如您所见,在您的糟糕方法中,您将到达 C 2 次(A->C & A->B->C),而使用 Dijkstra 的方法时,您将只到达 C 一次。
这个例子应该证明你使用 Dijkstra 算法的迭代次数会更少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.