Dijkstra算法

Dijkstra算法(迪杰斯特拉算法,D算法)可以求出一个给定顶点到图中所有其他顶点的最短路径。Dijkstra算法的限制是要求图中所有边的权值不小于0。

算法思路

Dijkstra算法是依据最短路径的最优子结构性质来进行的,抓住这一点就可以很好的理解Dijkstra算法。该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。

假设P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,则有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是从k到s的最短距离,那么必定存在另一条从k到s的最短路径P'(k,s),那么P'(i,j)=P(i,k)+P'(k,s)+P(s,j)<P(i,j)。则与P(i,j)是从i到j的最短路径相矛盾。因此该性质得证。 

由上述性质可知,如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点。那么(Vi...Vk)也必定是从i到k的最短路径。为了求出最短路径,Dijkstra就提出了以最短路径长度递增,逐次生成最短路径的算法。譬如对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+matrix[i][j]}。根据这种思路,假设存在G=<V,E>,源顶点为V0,U={V0},dist[i]记录V0到i的最短距离,path[i]记录从V0到i路径上的i前面的一个顶点。

1.从V-U中选择使dist[i]值最小的顶点i,将i加入到U中;

2.更新与i直接相邻顶点的dist值。(dist[j]=min{dist[j],dist[i]+matrix[i][j]})

3.重复1,2直到U=V,停止。

下面以实例的方式展示Dijkstra算法的过程:

1.如下图一有向图,以a为源点寻找所有节点到它的最短路径。首先,与a相连最短路径为2,相连节点为d,将d加入U中。

2.考虑a点到U-V的所有路径,最短路径为到达c的路径,将c加入U。

 

 3.a点到V-U的最短路径为到e点的路径,将e加入U。

4.a点到V-U最短路径为到b点路径,将b加入U。

 

 5.a点到V-U最短路径为到g点路径,将g加入U。

 6.此时V-U中只剩下f点,此时由a点有两条路径都可到达f,长度都为12,任选一条,将f加入U。

 7.此时所有节点都在U中了,算法结束。图中红色路径即为寻找到的a点到各节点的最短路径。

算法的python实现

函数的参数是被操作的图graph和图中的一个顶点v0,设变量vnum记录图graph的顶点数。
算法中的一个问题是如何记录从v0到各顶点的最短路径。根据最优子结构性质,要记录到顶点v的最短路径,只需记录到v最短路径上的前一顶点。如果对每个顶点都有了这样的记录,就可以追溯这些记录,找出从v0到顶点v的最短路径。由此可见,记录所有最短路径只需要用一个vnum一1个元素的边集合。
下面算法里用一个vnum元的表paths记录路径,其元素pathslv]的形式为(v',p),说明从vo到顶点v的最短路径上的前一顶点是v',该最短路径的长度是p。此外,函数里还用paths[v]取值None表示v还不在U里。
求解最短路径的候选边集以路径长度作为排序码记录在优先队列cands里,队列元素形式为(p,v,v'),表示从v0经v到v'的已知最短路径的长度为p。根据p的值在cands里排序,保证总选出最近的未知距离顶点。
每次选出的具有最小p值的边。如果其终点v'在V-U,就将其加人paths,并将经由v'可达的其他顶点及其路径长度记人cands。显然,如果cands已有到某顶点的路径,但后来发现的新路径更短,优先队列保证最短的路径被先行取出,满足算法的需要。

def dijkstra_shortest_paths(graph,v0):
    vnum=graph.vertex_num()
    assert 0<=v0<vnum
    paths=[None]*vnum
    count=0
    cands=PrioQueue([0,v0,v0])
    while count<vnum and not cands.is_empty():
        plen,u,vmin=cands.dequeue()
        if paths[vmin]:
            continue
        paths[vmin]=(u,plen)
        for v,w in graph.out_edges(vmin):
            if not paths[v]:
                cands.enqueue((plen+w,vmin,v))
        count+=1
    return paths

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值