Dijkstra算法

Dijkstra算法-求单源最短路径

算法演示:

假设一个无向连通图如图所示,算法的重要作用是求单点到各点的最短距离,因此第一步是要找一个起始点,找这个点到各个点的最短距离,这里我们假设D点作为这个起始点。

同时这个算法需要两个集合,集合S代表已计算出最短路径的定点集合,集合U是未计算出最短路径的集合。为了使U中的元素不断转化未S中的元素,需要不断“激活”图中的点,来保证算法能够正常实现。

这个图中有7个点,因此需要依次激活这7个点。

首先选取D点作为起始点,S集合和U集合如下。

第一步:找到顶点D

S={ D(0) } ;     U={ A(∞),B(∞),C(3),E(4),F(∞),G(∞) };

与D连通的只有C和E,所以只有这两个点的路径有具体数值,其余4个点的都未与D直接相连,因此将它们之间的距离用∞表示。 

这里注意,U集合中路径最小的是哪个点,下一次就激活哪个点,并把这个点放到S集合中。

因此下一次要激活点C。

第二步:激活顶点C

S={ D(0),C(3)};     U={ A(∞) , B(13) , E(4) , F(9) , F(∞)};

由红体字所得,将C点放入S集合中,但同时要注意原来的路径长度是否要更新,如果新路径的长度比原路径小,就将路径更新。

在这个U集合当中,E的路径最短,因此下一步要激活顶点E。

第三步:激活顶点E

S={  D( 0 ),C( 3 ),E( 4 )}:     U={A(∞) , B(13) , F(6) , G(12)};

这里E就作为已经计算好的最短路径放在S中,这里值得注意的是,当E点吧被激活后,从F点到D点可以通过E点,同时通过E点的这条路径要比原来的短,因此要把它更新,F的最短路径变为6,G的最短路径变为12。

在这个U集合当中,F的路径最短,因此下一步要激活顶点F。

第四步:激活顶点F

S={D(0) , C(3) , E(4) , F(6)};    U={A(22) , B(13) , G(12)};

当F点被激活以后,A,B,G均可以通过F与D相连接,因此A,B,G的最短路径都要被更新。

在这个U集合当中,G的路径最短,因此下一步要激活顶点G。

第五步:激活顶点G

S={D(0) , C(3) , E(4) , F(6),, G(12)};    U={A(22) , B(13) };

当G点被激活后,A,B的路径都没有变得更短,因此不需要更新。

在这个U集合当中,B的路径最短,因此下一步要激活顶点B。

第六步:激活顶点B

S={D(0) , C(3) , E(4) , F(6),, G(12),, B(13) };    U={A(22) };

当B点被激活后,A的路径并没有变得更短,因此不需要更新。

下一步激活顶点A。

第七步:激活顶点A

S={D(0) , C(3) , E(4) , F(6),, G(12),, B(13),A(22) };    U={};

至此,寻取单源最短路径算法演示已完成,下面是代码实现。

代码及解释如下:

#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
using namespace std;
#define row 7
#define col 7
#define inf 0x3f3f3f3f
//用二维数组将图表示出来
int matrix[row][col] = {
	{inf,12,inf,inf,inf,16,14},
	{12,inf,10,inf,inf,7,inf},
	{inf,10,inf,3,5,6,inf},
	{inf,inf,3,inf,4,inf,inf},
	{inf,inf,5,4,inf,2,8},
	{16,7,6,inf,2,inf,9},
	{14,inf,inf,inf,8,9,inf}
};
//vis代表标记数组,s是已经计算出最短路径的集合数组
//u是未计算出最短路径的集合数组
//nextnode代表记录它的下一个节点
int vis[7], s[7], u[7], nextnode[7];

void Dijkstra(int index)
{
	vis[index] = 1;//D点先标记(为了防止D再被放到U集合中)
	for (int i = 0; i < 7; i++)
		u[i] = matrix[index][i];//先将以D点为起点的U集合初始化
	int min_cur = index;
    int Count = 6;//只需要再激活6个点即可
	while (Count)
	{
		int minx = inf;
		//第一次遍历U集合,目的是找到U集合中的最短路径的点
		//并在循环结束后将其放到S集合中
		for (int i = 0; i < 7; i++)
		{
			if (!vis[i] && u[i]<minx)//寻找U集合最短的路径
			{
				minx = u[i];//将最小值更新
				min_cur = i;//把最小值的下标记录下来,要知道激活了哪个点
			}
		}
		s[min_cur] = minx;//放入最短路径的S集合中相应位置
		vis[min_cur] = 1;//将激活过的点标记
		//第二次遍历U集合,目的是看U集合中的剩下点的路径能否更新成更短的
		//因为激活的点有可能与其他的点连接起来,距离一定比inf小,就可以更新
		for (int i = 0; i < 7; i++)
		{
			//如果激活的点与剩余未被标记过的点的距离仍然是inf,则不变
			//如果不是inf则把路径计算并记录下来
			//并在下一个if语句中判断是否比原来的短
			int tmp=matrix[i][min_cur] == inf ? inf : minx + matrix[i][min_cur];
			if (!vis[i] && tmp < u[i])
			{
				u[i] = tmp;//比它短就更新
				nextnode[i] = min_cur;
			}
		}
		Count--;
	}

}
int main()
{
	for (int i = 0; i < 7; i++)
		nextnode[i] = -1;
	Dijkstra('D' - 'A');//D点作为起点
	for (int i = 0; i < 7; i++)//显示最短距离
	{
		cout << "D到" << char(i + 'A') << "的最短距离是" << s[i] << endl;
	}
	int index = 0;
	while (index != -1)
	{
		cout << char(index + 'A');
		index = nextnode[index];
	}
	cout << "D" << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值