Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

这篇具有很好参考价值的文章主要介绍了Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、文章说明:
  1. C++语言实现;
  2. 有向图的存储结构为: 邻接矩阵;
  3. 这篇文章的代码是我根据B站UP主懒猫老师所写的,能成功运行,VS里面显示有很多警告。而且还可能存在有未调试出的BUG,请多多指教。
  4. 观看懒猫老师的视频后,才方便理解博主代码,不然可能理解起来会很吃力。
二、 算法思想与实现思路:

请前往B站观看 up主 懒猫老师 的教学视频;
——附:老师思路清楚,并且通过形象的PPT动画来模拟算法实现过程,非常有利于理解整个算法过程!

视频链接:
1.算法思想:
懒猫老师-数据结构-(46)最短路径(Dijkstra算法,迪杰斯特拉算法,单源最短路径)

2.算法实现过程:
懒猫老师-数据结构-(47)最短路径(Dijkstra算法实现,迪杰斯特拉算法,单源最短路径)

三、3个核心函数:

1.迪杰斯特拉算法函数;

void Dijkstra(AMGraph g)
{
	int start;
	char c;
	cout << "请输入最小路径的源点:" << "\t";
	cin >> c;                                                
	start = g.Locate_vex(c);                                        //利用定位函数查找源点在顶点表当中的序号;

	//1.用动态分配的方式,为路径path, 路径权值dist, 算法思想中的S数组开辟空间。
	//注意这里path,dist,S数组单元的序号所对应的顶点和类 AMGraph中顶点表 vexs 所对应的顶点是一样的!

	int* path = new int[g.vexnum];                                  //空间大小为 图的顶点个数,vexnum;
	int* dist = new int[g.vexnum];
	int* S = new int[g.vexnum];


	//2. 初始化这三个数组;
	for (int i = 0; i < g.vexnum; i++)
	{
		dist[i] = g.arcs[start][i];
		if (dist[i] != Maxlnt) path[i] = start;
		else path[i] = -1;
	}

	for (int i = 0; i < g.vexnum; i++)
	{
		S[i] = 0;                                                    // 0代表未进入算法思想的S集合,1代表已经进入。
	}
	S[start] = 1;                                                    // 将源点加入S集合。
	int num = 1;                                                     //计数变量,循环控制条件;
	int min;

    //3. 正式进入算法,求源点到其它顶点的最短路径。
	while (num < g.vexnum)
	{
		min = findMinDist(dist, S, g.vexnum);                        //查找在当前顶点所邻接后继结点的边中,具有最小权值的后继结点的序号。
		S[min] = 1;
		for (int i = 0; i < g.vexnum; i++)                           //对路径数组path 和路径权值数组dist 进行更新。
		{
			if ((S[i] == 0) && (dist[i] > dist[min] + g.arcs[min][i]))
			{
				dist[i] = dist[min] + g.arcs[min][i];
				path[i] = min;
			}
		}
		num++;
	}
	displayPath(dist, path, start, g);
	delete[]path;
	delete[]dist;
	delete[]S;
}

2.findMinDist()函数;
函数功能:
查找当前结点与后继邻接顶点中具有最小权值的边,的邻接顶点的序号

int findMinDist(int dist[], int S[], int n)
{
	int MIN = Maxlnt + 1;
	int mark = -1;
	for (int i = 0; i < n; i++)
	{
		if (S[i] == 0)
		{
			if (dist[i] < MIN)
			{
				MIN = dist[i];
				mark = i;
			}
		}
	}
	return mark;
}

3. 路径输出函数displayPath();
函数功能:

  • 一、如果对于除了源点的其它顶点,如果源点是可达该顶点的,则输出其的最小路径和权值
  • 二、输出源点所到达不了的顶点,说明这源点和这个顶点之间不存在有最短路径。
