Dijkstra 是用來找到從一個起點到其他所有點的最短路徑的演算法,適合靜態地圖。
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。heapq
模組import heapq
heapq
是 Python 的標準庫,用於實現最小堆(min-heap)。在 Dijkstra 演算法中,我們使用最小堆來高效地選擇當前距離最小的節點。
dijkstra
函數def dijkstra(graph, start):
這個函數接受兩個參數:
graph
:一個字典表示圖,節點作為鍵,與該節點相連的鄰居節點及其邊的權重作為值。start
:起點節點,演算法從這個節點開始計算最短距離。distances = {node: float('inf') for node in graph}
distances[start] = 0 # 起點距離為 0
distances
字典來存儲每個節點到起點的最短距離。初始時,所有節點的距離設定為無窮大(float('inf')
),表示尚未被訪問過。visited = set()
visited
集合用來存儲已經訪問過的節點。這樣可以避免再次訪問同一節點。
priority_queue = [(0, start)] # (距離, 節點)
priority_queue
是一個優先隊列,用來存儲尚未訪問的節點,並且根據距離進行排序(最小堆)。初始時,我們將起點節點和其距離(0)加入隊列。
while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)
這是 Dijkstra 演算法的核心部分:
heapq.heappop(priority_queue)
來取出當前距離最小的節點。這會返回一個二元組 (distance, node)
,即節點的距離和節點本身。if current_node in visited:
continue
如果當前節點已經在 visited
集合中,說明它已經被處理過,這時就跳過它,繼續處理下一個節點。
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))
對於當前節點的每一個鄰居:
graph[current_node].items()
返回當前節點的所有鄰居及其邊的權重。distance = current_distance + weight
。return distances
當所有節點都處理完後,返回 distances
字典,其中包含了從起點到每個節點的最短距離。
# 節點間的連接與距離
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
出發的最短距離,並將結果打印出來。