【数据结构】最短路径问题之Dijkstra算法

Dijkstra算法是求解图中单源点最短路径的一种算法,其实现过程类似于Prim算法。顾名思义,“单源点最短路”说明实现功能需要指定源点,并且该算法仅支持各边权值为正数的情况!

基本知识

路径第一个点称“源点”,最后一个点称”终点“。
最短路径指的是两个顶点间经历边数最少的路径。

基本思路

将顶点集合V分成两个集合,一类是生长点的集合S(包括源点和已经确定最短路径的顶点);另一类是非生长点的集合 V-S(包括所有尚未确定最短路径的顶点),并使用一个待定路径表,存储当前从源点V到每个非生长点的最短路径。

存储结构

邻接矩阵存储图,dis数组存储当前最短路径长度,待定路径表path存储表示路径的顶点序列

加入集合用dis数组对应顶点位置置0来表示。

功能实现

与之前的各种算法类似,最短路径算法针对的是图,因此需要建图才可使用该算法。仍然使用C++面向对象的思想:

class MGraph
{
public:
   	MGraph(DataType a[ ], int n, int e);     //构造函数,建n个顶点e条边的图
   	~MGraph( ){ };                        //析构函数
	void Dijkstra(int v);
private:
    int Min(int r[ ], int n);
	char vertex[MaxSize];           //存放图中顶点
    int edge[MaxSize][MaxSize];     //邻接矩阵
    int vertexNum, edgeNum;        //图的顶点数和边数
 };
  

构造函数

与前面的算法类似,需要将图的顶点、边的信息存入类中。

MGraph :: MGraph(char a[ ], int n, int e) 
{
   	int i, j, k, w;
   	vertexNum = n; edgeNum = e;
   	for (i = 0; i < vertexNum; i++)          //存储顶点
   		vertex[i] = a[i];
   	for (i = 0; i < vertexNum; i++)          //初始化邻接矩阵,存储各边的权值
 		for (j = 0; j < vertexNum; j++)
   			if (i == j)
			   	edge[i][j] = 0;             
			else
			 	edge[i][j] = 1000;            //假设权值最大是1000 
   	for (k = 0; k < edgeNum; k++)           //依次输入每一条边
   	{
   		cout << "输入边依附的两个顶点的编号,以及边上的权值:";
		cin >> i >> j >> w;                       //输入边依附的两个顶点的编号
		edge[i][j] = w;                           //输入权值
   	}
}

核心部分

思路

如基本思路所言,初始时,S只包含源点v,对D∈V-S,待定路径表path为从源点v到D的有向边。最短路径数组dis为源点v到D的路径长度。

之后在待定路径表中找到当前最短路径并记录顶点,将新找到的最短路径的顶点加入集合S中。

对不在集合S中(D∈V-S)的点d (d∈D),将路径表中v直接到d的路径长度与经过已确定的最短路径顶点之后再到达d的路径长度相比较,取较小者为v~d的最短路径。

简言之——初始化时,源点到其他各点的dis数组的数据为邻接矩阵源点行的数据,路径path为源点依次到其余点的顶点序列。之后,更新dis数组和path数组的数据。

代码实现

void MGraph :: Dijkstra(int v)            //从v出发
{
  	int i, k, num, dist[MaxSize];
  	string path[MaxSize];
	for (i = 0; i < vertexNum; i++)            //初始化数组dis和path
	{
   		dis[i] = edge[v][i];
   		if (dis[i] != 1000)                    //假设1000为边上权的最大值
			path[i] = vertex[v] + vertex[i];       //字符串连接
   		else path[i] = "";
   	}
	for (num = 1; num < vertexNum; num++)
        //遍历剩余(n-1)个顶点
	{
		k = Min(dis, vertexNum);      //在dis数组中找最小值并返回其下标
  		cout << path[k] <<":" << dis[k] << endl;
  		for (i = 0; i < vertexNum; i++)             //修改数组dis和path数据
    		if (dis[i] > dis[k] + edge[k][i]) {
       			dis[i] = dis[k] + edge[k][i];
       			path[i] = path[k] + vertex[i];         //字符串连接
    		}
		dis[k] = 0;                            //顶点k加到集合S中
	}
}

其中,找数组最小值元素位置的函数与Prim算法中找最小值位置函数类似,均返回最小值元素的下标:

int MGraph ::Min(int r[ ], int n)
{
	int index = 0, min = 1000;
	for (int i = 0; i < n; i++)
		if (r[i] != 0 && r[i] < min)
		{
			min = r[i]; index = i;		
		}
	return index;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值