图的应用:最短路径问题

最短路径问题

当我们通过网络浏览网页,发送电子邮件、QQ消息传输的时候,数据在互联网设备之间流动

  • 计算机网络专业领域会详尽地研究网络各层面上的技术细节
  • 我们对Internet工作方式感兴趣的主要是其中包含的图算法
    在这里插入图片描述

PC上的浏览器向服务器请求一个网页时,请求信息需要:

  • 先通过本地局域网,由路由器A发送到Internet,请求信息沿着Internet中的众多路由器传播,最后到达服务器本地局域网所属的路由器B,从而传给服务器。
    在这里插入图片描述

标注"Internet"的云状结构,实际上是一个由路由器连接成的网络

这些网络各自独立而又协同工作,负责将信息从Internet的一端传送到另一端

我们可以通过"traceroute"命令来跟踪信息传送的路径:

  • traceroute www.lib.pku.edu.cn

从本机到北大图书馆服务器之间的一条路由器路径,包含了四个路由器

在这里插入图片描述

由于网络流量的状况会影响路径选择算法,在不同的时间,路径可能不同

所以我们可以将互联网路由器体系表示为一个带权边的图

  • 路由器作为顶点,路由器之间网络连接作为边,权重可以包括网络连接的速度、网络负载程度、分时段优先级等影响因素
  • 作为一个抽象,我们把所有影响因素合成为单一的权重
    在这里插入图片描述

解决信息在路由器网络中选择传播速度最快路径的问题,就转变为在带权图上最短路径问题

这个问题与广度优先搜索BFS算法解决的词梯问题相似,只是在边上增加了权重

  • 如果所有权重相等,还是还原到词梯问题
    在这里插入图片描述

解决带权最短路径问题的经典算法是以发明者命名的"Dijkstra算法"

这是一个迭代算法,得出从一个顶点到其余所有顶点的最短路径,很接近于广度优先搜索算法BFS的结果

具体实现上,在顶点Vertex类中的成员dist用于记录从开始顶点到本顶点的最短带权路径长度(权重之和),算法对图中的每个顶点迭代一次

Dijkstra算法

顶点的访问次序由一个优先队列来控制,队列中作为优先级的是顶点的dist属性
最初,只有开始顶点dist设为0,而其他所有顶点dist设为sys.maxsize(最大整数),全部加入优先队列
随着队列中每个最低dist顶点率先出队
并计算它与邻接顶点的权重,会引起其他顶点dist的减小和修改,引起堆重排
并据更新后的dist优先级再依次出队


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码展示

from pythonds.graphs import PriorityQueue, Graph, vertex
def Dijkstra(aGraph,start):
    pq = PriorityQueue()          #优先队列
    start.setDistance(0)
    pq.buildHeap([(v.get.Distance(),v) for v in aGraph]) #对所有顶点建堆,形成优先队列
    while not pq.isEmpty():
        curentVert = pq.delMin()      # 优先队列出队
        for nextVert in currentVert.getConnections(): 
            newDist = currentVert.getDistance() + currentVert.getWeight(nextVert)
            if newDist < nextVert.getDistance():  #修改出队顶点所邻接顶点的dist,并逐个重排队列
                nextVert.setDistance(newDist)
                pq.decreaseKey(nextVert,newDist)

需要注意的是,Dijkstra算法只处理大于0的权重

  • 如果图中出现负权重,则算法会陷入无限循环

虽然Dijkstra算法完美解决了带权图的最短路径问题,但实际上Internet的路由器中采用的是其他算法

  • 主要原因是,Dijstra算法需要具备整个图的数据,但对于Internet的路由器来说,显然无法将整个Internet所有路由器及其连接信息保存在本地
  • 这不仅仅是数据量的问题,Internet动态变化的特性也使得保存全图缺乏现实性

路由器的选径算法(或"路由算法")对于互联网及其重要

距离向量路由算法

算法分析

首先,将所有顶点加入优先队列并建堆,时间复杂度为O(|V|)
其次,每个顶点仅出队一次,每次delMin花费O(log|V|),一共就是O(|V|log|V|)
另外,每个边关联到的顶点会做一次decreaseKey操作(O(log|V|)),一共就是O(|E|log|V|)
上面三个加起来就是O((|V|+|E|)log|V|
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leopold·Lin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值