void displayPath(int dist[], int path[], int start, AMGraph g)
{
	char* road = new char[g.vexnum];
	int number;                                      //number 用来表示源点到第i号顶点路径的长度;
	for (int i = 0; i < g.vexnum; i++)
	{
		int j = i;                                   //这里j可以从充当一个指针,一开始指向每条路径的终点。
		if (j != start && dist[j] != Maxlnt)         //注意这里j指向的终点必须是可达源点的,所以要加上判断条件 dist[j] 不可以等于无穷大 Maxlnt ;
		{
			number = -1;

			//1.利用while循环,从最短路径的终点向源点逐步衍生,逐步扩大road数组
			while (g.vexs[j] != g.vexs[start])        //当j 指向源点的时候,循环结束。
			{
				number++;
				road[number] = g.vexs[j];
				j = path[j];                          //j指向当前顶点的,前驱邻接顶点。
				if (j == start)                       //如果 j 指向源点了,将源点加入road 数组,数组中存储的就是逆序的路径了,number为路径的长度。
				{
					number++;
					road[number] = g.vexs[j];
				}
			}

			//2.利用for循环,将路径数组逆序输出即可得到 源点到第 i 号顶点的最小路径。
			cout << endl << g.vexs[start] << " to " << g.vexs[i] << " " << "路径权值:" << dist[i] << "\t" << "路径为: ";
			for (int k = number; k >= 0; k--)
			{
				if (k == 0)
				{
					cout << road[k] << endl;
				}
				else cout << road[k] << "—>";
			}
			cout << endl;
		}
	}

	//3.布尔变量adjust, 用来判断源点是否有到达不了的顶点, 如果有则利用for循环输出。
	bool adjust = true;
	for (int i = 0; i < g.vexnum; i++)
	{
		if (dist[i] == Maxlnt)
		{
			adjust = false;
			break;
		}
	}
	if (adjust == false)
	{
		cout << endl << "源点:" << g.vexs[start] << "到达不了的顶点为:" << "\t";
		for (int i = 0; i < g.vexnum; i++)
		{
			if (dist[i] == Maxlnt)
				cout << g.vexs[i] << "\t";
		}
		cout << endl << endl;
	}
	delete[]road;
}
四、完整代码:

说明: 为了更方便地调试程序,我将算法具体实现写成了一个小小系统的形式,
所以代码会比较冗长,注释也比较多,阅读起来可能很不舒适。

#include<iostream>
#include<string>
using namespace std;

#define Maxlnt 32767
#define MVNum 20
#define OK 1

class AMGraph
{
private:
	char vexs[MVNum];                              //顶点表;
	int arcs[MVNum][MVNum];                        //边表;
	int vexnum, arcnum;                            //点的数量和边的数量;
public:
	bool creat_graph();
	int Locate_vex(char c);                        //顶点定位函数,定位顶点在顶点表当中的数字;
	void print();                                  // 图的信息打印函数;

	friend void displayPath(int dist[], int path[], int start, AMGraph g); // 路径输出函数;
	friend void Dijkstra(AMGraph g);


};

int AMGraph::Locate_vex(char c)
{
	for (int i = 0; i < vexnum; i++)
	{
		if (c == vexs[i]) return i;
	}
	return -1;
}

bool AMGraph::creat_graph()
{
	cout << "请依次输入图的顶点数目和边数:" << "\t";
	cin >> vexnum >> arcnum;
	cout << endl << "请依次输入" << vexnum << "个顶点:" << "\t";
	for (int i = 0; i < vexnum; i++)
	{
		cin >> vexs[i];
	}
	for (int i = 0; i < vexnum; i++)
	{
		for (int j = 0; j < vexnum; j++)
		{
			if (i == j) arcs[i][j] = 0;
			else arcs[i][j] = Maxlnt;
		}
	}
	cout << endl;
	for (int k = 0; k < arcnum; k++)
	{
		char v1, v2;
		int w;
		cout << "请分别输入第" << k + 1 << "条有向边的起点,终点和权值:" << "\t";
		cin >> v1 >> v2 >> w;
		int i = Locate_vex(v1);
		int j = Locate_vex(v2);
		arcs[i][j] = w;
	}
	return OK;
}

