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为起点的所有边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

 

 

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/dick2737/article/details/80305274
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