最近在做网络拓扑相关的研究,各种经典算法自然是绕不过去的,由于数据量比较大,决定用链式前向星来存图,网上找一圈,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