void AMGraph::print()
{
	cout << endl << "顶点表的信息:" << endl;
	for (int i = 0; i < vexnum; i++)
	{
		cout << vexs[i] << " ";
	}
	cout << endl << endl;
	cout << "邻接矩阵的信息为:" << endl;

	// 这里for循环 从-1 开始打印邻接矩阵表格;
	for (int i = -1; i < vexnum; i++)
	{
		for (int j = -1; j < vexnum; j++)
		{
			//i=-1的时候, 需要输出边表中,  以i为起点的边所对应的终点;
			if (i == -1)
			{
				if (j == -1)cout << " " << "\t";
				else cout << vexs[j] << "\t";
				if (j == vexnum - 1) //换行条件控制
					cout << endl;
			}

			else
			{

				//j=-1的时候,需要输出边表中,  以j为终点的边所对应的起点: 
				if (j == -1)cout << vexs[i] << "\t";
				else
				{
					if (arcs[i][j] == Maxlnt)
						cout << "∞" << "\t";
					else cout << arcs[i][j] << "\t";
					if (j == vexnum - 1) //换行条件控制
						cout << endl;
				}
			}
		}
	}
}

int findMinDist(int dist[], int S[], int n)
{
	int MIN = Maxlnt + 1;
	int mark = -1;
	for (int i = 0; i < n; i++)
	{
		if (S[i] == 0)
		{
			if (dist[i] < MIN)
			{
				MIN = dist[i];
				mark = i;
			}
		}
	}
	return mark;
}

void displayPath(int dist[], int path[], int start, AMGraph g)
{
	char* road = new char[g.vexnum];
	int number;                                      //number 用来表示源点到第i号顶点路径的长度;
	for (int i = 0; i < g.vexnum; i++)
	{
		int j = i;                                   //这里j可以从充当一个指针,一开始指向每条路径的终点。
		if (j != start && dist[j] != Maxlnt)         //注意这里j指向的终点必须是可达源点的,所以要加上判断条件 dist[j] 不可以等于无穷大 Maxlnt ;
		{
			number = -1;

			//1.利用while循环,从最短路径的终点向源点逐步衍生,逐步扩大road数组
			while (g.vexs[j] != g.vexs[start])        //当j 指向源点的时候,循环结束。
			{
				number++;
				road[number] = g.vexs[j];
				j = path[j];                          //j指向当前顶点的,前驱邻接顶点。
				if (j == start)                       //如果 j 指向源点了,将源点加入road 数组,数组中存储的就是逆序的路径了,number为路径的长度。
				{
					number++;
					road[number] = g.vexs[j];
				}
			}

			//2.利用for循环,将路径数组逆序输出即可得到 源点到第 i 号顶点的最小路径。
			cout << endl << g.vexs[start] << " to " << g.vexs[i] << " " << "路径权值:" << dist[i] << "\t" << "路径为: ";
			for (int k = number; k >= 0; k--)
			{
				if (k == 0)
				{
					cout << road[k] << endl;
				}
				else cout << road[k] << "—>";
			}
			cout << endl;
		}
	}

	//3.布尔变量adjust, 用来判断源点是否有到达不了的顶点, 如果有则利用for循环输出。
	bool adjust = true;
	for (int i = 0; i < g.vexnum; i++)
	{
		if (dist[i] == Maxlnt)
		{
			adjust = false;
			break;
		}
	}
	if (adjust == false)
	{
		cout << endl << "源点:" << g.vexs[start] << "到达不了的顶点为:" << "\t";
		for (int i = 0; i < g.vexnum; i++)
		{
			if (dist[i] == Maxlnt)
				cout << g.vexs[i] << "\t";
		}
		cout << endl << endl;
	}
	delete[]road;
}

