求解两点间最短路径的算法

  • 最短路径算法
    • 1.Dijkstra算法
    • 2.Bellman-Ford算法
    • 3.SPFA算法
    • 4.Floyd算法
  • 几种最短路径算法的对比
    • Dijkstra算法、Bellman-Ford算法和SPFA算法的对比
    • Dijkstra算法和Floyd算法的对比

最短路径算法

  • 单源最短路算法:已知起点,求到达其他点的最短路径。
            常用算法:Dijkstra算法、Bellman-Ford算法、SPFA算法。
  • 多源最短路算法:求任意两点之间的最短路径。
            常用算法:Floyd算法。

1.Dijkstra算法

        迪杰斯特拉算法(Dijkstra)是寻找从一个顶点到其余各顶点最短路径的算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
        处理问题:单源、无负权、有向图、无向图最短路径。
        不能使用的情况:边中含有负权值(无法判断)。
        主要特点:以起始点为中心向外层层扩展,直到扩展到终点为止。
        算法过程:V为顶点集合,分为两组S和U。其中,S为已求出的顶点的集合(初始时只含有源点V0),U为尚未确定的顶点集合,源点到各个顶点最短路径的距离结果存在dist[]中。
                        1.初始化:S只包含源点,U包含除V中S以外的其他点;
                        2.选择:从U中选取一个距离源点最近的顶点u加入S;
                        3.更新:修改u的后继顶点的最短路径长度;
                        4.重复步骤2和3直到所有顶点都包含在S中。
       举例说明:图中有A、B、C、D、E五个顶点,其中A为源顶点,寻找A到其他各顶点的最短路径。
                        Step1:V包含A、B、C、D、E五个点,S只包含源点A,U包含V中除S以外的其他点,计算U中各点到源点的距离发现距源点最近的顶点是B;在这里插入图片描述                        Step2:将距源点最近的顶点B移入S中,S包含A、B,U包含C、D、E,再次计算U中各点到源点的距离发现距源点最近的顶点是C;在这里插入图片描述                        Step3:再次将距源点最近的顶点C移入S中,S包含A、B、C,U包含D、E,再次计算U中各点到源点的距离发现距源点最近的顶点是E;在这里插入图片描述                        Step4:再次将距源点最近的顶点E移入S中,S包含A、B、C、E,U包含D,再次计算U中各点到源点的距离发现距源点最近的顶点是D;在这里插入图片描述                        Step5:再次将距源点最近的顶点D移入S中,S包含A、B、C、E、D,U为空,算法结束,得到的dist[]中的结果就是A到其他各顶点的最短距离。在这里插入图片描述

2.Bellman-Ford算法

       贝尔曼-福特算法(Bellman–Ford)是求解单源最短路径问题的一种算法,它的原理是对图进行次松弛操作,得到所有可能的最短路径。其算法可以进行若干种优化,提高了效率。
       基本思想: Bellman-Ford的思想和Dijkstra很像,其关键点都在于不断地对边进行松弛,而最大的区别就在于前者能作用于负边权的情况。其实现思路是在求出最短路径后,判断此刻是否还能对便进行松弛,如果还能进行松弛,便说明还有负边权的边。
       处理问题:单源、可有负权、有向图、无向图最短路径。
       算法过程:1.初始化:初始化所有的点,每一个点保存一个值,表示源点到这个点的距离其他点的值设为无穷大;
                        2.迭代求解:进行循环,从1到n-1,进行松弛计算;
                        3.检验负权回路:遍历所有边,如果的d[v]>d[u]+w(u,v)存在,则有从源点可达的权为负的回路。
       边的松弛操作:如下图所示,d[v]、d[u]是目前s到v、u的最短距离,关注边<u,v>能否改善d[v]的值。如果if(d[u]+w<d[v])成立,原有的d[v]路线将被s → \rightarrow →u → \rightarrow →v代替,这就是边<u,v>的松弛操作。在这里插入图片描述

3.SPFA算法

       SPFA 算法是Bellman-Ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环,它采用一系列的松弛操作以得到从某一个节点出发到达图中其它所有节点的最短路径。
       处理问题:单源、可有负权、有向图、无向图最短路径(自身其实无法处理负权)
       算法思想:设立一个队列用来保存待优化的点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

