理解 Dijkstra 演算法:從理論到實現
Dijkstra 演算法是圖論中使用的經典尋路演算法,用於尋找圖中從來源節點到所有其他節點的最短路徑。在本文中,我們將探索該演算法、其正確性證明,並提供 JavaScript 中的實作。
什麼是 Dijkstra 演算法?
Dijkstra 演算法是一種貪婪演算法,旨在找到具有非負邊權重的加權圖中從單一來源節點開始的最短路徑。它由 Edsger W. Dijkstra 於 1956 年提出,至今仍然是電腦科學中使用最廣泛的演算法之一。
輸入輸出
- 輸入:圖表 G=(V,E) , 在哪裡 VVVVE E
- EE > 是邊的集合,以及源節點 V 中的 VV sε 的最短路徑距離 s
- s
- s
- 到所有其他節點
- V
VVVVVVV . 核心概念 鬆弛:更新到節點的最短已知距離的過程。 優先隊列:高效率取得暫定距離最小的節點。 貪婪法: 依照最短距離的非遞減順序處理節點。 演算法 初始化距離:距離(s)=0,距離(v)=距離(v)=(v)=(v)=∞∀v=s 使用優先權佇列根據距離儲存節點。
重複提取距離最小的節點並鬆弛其鄰居。
放鬆 - 數學解釋
- 初始化: 距離(s)=0,距離(v)=距離(v)=(v)=(v)=∞對於一個llv
s(s)( s ) (v)( v )
(v) 代表任何其他節點。-
放鬆步驟:對於每條邊
(u,v) (u,v)v)w(u, v) u,v)v)v)v(u,v),上一頁(v)=距離(v)=距離(u) w(u,v),上一個(v)=u
為什麼有效:鬆弛確保我們始終能夠在找到更短路徑時透過逐步更新距離來找到到節點的最短路徑。
優先權隊列 - 數學解釋
-
隊列操作:
- 優先權佇列總是使節點出列
(u)
最小的暫定距離:
u=arg v∈Q 分鐘距離距離距離
- 為什麼有效:透過處理具有最小的節點 (文本{距離}(v) ) (距離(v)) ( u ) (u)
. - 優先權佇列總是使節點出列
(u)
最小的暫定距離:
正確性證明
我們用強歸納法證明了Dijkstra演算法的正確性。什麼是強感應?
強歸納法是數學歸納法的變體,用來證明一個命題 ( P(n) ) (P(n))( P(1), P(2), 點, P (k) ) (P(1),P(2),…,P(k)) kk)( P(k 1) ) (>(>k)( P(k) )
(P(k))
-
證明
(>(>1)) 。在我的另一篇文章中更詳細地探索它。 Dijkstra 演算法的正確性(歸納證明) 基本案例: 來源節點 (s)( s ) (s) 初始化為 距離(s)=0文字{dist}(s) = 0 距離(s)=0 ,這是正確的。
(kk1))( P(k 1) ) 歸納假設:
假設到目前為止處理的所有節點都有正確的最短路徑距離。-
歸納步驟:
)
下一個節點 (u) 從優先權佇列中出列。自從 u)距離(u))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; } }
也是正確的。
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
-
邊緣:
- A至 B = (1),A 至 C = (4) A→B=(1),A→C=(1),A→ C=
- >(4)=(5)B至 C = (2),B 至 D = (5) B→
- C=(2),B→→D=(1 )
C至 D = (1)
- C→
D=(1)距離(C)C)C))) ∞, 距離(D)D)>D)>>>>某事> 文字{距離}(A) = 0, ;文字{距離}(B) = infty, ;文字{距離}(C) = infty, ;文字{距離}(D) = infty 距離(A)=0,距離(B)=距離(B)=(B)= > ∞,距離(C)=∞,距離(D)=∞ -
流程A:
- 放鬆邊緣:
A→B,A→C。
距離(B)=1,距離(C)=(C)=(C)=
- 放鬆邊緣:
A→B,A→C。
-
>4
-
→D.B到 C,B 到 D。 B→)=)文字{距離}(C) = 3,;文本{距離}(D) = 6 距離(C)=3,
(D)= -
→D.B到 C,B 到 D。
-
(D)=
-
(D)=
放鬆邊緣:
C→距離(D)=4文字{dist}(D) = 4 距離(D)=4
-
(D)=
放鬆邊緣:
C
-
過程D:
- 沒有更多更新。
最終距離和路徑
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) |
要點:
-
簡單數組:
- 由於提取最小值的線性搜索,對於大圖來說效率低下。
-
二元堆:
- 由於其簡單性和效率的平衡而成為標準和常用的。
-
二項式堆:
- 理論保證稍好,但實現起來更複雜。
-
斐波那契堆:
- ( O(1) )攤銷遞減金鑰的最佳理論效能,但更難實現。
-
配對堆:
- 簡單且在實務上表現接近斐波那契堆。
結論
Dijkstra 演算法是一種強大而有效的方法,用於在具有非負權重的圖中找到最短路徑。雖然它有限制(例如,無法處理負邊權重),但它廣泛用於網路、路由和其他應用程式。
- 鬆弛透過迭代更新路徑確保最短距離。
- 優先隊列保證我們總是處理最近的節點,保持正確性。
- 正確性用歸納法證明:一旦節點的距離確定,它就保證是最短路徑。
這裡有一些詳細的資源,您可以在其中探索 Dijkstra 演算法以及嚴格的證明和範例:
- Dijkstra 演算法 PDF
- SlideShare 上的最短路徑演算法
此外,維基百科提供了該主題的精彩概述。
引用:
[1] https://www.fuhuthu.com/CPSC420F2019/dijkstra.pdf
歡迎在評論中分享您的想法或改進!
以上是理解 Dijkstra 演算法:從理論到實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務
