狄克斯特拉演算法,解決加權最短路徑問題--python實現
阿新 • • 發佈:2018-12-31
問題:尋找從起點到終點的最短路徑。
關係圖如下:
解決思路:建立三張散列表。graph 儲存關係圖;costs 儲存各個節點的開銷(開銷是指從起點到該節點的最小的權重);
parents 儲存各個節點的父節點是誰。
建立一個數組用來儲存已經處理過的節點 processed.
檢視所有節點,只要有節點未處理就迴圈以下過程:
(1) 獲取開銷最小的節點,就是離起點最近的節點。
(2) 計算經過該節點到達他全部鄰居的開銷。
(3) 若這個開銷小於原本他自己記錄中的開銷,就更新鄰居的開銷和鄰居的父節點。
(4) 將這個節點新增到已經處理的陣列中。
程式碼(有詳細註釋):
注意:狄克斯特拉演算法不適用於權值為負的最短路徑問題。# -*-coding:utf-8-*- # 用散列表實現圖的關係 graph = {} graph["start"] = {} graph["start"]["a"] = 6 graph["start"]["b"] = 2 graph["a"] = {} graph["a"]["end"] = 1 graph["b"] = {} graph["b"]["a"] = 3 graph["b"]["end"] = 5 graph["end"] = {} # 建立節點的開銷表,開銷是指從start到該節點的權重 # 無窮大 infinity = float("inf") costs = {} costs["a"] = 6 costs["b"] = 2 costs["end"] = infinity # 父節點散列表 parents = {} parents["a"] = "start" parents["b"] = "start" parents["end"] = None # 已經處理過的節點,需要記錄 processed = [] # 找到開銷最小的節點 def find_lowest_cost_node(costs): # 初始化資料 lowest_cost = infinity lowest_cost_node = None # 遍歷所有節點 for node in costs: # 該節點沒有被處理 if not node in processed: # 如果當前節點的開銷比已經存在的開銷小,則更新該節點為開銷最小的節點 if costs[node] < lowest_cost: lowest_cost = costs[node] lowest_cost_node = node return lowest_cost_node # 找到最短路徑 def find_shortest_path(): node = "end" shortest_path = ["end"] while parents[node] != "start": shortest_path.append(parents[node]) node = parents[node] shortest_path.append("start") return shortest_path #尋找加權的最短路徑 def dijkstra(): # 查詢到目前開銷最小的節點 node = find_lowest_cost_node(costs) # 只要有開銷最小的節點就迴圈 while node is not None: # 獲取該節點當前開銷 cost = costs[node] # 獲取該節點相鄰的節點 neighbors = graph[node] # 遍歷這些相鄰節點 for n in neighbors : # 計算經過當前節點到達相鄰結點的開銷,即當前節點的開銷加上當前節點到相鄰節點的開銷 new_cost = cost + neighbors[n] # 如果計算獲得的開銷比原本該節點的開銷小,更新該節點的開銷和父節點 if new_cost < costs[n]: costs[n] = new_cost parents[n] = node # 遍歷完畢該節點的所有相鄰節點,說明該節點已經處理完畢 processed.append(node) # 去查詢下一個開銷最小的節點,若存在則繼續執行迴圈,若不存在結束迴圈 node = find_lowest_cost_node(costs) # 迴圈完畢說明所有節點都已經處理完畢 shortest_path = find_shortest_path() shortest_path.reverse() print(shortest_path) # 測試 dijkstra()