4.Floyd算法

       弗洛伊德算法(Floyd)又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法,也要高于执行|V|次SPFA算法。
       处理问题:多源、可有负权、有向图、无向图最短路径。
       优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
       缺点:时间复杂度比较高,不适合计算大量数据。
       算法过程:1.从任意一条单边路径开始,所有两点之间的距离是边的权,用邻接矩阵G表示,如果两点之间没有边相连,则权为无穷大;
                        2.对于每一对顶点i和j,看看是否存在一个顶点k使得从i到k再到j比已知的路径更短。G[i][j] = min( G[i][j], G[i][k]+G[k][j] ),如果G[i][j]的值变小,定义一个矩阵D用来记录所插入点的信息,则D[i][j]=k。
                                       f o r k i n r a n g e ( s e l f . V ) : for{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}k{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}} in {_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}range(self.V): for​k​​​​​​​​in​​​​​​​​range(self.V):
                                              f o r i i n r a n g e ( s e l f . V ) : for{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}i{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}} in {_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}range(self.V): for​​​​​​​​i​​​​​​​​in​​​​​​​​range(self.V):
                                                     f o r j i n r a n g e ( s e l f . V ) : for{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}j{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}} in {_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}range(self.V): for​​​​​​​​j​​​​​​​​in​​​​​​​​range(self.V):
                                                            i f s e l f . G [ i ] [ k ] + s e l f . G [ k ] [ j ] < s e l f . G [ i ] [ j ] : if{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}self.G[i][k]{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}+self.G[k][j]<self.G[i][j]: if​​​​​​​​self.G[i][k]​​​​​​​​+self.G[k][j]<self.G[i][j]:
                                                                   s e l f . G [ i ] [ j ] = s e l f . G [ i ] [ k ] < s e l f . G [ k ] [ j ] self.G[i][j]{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}={_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}self.G[i][k]<self.G[k][j] self.G[i][j]​​​​​​​​=​​​​​​​​self.G[i][k]<self.G[k][j]
                                                                   s e l f . D [ i ] [ j ] = s e l f . D [ i ] [ k ] self.D[i][j]{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}={_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}{_{}}self.D[i][k] self.D[i][j]​​​​​​​​=​​​​​​​​self.D[i][k]
       举例说明:图中有1、2、3、4、5五个顶点,寻找任意两点间的最短路径。矩阵G为任意两点间的权值邻接矩阵,矩阵D为用来记录所插入点的标号。
                        Step1:初始化矩阵G、D,G初始化为任意两点间的距离,若两点间没有直线相连则用无穷大表示;D初始化为任意两点间的终点标号。在这里插入图片描述                        Step2:更新矩阵G、D,看有没有任意两点经过0之后比原来的路径更短,有的话G中对应的元素更新为更小的值,D中对应的元素更新为同一行第0列的元素。在这里插入图片描述                        Step3:继续更新矩阵G、D,看有没有任意两点经过1之后比原来的路径更短,有的话G中对应的元素更新为更小的值,D中对应的元素更新为同一行第1列的元素。在这里插入图片描述                        Step4:继续更新矩阵G、D,看有没有任意两点经过2之后比原来的路径更短,有的话G中对应的元素更新为更小的值,D中对应的元素更新为同一行第2列的元素。在这里插入图片描述                        Step5:继续更新矩阵G、D,看有没有任意两点经过3之后比原来的路径更短,有的话G中对应的元素更新为更小的值,D中对应的元素更新为同一行第3列的元素。在这里插入图片描述                        Step6:继续更新矩阵G、D,看有没有任意两点经过4之后比原来的路径更短,有的话G中对应的元素更新为更小的值,D中对应的元素更新为同一行第4列的元素。算法结束,得到的 G 4 {G_{4}} G4​为任意两点间的最短距离, D 4 {D_{4}} D4​为任意两点间最短路径间的信息。在这里插入图片描述

几种最短路径算法的对比

Dijkstra算法、Bellman-Ford算法和SPFA算法的对比

  • Dijkstra算法无法判断含负权边的图的最短路径,Bellman-Ford算法优于Dijkstra算法的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高。
  • SPFA算法在负边权图上可以完全取代Bellman-Ford算法,另外在稀疏图中也表现良好。但是在非负边权图中,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法,以及它的使用堆优化的版本。
  • 与Dijkstra算法与Bellman-Ford算法都不同,SPFA的算法时间效率是不稳定的,即它对于不同的图所需要的时间有很大的差别。

Dijkstra算法和Floyd算法的对比

  • Dijkstra算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。
  • Floyd算法是多源最短路径算法,用于计算任意两点间的最短路径。
  • Dijkstra算法是基于贪心算法的思想,从起点出发逐步找到通向终点的最短距离;而Floyd算法是基于动态规划的思路,通过循环迭代的方法同时找出任意两个顶点间的最短距离。

求解两点间最短路径的算法_两点之间最短路径-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值