最短路径(Dijkstra算法和Floyd算法) 您所在的位置:网站首页 最短路径例题图解matlab 最短路径(Dijkstra算法和Floyd算法)

最短路径(Dijkstra算法和Floyd算法)

2024-06-18 20:07| 来源: 网络整理| 查看: 265

最短路径

​ 在图中,不可避免要解决的一个问题就是计算两点之间的最短路径,对于图结构来说,两个点之间不一定只有一条路径,那么如何才能找出最短的那一条就是图中最短路径问题。最短路径问题在实际生活中应用十分广泛。接下来主要介绍两种较为常用的最短路径算法— D i j k s t r a Dijkstra Dijkstra算法和 F l o y d Floyd Floyd算法。

文章目录 最短路径迪杰斯特拉 D i j k s t r a Dijkstra Dijkstra算法 F l o y d Floyd Floyd算法最小生成树与最短路径的区别 ​ 首先需要对最短路径问题进行一些说明,图的类型既可以是有向图也可以是无向图,为了统一,之后统一使用有向图来进行解释。接下来也对于该问题中的一些定义进行区分:

路径长度:一条路径上所经过的边的数目带权路径长度:路径上所经过边的权值之和最短路径:带权路径长度值最小的那条路径 迪杰斯特拉 D i j k s t r a Dijkstra Dijkstra算法

​ D i j k s t r a Dijkstra Dijkstra算法是一种较为经典的最短路径求解算法,它的整体思路和前面的 P r i m Prim Prim算法非常相似,但是又有一些不同之处。接下来首先对 D i j k s t r a Dijkstra Dijkstra算法的整体流程进行一个大致的了解:

设置两点顶点的集合 U U U和 T T T,集合 U U U中存放已找到最短路径的顶点,集合 T T T中存放当前还未找到的最短路径的顶点。初始状态时,集合 U U U中只包含源点,设为 v 0 v_0 v0​。然后从集合 T T T中选择到源点 v 0 v_0 v0​路径长度最短的顶点 u u u加入到集合 U U U中。集合 U U U中每加入一个新的顶点 u u u都要修改源点 v 0 v_0 v0​带集合 T T T中剩余顶点的当前最短路径值,集合 T T T中各顶点的新的当前最短路径长度值,为原来的当前最短路径长度值与从源点过顶点 u u u到达该顶点的带权路径长度中的较小者。回到3,此过程不断重复,直到集合 T T T中的顶点全部加入到集合 U U U中为止。

从上述算法流程中可以看出, D i j k s t r a Dijkstra Dijkstra算法和 P r i m Prim Prim算法的相似之处在于在寻找路径时,都是逐点添加,添加之后也需要重新更新路径。

​ 该算法在计算的时候将所有的点分为两个集合,一个是目标点集 U U U,初始时只有起点, D i j k s t r a Dijkstra Dijkstra算法的功能是,给定一个起点,计算其到其他所有点的最短路径,也就是 1    t o    n 1\,\,to\,\, n 1ton的问题。之后在集合 T T T中找到起点 v 0 v_0 v0​能够达到的,且距离最短的点,将其加入到 U U U中,之后根据新加入的点,重新计算一次 v 0 v_0 v0​到 T T T中剩余点的当前最短距离即可。

​ 接下来通过一个例子来对该算法进行更进一步的理解。 在这里插入图片描述

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

​ 上述例子中,有图中圆圈中的字母代表节点的信息,圆圈上面的内容代表源点到其最短距离以及前驱节点,前驱节点用于后续重现最短路径。这里主要是使用到了一个简单的定理,**如果起点 v 0 v_0 v0​到目标点 u u u之间的某一条路径是最短路径,那么在该路径上面,任何一个点 u ′ u' u′到 v 0 v_0 v0​的路径都是 u ′ u' u′到 v 0 v_0 v0​的最短路径。**这个证明十分简单,使用反证法即可。那么这里在记录最短路径的信息时,如果需要重现路径中的顶点,那么只需要对于每一个结点设置一个前驱结点即可。

​ 接下来继续查看一个例子,这里使用表格的形式来对整个算法流程进行分析。 在这里插入图片描述 在这里插入图片描述

​ 在对该算法有了一定的理解之后,接下来就是考虑如何使用代码来实现它。由于该算法和 P r i m Prim Prim算法十分相近,所以在实现部分和 P r i m Prim Prim算法的实现部分基本一致,除了多了一个前驱数组,在初始化时,依旧是根据起点和邻接矩阵来对所有的距离进行初始化。对于源点到 T T T中点的最短距离,也是借助一个访问数组 v i s i t visit visit和距离数组 d i s dis dis来进行保存, v i s i t [ i ] = f a l s e visit[i]=false visit[i]=false代表第 i i i个点在集合 T T T中。之后在每次循环中,找出距离最短的,然后将其加入到集合 U U U中。最后就是最关键的一步,也就是根据新加入的点来更新到 T T T中剩余点的最短距离,这一步和 P r i m Prim Prim算法中的判断条件不同,需要注意。

​ 在具体实现路径重现的时候,主要是借助前驱数组和栈来进行实现,具体代码如下所示。

// Dijkstra算法 void Dijkstra(int begin) { int minpath = INF; int path[MAX_NUM]; int dis[MAX_NUM]; // 保存到其他点的距离 for (int i = 0; i < num; i++) { if (map[begin][i]) // 设置为原本的距离 { dis[i] = map[begin][i]; path[i] = begin; } else // 不存在就设置距离为无穷大 { dis[i] = INF; path[i] = -1; } } // 初始化访问数组全部为未访问 for (int i = 0; i < num; i++) visit[i] = false; visit[begin] = true; // 起始结点已经被访问 // 已经添加了一个begin,还需要将剩下num-1个点加入 for (int i = 0; i < num - 1; i++) { int min_index = -1; int min_dis = INF; // 找到当前最小的一条边 for (int j = 0; j < num; j++) { if (min_dis > dis[j] && visit[j] == false) { min_dis = dis[j]; min_index = j; } } if (min_dis == INF) // 存在最短距离 continue; visit[min_index] = true; // 该点加入到目标点集中 // 更新距离 for (int j = 0; j < num; j++) { if (map[min_index][j] != 0 && dis[j] > dis[min_index] + map[min_index][j]) { dis[j] = dis[min_index] + map[min_index][j]; path[j] = min_index; } } } // 输出路径 for (int i = 0; i < num; i++) { if (i == begin) // 到自己的路径不必输出 continue; // 先输出长度和信息 cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有