[Python]Dijkstra 演算法實作

更新 發佈閱讀 10 分鐘

Dijkstra 演算法實作

Dijkstra 是用來找到從一個起點到其他所有點的最短路徑的演算法,適合靜態地圖。

實作步驟

  1. 定義地圖:使用圖(Graph)表示地圖。
  2. 初始化距離:起點距離設為 0,其餘點設為無限大。
  3. 遍歷節點:逐步找出距離最短的節點,更新相鄰節點的距離。
  4. 結束條件:所有節點被訪問完成。

程式碼

import heapq  # 引入 heapq 模組,實現最小堆優先隊列

def dijkstra(graph, start):
# 初始化最短距離字典,將所有節點的最短距離設為無窮大
distances = {node: float('inf') for node in graph}
distances[start] = 0 # 起點到自己的距離為 0

# 儲存已訪問的節點集合,避免重複處理節點
visited = set()

# 初始化優先隊列,將起點節點及其距離 0 加入隊列
priority_queue = [(0, start)] # 優先隊列中的元素是 (距離, 節點)

while priority_queue:
# 從優先隊列中取出距離最小的節點
current_distance, current_node = heapq.heappop(priority_queue)

# 如果當前節點已經訪問過,跳過該節點
if current_node in visited:
continue

# 將當前節點標記為已訪問
visited.add(current_node)

# 遍歷當前節點的所有鄰居
for neighbor, weight in graph[current_node].items():
# 計算從起點到鄰居的距離
distance = current_distance + weight
# 如果新計算出的距離比已知距離更短,則更新最短距離
if distance < distances[neighbor]:
distances[neighbor] = distance
# 將鄰居節點和其新的距離加入優先隊列
heapq.heappush(priority_queue, (distance, neighbor))

# 返回從起點到所有節點的最短距離
return distances

# 測試圖:節點間的連接與對應的邊的權重
graph = {
'A': {'B': 1, 'C': 4}, # 節點 A 與 B 的距離為 1,A 與 C 的距離為 4
'B': {'A': 1, 'C': 2, 'D': 5}, # 節點 B 與 A 的距離為 1,B 與 C 的距離為 2,B 與 D 的距離為 5
'C': {'A': 4, 'B': 2, 'D': 1}, # 節點 C 與 A 的距離為 4,C 與 B 的距離為 2,C 與 D 的距離為 1
'D': {'B': 5, 'C': 1} # 節點 D 與 B 的距離為 5,D 與 C 的距離為 1
}

start_node = 'A' # 設定起點為節點 A
# 呼叫 dijkstra 函數,計算從節點 A 出發的最短距離
shortest_distances = dijkstra(graph, start_node)

# 輸出結果,顯示從節點 A 到其他節點的最短距離
print("Shortest distances from node A:", shortest_distances)

測試輸出

對於這個測試例子,演算法會計算並返回從節點 A 到其他節點的最短距離,輸出結果應該如下:

Shortest distances from node A: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

這表示:

  • 從 A 到 A 的距離是 0。
  • 從 A 到 B 的最短距離是 1。
  • 從 A 到 C 的最短距離是 3。
  • 從 A 到 D 的最短距離是 4。


程式碼詳細解說


1. 引入 heapq 模組

import heapq

heapq 是 Python 的標準庫,用於實現最小堆(min-heap)。在 Dijkstra 演算法中,我們使用最小堆來高效地選擇當前距離最小的節點。

2. 定義 dijkstra 函數

def dijkstra(graph, start):

這個函數接受兩個參數:

  • graph:一個字典表示圖,節點作為鍵,與該節點相連的鄰居節點及其邊的權重作為值。
  • start:起點節點,演算法從這個節點開始計算最短距離。

3. 初始化最短距離字典

distances = {node: float('inf') for node in graph}
distances[start] = 0 # 起點距離為 0
  • 我們使用 distances 字典來存儲每個節點到起點的最短距離。初始時,所有節點的距離設定為無窮大(float('inf')),表示尚未被訪問過。
  • 然後,將起點的距離設置為 0,因為起點到自身的距離是 0。

