最短路径之Dijkstra(迪杰斯特拉)算法(无向图)
简介
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。由for循环可知,其时间复杂度是O(n^2)。
原理
在已知图的邻接矩阵net.vexs[i][j](无向网,含权值的图)的条件下,通过遍历已知图的所有路径,用dis[i]数组来记录到i点的最短路径,然后在循环中不断判断更替。首先,将所有点的集合分为俩部分,一边是已经遍历过的,另外一边是没有遍历过的,分别用mark[i]=1、mark[i]=0来表示。
代码通解
在下面代码中,先将赋予初始值dis[i]=INF(无穷大)、mark[i]=0(未标记),而后单独将源点(x)所联通的路径权值net.arcs[x][i]赋予dis[i](<INF称为初始化),i为联通的点,暂定为到i的最短路径,标记mark[x]=1,即已经遍历;然后,在一个for遍历了所有节点的大循环里面:
①寻找遍历到点联通路径(与之相连线的点)中权值最小的一条; 标记遍历点;
②修正最短路径;
而后,便是已经遍历所有点了,dis[i]也在不断的修正中得到真正的最小值,即最短路径。详情看下列代码:
#define MAXSIZE 20
#define PLACENUM 12
#define INF 9999 // 此处定义999为无穷大struct
{int vexnum,arcnum; //节点数和边数int vexs[MAXSIZE]; // 节点名int arcs[MAXSIZE][MAXSIZE]; //俩个节点之间的值
} net;
/*补充的结构体net,2019.7.3*/void Dijkstra(int x,int y) // x为源点,y为终点
{int i,j,k;int min;int u; //下一个放入集合p的点int dis[net.vexnum]; // 最短路径int mark[net.vexnum]; // 被mark的便是已经遍历,未被mark的便是未遍历/*首先进行最短路径初始化*/for(i=0; i<net.vexnum; i++){mark[i] = 0;dis[i] = net.arcs[x][i];}mark[x]=1; // 标记源点for(k=0; k<net.vexnum; k++) // for 大循环{min = INF; // min初始化最大值,便于后来数据替换(每一个点的出度入度判断)/*寻找遍历到点联通路径(与之相连线的点)中权值最小的一条; 标记遍历点;*/for(i=0; i<net.vexnum; i++){if(mark[i]==0&&min>dis[i]) //判断未遍历点 且 被赋值的最短路径(dis[i]<INF),未被赋值的点 // 应当min==dis[i]=INF{min = dis[i]; //在已知赋值最短路径中,寻找权值最小的点并将他作为下一个遍历 u=i; //点u点}}mark[u]=1; //标记u点,下面u修正将会以最短路径进行辐射/*修正最短路径*/for(i=0;i<net.vexnum;i++){if(!mark[i]&&dis[i]>dis[u]+net.arcs[u][i]) // !mark[i]判断不去走回头路, // dis[i]>dis[u]+net.arcs[u][i]有俩个用途:①若u链接的是x源点没有赋值最短路径的点,那么这里可以赋值②若是赋值过的点,那么可以判断是上一个dis[i](此时是被赋值过的)是不是真正的最短路径,即修正。{dis[i] = dis[u] + net.arcs[u][i]; //若A->C比A->B->C更长那么A->B->C则是到C的最短路径,下图将解释。}}}printf("最短路径值为: %d",dis[y]);
}
我们以A,B,C三个点来举例子,三个点的最短路径分别为dis[0]、dis[1]、dis[2]。
①A为源点初始化,dis[B]=3 (到B的最短路径,dis[1]), dis[C]=6;
②dis[B]<dis[C],选取B为u下一个遍历点;与B相联的有A(不走回头路)、E、C;
③E未赋值,赋予dis[E]; C被之前赋予过,比较 dis[C] > dis[B] + net.arcs[B][C] (要不然你根本进不了这儿),重新赋值dis[C] = dis[B]+net.arcs[B][C];
④大循环遍历所有点,走遍天下。
我觉得下面几张图很不错,图片取自https://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
图一
图二
19.3.24
关于修正最短路径
请参考一下文中引入的动图(图一)和表格图(图二),迪杰斯特拉求最短路径是,将需要遍历的点集合一个个进行遍历的。!mark[i]是需要其值为false(尚未遍历到,这是相对于当前遍历点),当然,这就实现了它不会往回走,同时记录它“向前走”的最短距离点u,在其基础上(修正循环),与u点相连的未被标记(遍历到)的点记其中一个为z,判断源点x->z点们的dis(最短)值是否大于x->u->z点们的距离,如果大于,更新z点们的最新(新的路径)最短距离,在已知最短距离的情况下然后进行更新,直到遍历完所有的点集合(所有路径)。从源点往外辐射就能够理解了。
比如说1,2,3为三角形相互联系。当前是2。已经遍历了1,赋予了1->2、1->3、1->6的dis值,那么在修正部分就会从u(设12、13、16中12距离最小),也就是2往外与没遍历且相邻的3和4判断以下:1->3大于1->2->3? 1->4大于1->2->4?,如果大于,更新dis值,此为修正,这里在已知最短距离1->2的基础上修正了1->3和1->4的dis值。同理到3的时候会修正源点(x/1)到4和到6的最短距离。
下图圆形为已遍历点,方形为未遍历的集合数据,实线为相邻连线,虚线为修正过程。
PS:mark是已经被找过从该点出发的相邻路径,修正在已知最短距离的情况下(u),进行辐射,也就相对于找了u的所有相邻路径来比较更新(!mark[i]&& dis[i]>dis[u]+net.arcs[u][i]),但他并未记录u辐射的路径中的相邻最短路径(需要大循环)。
21.4.16
关于负权值问题
迪杰斯特拉本质上是贪心:找局部最优解,前提是最终的结果是由不断简化问题的局部最优解组成的,贪心是一种特殊的动态规划:他只关注局部最优解(但是我们知道局部最优解不一定是全局最优)。弗洛伊德是动态规划。这里体现出一点:迪杰斯特拉只是单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。而弗洛伊德则是算出所有的点之间的最短路径(多对多)。
那么我们再看负权值问题:迪杰斯特拉:每次修正,我们只会修正当前点所连接的,未被遍历过的(mark[i]),注意前面这句话有两个条件。那么久说明他不会修改早已经(很久以前)就已经确定的最短路径,因为已经确定了是局部最优解,这里在代码里面也能看出来。而也因为这样,弗洛伊德是是能够算负权的(他可以更新“早已经”确定的最短路径,因为他要算出全部点之间的最短路径),值得注意的是弗洛伊德不能解决带有“负权回路”(或者叫“负权环”)的图,因为带有“负权回路”的图没有最短路。
除此之外,求带负权值边的单源最短路径还可以用贝尔曼-福特算法。至于迪杰斯特拉比弗洛伊德快,也是因为他是单源的缘故。
如果看懂了点个赞,给点小动力,谢谢啦~
PS:最简单(代码量)实现寻找最短路径的弗洛伊德算法点这里
最短路径之Dijkstra(迪杰斯特拉)算法(无向图)相关推荐
- Dijkstra(迪杰斯特拉)算法求单源最短路径问题
Dijkstra(迪杰斯特拉)算法求单源最短路径问题 重要的事情说三遍:代码不是我写的!代码不是我写的!代码不是我写的! 第一个算法是严蔚敏数据结构(C语言版)上写的,第二个算法是王道数据结构上写的, ...
- MATLAB轻松绘制地图路线——Dijkstra(迪杰斯特拉)算法最短路径规划
文章目录 1. 地图绘制 2. 计算各节点之间的距离 3. Dijkstra(迪杰斯特拉)算法 4. 根据计算出的距离利用Dijkstra(迪杰斯特拉)算法找出指定节点之间的最短路径 工程文件(可直接 ...
- Dijkstra迪杰斯特拉算法 C++实现
本篇文章主要介绍了Dijkstra迪杰斯特拉算法的C++实现,文章包含两个部分,在第一部分中我会简单介绍迪杰斯特拉算法以及一些个人的理解,第二部分会对C++代码的逻辑进行解释.下面是我已经上传的代码资 ...
- Dijkstra(迪杰斯特拉)算法
一.简介 迪克斯特拉算法又名Dijkstra算法(属于贪心算法).Dijkstra算法是从一节点到其余各节点最短路径计算方法. 迪杰斯特拉算法以起始点为中心向外层层扩展,直到扩展到终点为止. 算法思想 ...
- 算法提升:图的Dijkstra(迪杰斯特拉)算法
目录 概念 思路 代码 概念 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路 ...
- JavaScript实现dijkstra迪杰斯特拉算法(附完整源码)
JavaScript实现dijkstra迪杰斯特拉算法 PriorityQueue完整源代码 MinHeap.js完整源代码 Heap.js完整源代码 Comparator.js完整源代码 dijks ...
- C++实现Dijkstra(迪杰斯特拉)算法(附完整源码)
C++Dijkstra迪杰斯特拉算法的实现 C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main函数测试) C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main ...
- 图的应用---最短路径问题 用迪杰斯特拉算法解决 《地铁换乘问题》
图的应用-最短路径问题 用迪杰斯特拉算法解决 <地铁换乘问题> 代码是在我学习的过程中完成的,也许会有问题,希望大家批评指正. 题目: 描述:已知2条地铁线路,其中A为环线,B为东西向线路 ...
- dijkstra迪杰斯特拉算法(邻接表法)
算法简易过程: 迪杰斯特拉算法(朴素) O(n^2) G={V,E} V:点集合 E:边集合 初始化时 令 S={某源点ear}, T=V-S= {其余顶点},T中顶点对应的距离(ear, Vi)值若 ...
最新文章
- 分布式事务 -- seata框架AT模式实现原理
- python第六周实验_第六周实验四
- relative与absolute相结合
- python调用所有函数_python 调用函数
- 自由之战服务器显示登录失败,自由之战:生存的游戏一直登入不进去怎么办
- meterpreter--收集系统信息
- puppet负载均衡之nginx+passenger
- MSSQL获取当前日期及格式
- 如何自学生物信息学:从菜鸟到专家
- FileResponse django下载文件问题
- 手握IP却不知如何讲好城市故事?“宝藏天津”慢直播支招城市营销
- 如何系统地自学 Python?
- matlab 矩阵白化,主成分分析中如何对矩阵进行白化处理
- 面试之NGFW 性能测试
- 科比,老大1000天
- perl中正则匹配中文字符
- python qqplot 检验正态分布
- vue: Invalid prop: type check failed for prop “action“. Expected String with valu
- 太激动!Android修改全局字体样式,替换整个APP字体
- 【STM32F429】第4章 ThreadX FileX文件系统移植到STM32F429(SD卡)