最短路径,说白了,就是图里从一个顶点到另一个顶点的最小权值之和。
今天,小编带大家一起用迪杰斯特拉(Dijkstra)算法实现它吧!
目录
一.实现原理
其实,在小编看来,迪杰斯特拉算法与普里姆算法有些异曲同工之妙,建议大家可以先看看学懂最小生成树(普里姆算法)
这篇文章,这样更有利于理解迪杰斯特拉算法。
回到正文,迪杰斯特拉算法其实是一种贪心算法。其原理是从起点顶点(源点)出发,确定其到每个顶点的最短路径,直到确定到终点顶点(终点)为止,此时从顶点开始确定的这条路径就是最短路径。
二.代码实现
(一)思路
我们需要三个“工具”数组。一个是用来判断每个顶点是否已经确定最短路径,设为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中该值。这一步可能是这里头最难理解的,什么意思呢,上图来解释:
由上图可知当确定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];
}
创作不易,看在更新频率的面子上,给博主三连回回血吧,求求啦~😙 如有错误,敬请斧正