void Dijkstra(AMGraph g)
{
	int start;
	char c;
	cout << "请输入最小路径的源点:" << "\t";
	cin >> c;                                                
	start = g.Locate_vex(c);                                        //利用定位函数查找源点在顶点表当中的序号;

	//1.用动态分配的方式,为路径path, 路径权值dist, 算法思想中的S数组开辟空间。
	//注意这里path,dist,S数组单元的序号所对应的顶点和类 AMGraph中顶点表 vexs 所对应的顶点是一样的!

	int* path = new int[g.vexnum];                                  //空间大小为 图的顶点个数,vexnum;
	int* dist = new int[g.vexnum];
	int* S = new int[g.vexnum];


	//2. 初始化这三个数组;
	for (int i = 0; i < g.vexnum; i++)
	{
		dist[i] = g.arcs[start][i];
		if (dist[i] != Maxlnt) path[i] = start;
		else path[i] = -1;
	}

	for (int i = 0; i < g.vexnum; i++)
	{
		S[i] = 0;                                                    // 0代表未进入算法思想的S集合,1代表已经进入。
	}
	S[start] = 1;                                                    // 将源点加入S集合。
	int num = 1;                                                     //计数变量,循环控制条件;
	int min;

    //3. 正式进入算法,求源点到其它顶点的最短路径。
	while (num < g.vexnum)
	{
		min = findMinDist(dist, S, g.vexnum);                        //查找在当前顶点所邻接后继结点的边中,具有最小权值的后继结点的序号。
		S[min] = 1;
		for (int i = 0; i < g.vexnum; i++)                           //对路径数组path 和路径权值数组dist 进行更新。
		{
			if ((S[i] == 0) && (dist[i] > dist[min] + g.arcs[min][i]))
			{
				dist[i] = dist[min] + g.arcs[min][i];
				path[i] = min;
			}
		}
		num++;
	}
	displayPath(dist, path, start, g);
	delete[]path;
	delete[]dist;
	delete[]S;
}

void menu()
{
	cout << "****《迪杰斯特拉算法求最短路径》*****" << endl;
	cout << "**1. 图的建立" << endl;
	cout << "**2. 输出图的信息" << endl;
	cout << "**3. 求图的最短路径" << endl;
	cout << "**4. 退出" << endl;
	cout << "____________________________________________" << endl;
}

void deletescreen()
{
	system("pause");
	system("cls");
}

int main()
{
	void menu();
	void deletescreen();
	AMGraph g1;
	//menu();
	string choose;
	while (true)
	{
		menu();
		cin >> choose;
		if (choose == "1")
		{
			g1.creat_graph();
			cout << endl << "图建立成功!" << endl;
			deletescreen();
		}
		else if (choose == "2")
		{
			g1.print();
			deletescreen();
		}
		else if (choose == "3")
		{
			Dijkstra(g1);
			deletescreen();
		}
		else if (choose == "4")
		{
			cout << "退出成功!" << endl;
			exit(0);
		}
		else
		{
			cout << "输入有误!请重新输入" << endl;
			deletescreen();
		}
	}
	return 0;
}
五、测试情况:

测试一:
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径
求图片中
1.源点为A到其它顶点的最小路径
2.源点为D到其它顶点的最小路径

测试结果:
1.建图
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

2.图的信息:
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

3.A到其它顶点的最小路径
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

4.D到其它顶点的最小路径
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径
测试二:
1.测试案例:
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

2.求以 0 作为源点,到其它顶点的最短路径:
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

感谢你的收看,希望这可以帮助到你。文章来源地址https://www.toymoban.com/news/detail-477234.html

