python實現Dijkstra + 堆優化 + 鏈式前向星
最近在做網路拓撲相關的研究,各種經典演算法自然是繞不過去的,由於資料量比較大,決定用鏈式前向星來存圖,網上找一圈,PYTHON+鏈式前向星的程式碼沒找到,於是乎決定自己寫一下,不寫不知道,寫了才嚇一跳,程式碼能力真是弱掉渣了。
一、背景介紹
1.鏈式前向星
內容引用自以下兩篇文章:
https://blog.csdn.net/Binary_Heap/article/details/78209086
https://blog.csdn.net/ACdreamers/article/details/16902023
2.Dijkstra
演算法詳解:https://blog.csdn.net/qq_35644234/article/details/60870719
程式設計思路概括:
visited:已確定最短路徑的頂點的集合,distance:源點到每個頂點的距離,初始設為無窮大,V每次確定的最小值對應的點
V初始為源點
a.從V出發,遍歷以V為起點的所有邊,得到weight,如果 len(src,v)+weight 小於distance中對應的值,則更新distance (用鏈式前向星可輕鬆實現,速度很快)
b.找到distance中最小值,對應的頂點加入到visited中,該頂點為新的V,跳到a步驟,直到vistited中包含所有的點
二、實現
環境:Python 3.6
1.資料結構
前面介紹的前向星的知識,用C實現起來較為複雜,python的字典可以輕鬆實現這一功能:
直接將邊檔案處理成以下格式,如果邊較多,可以轉化為Json存到本地,使用時直接讀取即可。
G = {1:{1:0, 2:1, 3:12}, 2:{2:0, 3:9, 4:3}, 3:{3:0, 5:5}, 4:{3:4, 4:0, 5:13, 6:15}, 5:{5:0, 6:4}, 6:{6:0}}
2.堆優化
在尋找未得到最優值的點中最小的值時,採用堆優化,其複雜度為O(1),可以將整個演算法的複雜度降為nlog(n)
直接使用的heapq這個包來管理堆
2.演算法實現
def dijkstra(G,start): ###dijkstra演算法
INF = 999999999
dis = dict((key,INF) for key in G) # start到每個點的距離
dis[start] = 0
###堆優化
t1 = time.time()
dis_un = {} #未訪問的點的距離
pq = [] #存放排序後的值
for node,d in dis.items(): #最小堆
entry = [d,node]
dis_un[node] = entry
heapq.heappush(pq,entry)
t2 = time.time()
print('建立堆所用時間: ',t2-t1)
t3 = time.time()
while len(pq)>0:
v_dis,v = heapq.heappop(pq) #未訪問點中距離最小的點和對應的距離
for node in G[v]: #與v直接相連的點
new_dis = dis[v] + float(G[v][node])
if new_dis < dis[node]: #如果與v直接相連的node通過v到src的距離小於dis中對應的node的值,則用小的值替換
dis[node] = new_dis #更新所有點的距離
dis_un[node][0] = new_dis #g更新未訪問的點到start的距離
t4 = time.time()
print('Dijkstra演算法所用時間:',t4-t3)
return dis
原始碼下載:https://github.com/dick2737/dijkstra