Dijkstra算法及代码详解

您所在的位置:网站首页 算法怎么用代码实现数据 Dijkstra算法及代码详解

Dijkstra算法及代码详解

2024-07-11 07:54| 来源: 网络整理| 查看: 265

迪杰斯特拉算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值,其在运行过程中维持的关键信息是一组节点集合S。算法重复从结点集V-S中选择最短路径估计最小的结点u,将u加入到集合S,然后对所有从u发生的边进行松弛,运行结束后,从源节点到集合S中每个结点之间的最短路径已经被找到。 下面,通过一个实例讲解该过程!

一、示例详解

在这里插入图片描述 如图,是一个有向无环图,假定出发点为V1,迪杰斯特拉算法将算出V1到其他所有点的最短路径,则所求V1到终点的最短路径也可得到,该算法主要完成以下几步:

找到V1 得到以V1出发的邻接点的最短距离,将V1加到S集合中(代码中通过vis数组标记) 从S集合之外的点中找到距离最短者,对以其为出发点的邻接点进行松弛操作,若距离被更新,则记录前驱 重复3,直到所有点被S集合收录

完成后,将得到V1到所有点的最短距离,同时,通过每一个点记录的前驱得到最短路径。

1.问题 1.1 松弛操作是啥?

松弛操作意味着比起原来的路径,找到了一条距离更短的路,则将原来点的距离更新为新的距离。注意本文中某个点的距离全部指的是从出发点即V1到该点的距离。代码如下:

if(dis[j]>dis[k]+map[k][j]) { dis[j]=dis[k]+map[k][j]; path[j]=k; } 1.2 为啥每个点记录前驱能用于V1到所有终点?

我的理解是最短路是由最短路+某一条固定路组成,所以前驱适用全部点,比如该图中V1到V7的最短路径为V1->V2->V3->V5->V6->V7,因为V6->V7的距离固定为50,所以V7的最短路径中V1->V6的一段必然是V1->V6的最短路径,因此每个结点只需记录一个前驱。要想打印出路径,从终点开始一次次找前驱即可,可通过递归实现。代码如下:

void print(int x)//x为终点 { if(x == -1) return; //递归 print(path[x]); printf("%d->",x); } 2. 算法过程

程序运行过程中,数据的更新情况如图所示: 在这里插入图片描述

红色数据代表每次迭代中被更新的数据,下标代表了结点前驱。由上图可得,当所有结点加入S后,就得到了V1到所有结点的最短距离和最短路径,例如V1到V7的最短距离为130,V7的前驱为V6,V6的前驱为V5,V5的前驱为V3,V3的前驱为V2,V2的前驱为V1,则V1到V7的最短路径为V1->V2->V3->V5->V6->V7。

3. 算法复杂度分析

在这里插入图片描述

二、代码实现 #include #include #include /*问题描述: * 输入n和m,代表n个节点,m条边,然后是m行输入,每行有x,y,z,代表x到y的路距离为z。 * 问题:从1出发到各点的最短路径。 * 测试样例: 7 12 1 2 20 1 3 50 1 4 30 2 3 25 2 6 70 3 4 40 3 6 50 3 5 25 4 5 55 5 6 10 5 7 70 6 7 50 */ using namespace std; const int maxn = 100; int map[maxn][maxn]; int dis[maxn]; int path[maxn]; int vis[maxn];//记录更新过的点 int n; void dijk(int s) { //初始化 memset(path,-1,sizeof(path)); /*INF使用0x3f3f3f3f的好处: * 1:满足无穷大加一个有穷的数依然是无穷大(在DijKstra算法松弛操作中避免了溢出而出现负数) * 2:满足无穷大加无穷大依然是无穷大(两个0x3f3f3f3f相加并未溢出) * 3:初始化时,由于每一个字节为0x3f,所以只需要memset(buf,0x3f,sizeof(buf))即可 */ memset(dis,0x3f,sizeof(dis)); //初始化为无穷大 memset(vis,0,sizeof(vis)); dis[s] = 0; //自身到自身的距离为0 while(1) { int k = 0; for(int j = 1; j


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3