[英]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.