到了这里,关于Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于邻接矩阵的有向图的广度优先遍历(BFS)和深度优先遍历(DFS)算法

    概念: 广度优先遍历算法是图的另一种基本遍历算法,其基本思想是尽最大程度辐射能够覆盖的节点,并对其进行访问。 以迷宫为例,广度优先搜索则可以想象成一组人一起朝不同的方向走迷宫,当出现新的未走过的路的时候,可以理解成一个人有分身术,继续从不同的方

    2024年02月06日
    浏览(49)
  • 有向图的拓扑排序

    拓扑排序 。任意给定一个有向图,设计一个算法,对它进行拓扑排序。拓扑排序算法思想:a.在有向图中任选一个没有前趋的顶点输出;b.从图中删除该顶点和所有以它为尾的弧;c.重复上述a、b,直到全部顶点都已输出,此时,顶点输出序列即为一个拓朴有序序列;或者直到

    2024年02月09日
    浏览(35)
  • 用go语言实现一个构建有向图的函数,同时图结构的点和边上都支持添加属性

    当然可以。下面是一个简单的用Go语言实现的有向图构建函数的示例。这个图结构使用map来存储,每个节点都由一个唯一的标识符(id)表示,并且节点和边都可以附加属性。 go 这个示例代码创建了一个有向图,并添加了两个节点(A和B)和一个从A到B的边。每个节点和边都有

    2024年01月20日
    浏览(26)
  • 有向图的强连通分量

    对于一个有向图,连通分量:对于分量中任意两点u,v,必然可以从u走到v,且从v走到u. 强连通分量:极大连通分量。 求出强连通分量后,可以通过将强连通分量缩点的方式,将有向图转化成有向无环图。 求强连通分量的方法:tarjan O(n+m),时间复杂度是线性的 1 . 采用dfs来遍历整

    2024年02月10日
    浏览(27)
  • 公开游戏、基于有向图的游戏

    目录 〇,背景 一,公开游戏、策梅洛定理 1,公开游戏 2,策梅洛定理 3,非有向图游戏的公开游戏 力扣 486. 预测赢家(区间DP) 力扣 877. 石子游戏(退化贪心) 力扣 1140. 石子游戏 II(二维DP) 力扣 1406. 石子游戏 III(数列DP) 力扣 1563. 石子游戏 V(区间DP)  力扣 1686.

    2024年02月09日
    浏览(32)
  • 2023-8-29 有向图的拓扑排序

    题目链接:有向图的拓扑排序

    2024年02月11日
    浏览(28)
  • 真题详解(有向图)-软件设计(六十二)

    真题详解(极限编程)-软件设计(六十一) https://blog.csdn.net/ke1ying/article/details/130435971 CMM指软件成熟度模型,一般1级成熟度最低,5级成熟度最高,采用更高级的CMM模型可以提高软件质量。 初始:杂乱无章。 可重复级:建立基本的项目管理过程和跟踪费用项。 已定义(确定)

    2024年02月01日
    浏览(50)
  • 搜索与图论-有向图的拓扑序列

    有向图的拓扑序列就是图的广度优先遍历的一个应用。 若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个 拓扑序列 。(起点在终点的前面) 拓扑序列是针对有向图,无向图是没有拓扑序列的。 有向无环图一定是

    2024年02月01日
    浏览(35)
  • 有向图的邻接表和邻接矩阵

    有向图的邻接表是一种常用的表示方法,用于表示图中各个节点之间的关系。在有向图中,每条边都有一个方向,因此邻接表中的每个节点记录了该节点指向的其他节点。 具体来说,有向图的邻接表由一个由节点和它们的邻居节点列表组成的集合构成。对于每个节点,邻接表

    2024年02月22日
    浏览(29)
  • 使用颜色检测有向图中的循环

    给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,您的函数应返回 true,否则返回 false。 例子:   输入:  n = 4, e = 6  0 - 1, 0 - 2, 1 - 2, 2 - 0, 2 - 3, 3 - 3  输出: 是  解释:    

    2024年02月03日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包