详细实现最短路径(迪杰斯特拉算法)

最短路径,说白了,就是图里从一个顶点到另一个顶点的最小权值之和。

今天,小编带大家一起用迪杰斯特拉(Dijkstra)算法实现它吧!

目录

一.实现原理

二.代码实现

(一)思路

(二).代码


一.实现原理

其实,在小编看来,迪杰斯特拉算法与普里姆算法有些异曲同工之妙,建议大家可以先看看学懂最小生成树(普里姆算法)

这篇文章,这样更有利于理解迪杰斯特拉算法。

回到正文,迪杰斯特拉算法其实是一种贪心算法。其原理是从起点顶点(源点)出发,确定其到每个顶点的最短路径,直到确定到终点顶点(终点)为止,此时从顶点开始确定的这条路径就是最短路径。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCx6KaBIOWuheWcqOWutg==,size_20,color_FFFFFF,t_70,g_se,x_16

.代码实现

(一)思路

我们需要三个“工具”数组。一个是用来判断每个顶点是否已经确定最短路径,设为judge[],可以用bool类型的数组,确定就是true,没确定就是false;另一个用来确定到每个顶点的最短的上一个顶点下标(直接前驱顶点),设为vexsub[],所以类型是int存下标;最后一个用来存放源点到每一个顶点的最小路径的权值和,设为path[],所以类型是int存权值。

实现思路与普里姆算法异曲同工。

初始化:先将源点到每个顶点的路径放入path中,利用邻接矩阵实现即可,将源点所在行的权值放入path中。judge中全部存放false,因为尚未确定最短路径,但源点的judge要设成true。vexsub中全部存放源点下标,因为path中的值都是由源点直接指向的。

主循环过程:循环的结束条件设成直到终点的judge变成true为止,即找到到终点的最短路径。

在path中找到最小的一条路径,将路径终点的顶点的judge设为true,因为path中存放的是能到这个顶点的最小路径。

再将该终点到每一个顶点a的权值加上源点到该终点的权值之和与path中到点a的值相比,如果小就替换path中该值。这一步可能是这里头最难理解的,什么意思呢,上图来解释:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCx6KaBIOWuheWcqOWutg==,size_20,color_FFFFFF,t_70,g_se,x_16

 由上图可知当确定c的最短路径是a->c后,a->c加c->b的权值小于原先path里存的a->b的值,所以把path中b的下标所在的值变成了a->c+c->b。

我们在实现寻找最短路径时,只需找到终点的上一个前驱,前驱的上一个前驱...直到源点为止即可。(可以用递归来实现打印)。

上代码吧!

(二).代码

#define MAXVEX 100
#define Maxnum 99
typedef char vextype;
typedef struct UND//邻接矩阵
{
	int form[MAXVEX][MAXVEX];
	int vexnum, arcnum;
	vextype list[MAXVEX];
}UND;
void Shortest_Path_DIJ(UND* u);//最短路径,迪杰斯特拉
void print(int* msub, int head, int tail, UND* u);
void Shortest_Path_DIJ(UND* u)//最短路径,迪杰斯特拉
{
	cout << "-------------Short Path--------------\n";
	char c1, c2;
	cout << "头顶点:"; cin >> c1;//自主选择起点终点
	cout << "尾顶点:"; cin >> c2;
	int head = Findvex(u, c1);
	int tail = Findvex(u, c2);
	int mpath[MAXVEX];//mini path
	int msub[MAXVEX];//mini path sub
	bool jp[MAXVEX] = { false };//judge path
	for (int i = 0; i < u->vexnum; i++)//初始化
	{
		mpath[i] = u->form[head][i];
		msub[i] = head;
	}
	jp[head] = true;
	while(!jp[tail])//主循环
	{
		int mininum = Maxnum, minisub;
		for (int i = 0; i < u->vexnum; i++)//找到此时能到每个点最小路径的最小值
		{
			if (!jp[i] && mpath[i] < mininum)
			{
				mininum = mpath[i];
				minisub = i;
			}
		}
		jp[minisub] = true;//走过的路径要声明已确定最小值
		for (int i = 0; i < u->vexnum; i++)//新走过的顶点到未走点的路径与存在的到该点的最小路径之和
		{
			if (!jp[i] && mpath[minisub] + u->form[minisub][i] < mpath[i])//判断路径小的条件
			{
				mpath[i] = mpath[minisub] + u->form[minisub][i];
				msub[i] = minisub;
			}
		}
	}
	//打印最小路径
	print(msub, head, tail, u);
	cout << endl;
}
void print(int* msub, int head, int tail, UND* u)//递归打印
{
	if (head == tail)
	{
		cout << u->list[head];
		return;
	}
	print(msub, head, msub[tail], u);
	cout << "->" << u->list[tail];
}

创作不易,看在更新频率的面子上,给博主三连回回血吧,求求啦~😙     如有错误,敬请斧正

  • 29
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就要 宅在家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值