最近在做网络拓扑相关的研究,各种经典算法自然是绕不过去的,由于数据量比较大,决定用链式前向星来存图,网上找一圈,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为起点的所有边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这个包来管理堆
3.算法实现
def dijkstra(G,start): ###dijkstra算法
INF = 999999999
dis = dict((key,INF) for key in G) # start到每个点的距离
dis[start] = 0
vis = dict((key,False) for key in G) #是否访问过,1位访问过,0为未访问
###堆优化
pq = [] #存放排序后的值
heapq.heappush(pq,[dis[start],start])
t3 = time.time()
path = dict((key,[start]) for key in G) #记录到每个点的路径
while len(pq)>0:
v_dis,v = heapq.heappop(pq) #未访问点中距离最小的点和对应的距离
if vis[v] == True:
continue
vis[v] = True
p = path[v].copy() #到v的最短路径
for node in G[v]: #与v直接相连的点
new_dis = dis[v] + float(G[v][node])
if new_dis < dis[node] and (not vis[node]): #如果与v直接相连的node通过v到src的距离小于dis中对应的node的值,则用小的值替换
dis[node] = new_dis #更新点的距离
# dis_un[node][0] = new_dis #更新未访问的点到start的距离
heapq.heappush(pq,[dis[node],node])
temp = p.copy()
temp.append(node) #更新node的路径
path[node] = temp #将新路径赋值给temp
t4 = time.time()
print('Dijkstra算法所用时间:',t4-t3)
return dis,path
源码下载:https://github.com/dick2737/dijkstra