图的最短路径之Dijkstra求单源最短路径算法(C++)

一个有向带权图求它的单源最短路径可以使用Dijkstra算法。

单源最短路径是指:从图中的某个顶点出发,到其余各个顶点权值最小的路径。

Dijkstra算法需要用到三个辅助数组:

  • dist[max]:记录当前出发点v到其余各个点的最短权值之和(包括自己,为0);
  • path[max]:记录当前每个结点在最短权值路径的状态下的前驱结点;
  • s[max]:记录当前状态下的每个结点是否被访问过,访问过为1,没访问为0;

(max为图的顶点数)

Dijkstra算法由于要不断地访问顶点之间的边的信息,所以更适合将图用邻接矩阵进行存储。

本文关于Dijkstra算法的思想就不再赘述,主要是分享Dijkstra算法的代码实现。

算法的核心代码:

void Dijkstra(Mgraph G,int v) {
	int num = 0;
	int min = 0;
	int s[MAX];
	int dist[MAX];
	int path[MAX];
	for (int i = 0; i < G.vexnum; i++)
	{
		dist[i] = G.arc[v][i];
		if (dist[i] != INF) path[i] = v;
		else path[i] = -1;
	}
	for (int i = 0; i < G.vexnum; i++)
	{
		s[i] = 0;
	}
	s[v] = 1;
	num = 1;
    //在未访问的结点中更新dist和path数组以及s数组
	while (num < G.vexnum)
	{
		min = FindMinDist(dist, s, G); //寻找最小的权值结点
		s[min] = 1;
		for (int i = 0; i < G.vexnum; i++)
		{
			if (s[i] == 0 && (dist[i] > dist[min] + G.arc[min][i]))
			{
				dist[i] = dist[min] + G.arc[min][i];
				path[i] = min;
			}
			
		}
		num++;
	}
    //打印输出结果:
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << dist[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << path[i] << " ";
	}
}

完整代码:
 

#include<iostream>
using namespace std;
#define MAX 9
#define INF 9999
typedef struct Mgraph {
	char Vexnum[MAX]; //图的顶点信息
	int arc[MAX][MAX];//二维数组存储顶点之间的边的权值信息
	int vexnum;//图的顶点数
	int edgenum;//图的边数
};
//创建图
void CreatM(Mgraph& G)
{
	int i, j, w;
	cout << "请输入图的顶点数和边数" << endl;
	cin >> G.vexnum >> G.edgenum;
	cout << "请输入顶点信息" << endl;
	for (int i = 0; i < G.vexnum; i++)
	{
		cin >> G.Vexnum[i];
	}
	//初始化二维数组的边的权值为INF
	for (int i = 0; i < G.vexnum; i++)
	{
		for (int j = 0; j < G.vexnum; j++)
		{
			if(i == j) G.arc[i][j] = 0;
			else G.arc[i][j] = INF;
		}
	}
	//更改二维数组中边的权值为输入进来的权值
	for (int k = 0; k < G.edgenum; k++)
	{
		cout << "请输入边(Vi,Vj)的下标i,j和权重w: " << endl;
		cin >> i >> j >> w;
		G.arc[i][j] = w;
	}
}
void MyPrint(Mgraph G) {
	cout << "创建的图的邻接矩阵如下所示: " << endl;
	for (int i = 0; i < G.vexnum; i++)
	{
		for (int j = 0; j < G.vexnum; j++)
		{
			cout << G.arc[i][j] << "   ";
		}
		cout << endl;
	}
}
//在dist数组中找s[i] = 0,权值最小的数组下标。
int FindMinDist(int *pdist,int *s, Mgraph G) {
	int num = G.vexnum;
	int min = INF;
	for (int i = 0; i < num; i++)
	{
		if (pdist[i] < min && s[i] == 0)
		{
			min = i;
		}
	}
	return min;
}
//算法核心
void Dijkstra(Mgraph G,int v) {
	int num = 0;
	int min = 0;
	int s[MAX];
	int dist[MAX];
	int path[MAX];
	for (int i = 0; i < G.vexnum; i++)
	{
		dist[i] = G.arc[v][i];
		if (dist[i] != INF) path[i] = v;
		else path[i] = -1;
	}
	for (int i = 0; i < G.vexnum; i++)
	{
		s[i] = 0;
	}
	s[v] = 1;
	num = 1;
	while (num < G.vexnum)
	{
		min = FindMinDist(dist, s, G);
		s[min] = 1;
		for (int i = 0; i < G.vexnum; i++)
		{
			if (s[i] == 0 && (dist[i] > dist[min] + G.arc[min][i]))
			{
				dist[i] = dist[min] + G.arc[min][i];
				path[i] = min;
			}
			
		}
		num++;
	}
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << dist[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << path[i] << " ";
	}
}
int main() {
	Mgraph G;
	CreatM(G);
	//MyPrint(G);
	Dijkstra(G,0);
	return 0;
}

执行结果:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值