图结构专栏——Dijkstra算法详解(大量注释)

图结构专栏——Dijkstra算法详解(大量注释)

Dijkstra 算法是求一个图中一个点到其他所有点的最短路径的算法

一、算法详解

每次从 「未求出最短路径的点」中 取出 距离距离起点 最小路径的点,以这个点为桥梁 刷新「未求出最短路径的点」的距离,可以结合下面的案例来理解。

对于这样一个无向图,我们希望求得节点3到其他节点的最短路径长度。
在这里插入图片描述
首先,我们定义一个数组distance记录了节点3到其他节点的最短路径长度,再定义一个数组visited记录哪些节点到3节点的最短路径长度已经计算过了,这些数组初始化都为-1。

1、首先将我们的目标节点3加入visited中,同时更新distance表

这次结束后visited表:

1234
-1-10-1

因为节点3被加入到visited表,所以更新distance表,更新的方法是使用节点3到其他节点的路径长度

1234
6-1-12

在这里插入图片描述

我们需要将distance表中长度最小的而且不在visited数组中的节点取出来,即为4节点

2、这一步将我们上一步取得的节点4加入visited中,同时更新distance表

这次结束后visited表:

1234
-1-100

因为节点4被加入到visited表,所以更新distance表,之后更新distance表的方法是

  • 对于每个节点j,如果他不在visited数组,并且他与此刻加入visited数组的节点i相连,那么
    1. 如果distance[j] = -1,说明之前加入的节点与该节点j不直接连通,那么此时distance[j]的值就是节点i,j路径的权值
    2. 如果distance[j] >=0,说明之前加入的节点与该节点j直接连通,那么要判断这一步加入了节点i会不会产生目标节点3到节点j更短的路径。那么distance[j] = min( distance[j] , distance[i] + graph[i][j] )

举例来说,加入了节点4以后,因为节点2与节点4相连,因此distance[2]就等于distance[4] + graph[4][2] = 2 + 3 = 5

加入了节点4以后,判断节点1的情况:虽然第一步中得到distance[1] = 6,但是由于加入了新节点4,而节点4与节点1相连,那么distance[j] = min( distance[j] , distance[i] + graph[i][j] ) = min(6 , 2 + 2) = 4

那么更新后的distance表即为

1234
45-12

在这里插入图片描述

我们需要将distance表中长度最小的而且不在visited数组中的节点取出来,即为1节点

3、这一步将我们上一步取得的节点1加入visited中,同时更新distance表

这次结束后visited表:

1234
0-100

更新后的distance表即为

1234
45-12

在这里插入图片描述

我们需要将distance表中长度最小的而且不在visited数组中的节点取出来,即为2节点

4、这一步将我们上一步取得的节点2加入visited中,同时更新distance表

这次结束后visited表:

1234
0-100

更新后的distance表即为

1234
45-12

在这里插入图片描述

至此我们将所有的节点都放入visited表中,表示求解结束。

二、代码

	vector<int> visited;//记录哪些节点的结果被求出来,初始都是0,当一个节点的结果被求出来后值变为-1
	vector<vector<int>> graph;//记录图的信息,不连通的边为-1
	vector<int> distance;//记录结果,即为目标节点target到其他节点的最短距离,特别的distance[target] = 0,初始值是-1

	//weight存储节点之间的权重 eg:[[2,1,1],[2,3,1],[3,4,1]],第一个元素意思是2节点指向1节点,而且这条边的权值为1(节点从0开始)
	//n是节点数
	//k是要判断第k个节点(节点从0开始)
	vector<int> networkDelayTime(vector<vector<int>>& weight, int n, int k) {
		graph.resize(n + 1, vector<int>(n + 1, -1));
		distance.resize(n + 1, -1);
		distance[k] = 0;
		visited.resize(n + 1, 0);
		for (int i = 0; i < weight.size(); i++)
		{
			int one = weight[i][0];//有向边的尾部
			int two = weight[i][1];//有向边的头部,即one->two
			int thisweight = weight[i][2];//这条有向边的权值
			graph[one][two] = thisweight;//这条边的信息加入图矩阵中
		}
		for (int i = 0; i < graph[k].size(); i++)
		{
			
			distance[i] = graph[k][i];//第一次将目标节点到其他节点的长度记录在distance中
		}
		visited[k] = - 1;

		for (int i = 1; i <= n; i++)
		{
			int mindis = (1 << 31) - 1;
			int minindex = 0;
			//遍历节点,找到不在visited数组同时在distance中值最小的节点
			for (int j = 1; j <= n ; j++)
			{
				if (visited[j] == 0 && distance[j] < mindis && distance[j] >= 0)
				{
					mindis = distance[j];
					minindex = j;
				}
			}
			//得到该节点后加入visited数组
			visited[minindex] = -1; 
			//遍历与该节点相连的不在visited数组的节点,判断这些节点的distance需不需要被更新
			for (int j = 1; j <= n; j++)
			{
				if (graph[minindex][j] >= 0 && visited[j] == 0)
				{
					int thisdistance = distance[minindex] + graph[minindex][j];
					if (distance[j] > thisdistance || distance[j] == -1)
					{
						distance[j] = thisdistance;
					}
				}
			}
		}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值