Dijkstra 算法是图论中使用的经典寻路算法,用于查找图中从源节点到所有其他节点的最短路径。在本文中,我们将探索该算法、其正确性证明,并提供 JavaScript 中的实现。
Dijkstra 算法是一种贪婪算法,旨在找到具有非负边权重的加权图中从单个源节点开始的最短路径。它由 Edsger W. Dijkstra 于 1956 年提出,至今仍然是计算机科学中使用最广泛的算法之一。
初始化距离:
使用优先级队列根据距离存储节点。
反复提取距离最小的节点并松弛其邻居。
哪里 (s) 是源节点,并且 (v) 代表任何其他节点。
为什么有效:松弛确保我们始终能够在找到更短路径时通过逐步更新距离来找到到节点的最短路径。
队列操作:
我们使用强归纳法证明了Dijkstra算法的正确性。
强归纳法是数学归纳法的一种变体,用于证明一个命题 (P(n)) ,我们假设真相是 (P(1),P(2),…,P(k)) 证明 ( P(k 1)) 。这与常规归纳法不同,常规归纳法仅假设 (P(k)) 证明 ( P(k 1)) 。在我的另一篇文章中更详细地探索它。
基本案例:
源节点
(s)
初始化为
距离(s)=0
,这是正确的。
归纳假设:
假设到目前为止处理的所有节点都有正确的最短路径距离。
归纳步骤:
下一个节点
(u)
从优先级队列中出列。自从
距离(u)
是最小的剩余距离,并且所有先前的节点都有正确的距离,
距离(u)
也是正确的。
先决条件(优先队列):
// Simplified Queue using Sorting // Use Binary Heap (good) // or Binomial Heap (better) or Pairing Heap (best) class PriorityQueue { constructor() { this.queue = []; } enqueue(node, priority) { this.queue.push({ node, priority }); this.queue.sort((a, b) => a.priority - b.priority); } dequeue() { return this.queue.shift(); } isEmpty() { return this.queue.length === 0; } }
这是使用优先级队列的 Dijkstra 算法的 JavaScript 实现:
function dijkstra(graph, start) { const distances = {}; // hold the shortest distance from the start node to all other nodes const previous = {}; // Stores the previous node for each node in the shortest path (used to reconstruct the path later). const pq = new PriorityQueue(); // Used to efficiently retrieve the node with the smallest tentative distance. // Initialize distances and previous for (let node in graph) { distances[node] = Infinity; // Start with infinite distances previous[node] = null; // No previous nodes at the start } distances[start] = 0; // Distance to the start node is 0 pq.enqueue(start, 0); while (!pq.isEmpty()) { const { node } = pq.dequeue(); // Get the node with the smallest tentative distance for (let neighbor in graph[node]) { const distance = graph[node][neighbor]; // The edge weight const newDist = distances[node] + distance; // Relaxation Step if (newDist < distances[neighbor]) { distances[neighbor] = newDist; // Update the shortest distance to the neighbor previous[neighbor] = node; // Update the previous node pq.enqueue(neighbor, newDist); // Enqueue the neighbor with the updated distance } } } return { distances, previous }; } // Example usage const graph = { A: { B: 1, C: 4 }, B: { A: 1, C: 2, D: 5 }, C: { A: 4, B: 2, D: 1 }, D: { B: 5, C: 1 } }; const result = dijkstra(graph, 'A'); // start node 'A' console.log(result);
重建路径
// Simplified Queue using Sorting // Use Binary Heap (good) // or Binomial Heap (better) or Pairing Heap (best) class PriorityQueue { constructor() { this.queue = []; } enqueue(node, priority) { this.queue.push({ node, priority }); this.queue.sort((a, b) => a.priority - b.priority); } dequeue() { return this.queue.shift(); } isEmpty() { return this.queue.length === 0; } }
初始化距离:
流程A:
过程B:
进程C:
过程D:
比较 Dijkstra 算法与不同优先级队列实现的时间复杂度:
Priority Queue Type | Insert (M) | Extract Min | Decrease Key | Overall Time Complexity |
---|---|---|---|---|
Simple Array | O(1) | O(V) | O(V) | O(V^2) |
Binary Heap | O(log V) | O(log V) | O(log V) | O((V E) log V) |
Binomial Heap | O(log V) | O(log V) | O(log V) | O((V E) log V) |
Fibonacci Heap | O(1) | O(log V) | O(1) | O(V log V E) |
Pairing Heap | O(1) | O(log V) | O(log V) | O(V log V E) (practical) |
Dijkstra 算法是一种强大而有效的方法,用于在具有非负权重的图中查找最短路径。虽然它有局限性(例如,无法处理负边权重),但它广泛用于网络、路由和其他应用程序。
这里有一些详细的资源,您可以在其中探索 Dijkstra 算法以及严格的证明和示例:
此外,维基百科提供了该主题的精彩概述。
引用:
[1] https://www.fuhuthu.com/CPSC420F2019/dijkstra.pdf
欢迎在评论中分享您的想法或改进!
以上是理解 Dijkstra 算法:从理论到实现的详细内容。更多信息请关注PHP中文网其他相关文章!