4. 初始化已訪問節點集合

visited = set()

visited 集合用來存儲已經訪問過的節點。這樣可以避免再次訪問同一節點。

5. 初始化優先隊列

priority_queue = [(0, start)]  # (距離, 節點)

priority_queue 是一個優先隊列,用來存儲尚未訪問的節點,並且根據距離進行排序(最小堆)。初始時,我們將起點節點和其距離(0)加入隊列。

6. 主迴圈

while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)

這是 Dijkstra 演算法的核心部分:

  • 當優先隊列不為空時,不斷循環。
  • 我們使用 heapq.heappop(priority_queue) 來取出當前距離最小的節點。這會返回一個二元組 (distance, node),即節點的距離和節點本身。

7. 如果節點已訪問過,跳過

if current_node in visited:
continue

如果當前節點已經在 visited 集合中,說明它已經被處理過,這時就跳過它,繼續處理下一個節點。

8. 標記節點為已訪問

visited.add(current_node)

將當前節點標記為已訪問,這樣就不會再次處理它。

9. 更新鄰居節點的距離

for neighbor, weight in graph[current_node].items():
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))

對於當前節點的每一個鄰居:

  • graph[current_node].items() 返回當前節點的所有鄰居及其邊的權重。
  • 計算從起點到鄰居的距離:distance = current_distance + weight
  • 如果計算出的距離比鄰居當前的距離短,則更新鄰居的最短距離,並將這個鄰居節點及其新的距離加入優先隊列。

10. 返回最短距離字典

return distances

當所有節點都處理完後,返回 distances 字典,其中包含了從起點到每個節點的最短距離。

11. 測試地圖與呼叫函數

# 節點間的連接與距離
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}
}

start_node = 'A'
shortest_distances = dijkstra(graph, start_node)
print("Shortest distances from node A:", shortest_distances)

這段程式碼定義了一個圖 graph,其中每個節點的鄰居和對應的邊權重以字典的形式給出。然後,呼叫 dijkstra 函數來計算從節點 A 出發的最短距離,並將結果打印出來。


留言
avatar-img
留言分享你的想法!
avatar-img
螃蟹_crab的沙龍
156會員
305內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。 興趣是攝影,踏青,探索未知領域。 人生就是不斷的挑戰及自我認清,希望老了躺在床上不會後悔自己什麼都沒做。
你可能也想看
Thumbnail
身為採購專家,當然不能錯過11/11購物節的超殺折扣!本文將帶你深入瞭解蝦皮11/11購物節的完整攻略,從必領的各種優惠券、商城折扣,到限時的搶購技巧,讓你買到手軟荷包也不哭泣。更重要的是,揭密蝦皮分潤計畫,教你如何零成本創業,透過分享商品連結,每月輕鬆加薪,開啟數位遊牧人生!
Thumbnail
身為採購專家,當然不能錯過11/11購物節的超殺折扣!本文將帶你深入瞭解蝦皮11/11購物節的完整攻略,從必領的各種優惠券、商城折扣,到限時的搶購技巧,讓你買到手軟荷包也不哭泣。更重要的是,揭密蝦皮分潤計畫,教你如何零成本創業,透過分享商品連結,每月輕鬆加薪,開啟數位遊牧人生!
Thumbnail
雙11購物節將近,這次分享一些蝦皮海外賣場購物的步驟與注意事項,並且介紹雙11蝦皮購物的相關優惠;另外蝦皮分潤計畫持續招募新血中,只要分享購物連結即可獲得分潤,是很適合創作者的額外收入管道喔!
Thumbnail
雙11購物節將近,這次分享一些蝦皮海外賣場購物的步驟與注意事項,並且介紹雙11蝦皮購物的相關優惠;另外蝦皮分潤計畫持續招募新血中,只要分享購物連結即可獲得分潤,是很適合創作者的額外收入管道喔!
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。 節點Vertex: 節點
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。 節點Vertex: 節點
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。
Thumbnail
Min-Heap 最小堆是一種特殊的樹狀資料結構, 其中每個節點的值都小於或等於其子節點的值。這意味著最小值總是位於根節點。 Min-Heap 常用於實作優先權佇列 (Priority Queue)、Dijkstra 演算法、 排序以及尋找中位數等應用。
Thumbnail
Min-Heap 最小堆是一種特殊的樹狀資料結構, 其中每個節點的值都小於或等於其子節點的值。這意味著最小值總是位於根節點。 Min-Heap 常用於實作優先權佇列 (Priority Queue)、Dijkstra 演算法、 排序以及尋找中位數等應用。
Thumbnail
Minimum Path Sum 給定一個矩陣,每個格子點代表經過的對應成本。 每回合可以往右移動一格或往下移動一格。 請問從起點左上角 走到 終點右下角的最小路徑成本總和是多少?
Thumbnail
Minimum Path Sum 給定一個矩陣,每個格子點代表經過的對應成本。 每回合可以往右移動一格或往下移動一格。 請問從起點左上角 走到 終點右下角的最小路徑成本總和是多少?
Thumbnail
本篇文章討論了在給定二元矩陣中,如何使用Dijkstra算法找出從左上角到右下角的最安全路徑的安全分數。包括定義曼哈頓距離、最安全路徑的算法以及時間複雜度和空間複雜度分析。最終推薦Dijkstra algorithm和priority queue的使用。文章提供了參考文獻LeetCode的連結。
Thumbnail
本篇文章討論了在給定二元矩陣中,如何使用Dijkstra算法找出從左上角到右下角的最安全路徑的安全分數。包括定義曼哈頓距離、最安全路徑的算法以及時間複雜度和空間複雜度分析。最終推薦Dijkstra algorithm和priority queue的使用。文章提供了參考文獻LeetCode的連結。
Thumbnail
這篇文章,會帶著大家複習以前學過的 格子點DP框架, 並且以最小成本的下降路徑的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 最小成本下降路徑的形式 每個格子點的值代表經過的成本。 要求從最上面那排往下方走,落到最下一排的最小成本的下降路徑。
Thumbnail
這篇文章,會帶著大家複習以前學過的 格子點DP框架, 並且以最小成本的下降路徑的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 最小成本下降路徑的形式 每個格子點的值代表經過的成本。 要求從最上面那排往下方走,落到最下一排的最小成本的下降路徑。
Thumbnail
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
Thumbnail
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
Thumbnail
這題算是路徑計數類的DP衍伸題(路徑數、方法數、組合數...等等這種枚舉類的題目,第一時間切入除了想到DFS+回溯法之外,也可以留意DP動態規劃解題的可能性) 題目會給我們一個指定長度為arrLen的陣列,起點從index=0開始出發,每次移動可以往左移一格,往右移一格,或是留在原地不
Thumbnail
這題算是路徑計數類的DP衍伸題(路徑數、方法數、組合數...等等這種枚舉類的題目,第一時間切入除了想到DFS+回溯法之外,也可以留意DP動態規劃解題的可能性) 題目會給我們一個指定長度為arrLen的陣列,起點從index=0開始出發,每次移動可以往左移一格,往右移一格,或是留在原地不
Thumbnail
進階圖論題目: 計算最短的一筆畫路徑長 題目會給定我們一張圖和對應的相鄰矩陣,要求我們返回一筆畫拜訪所有節點的最短路徑長,起終點不拘。
Thumbnail
進階圖論題目: 計算最短的一筆畫路徑長 題目會給定我們一張圖和對應的相鄰矩陣,要求我們返回一筆畫拜訪所有節點的最短路徑長,起終點不拘。
Thumbnail
就這樣,因為拖延症犯了想偷懶,結果是對dictionary的使用時機和使用方式,有了新的體會。原來,dictionary這樣用,也是可以的啦!
Thumbnail
就這樣,因為拖延症犯了想偷懶,結果是對dictionary的使用時機和使用方式,有了新的體會。原來,dictionary這樣用,也是可以的啦!
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News