Dijkstra算法的深入理解以及基于堆的优化改进

Dijkstra算法的深入理解

1. 问题提出

dijkstra算法主要为了解决单源最短路径问题:给定带权有向图(带权代表着我们可以针对不同的情况对路径上的权值进行调整,以得到最符合当前需求的路径,有向则表明它要求解的路径有源点和目的点,还有它是一个图)G和源点V,求从 V 到 G 中其余各顶点的最短路径。

2. 求解过程

1.将图中的节点分为两组,一组为已求出最短路径的节点集合,另一组为还未求出最短路径的节点集合。(这有点类似与动态规划的思想,利用已知最优解,求解后续最优解)
2.按照各节点与V的最短路径长度递增的顺序,逐个将还未求出最短路径的节点加入到已求出最短路径的集合中(还未求出最短路径的节点到V的路径是不断变化的,但是未求出最短路径集合中当前距V最近的节点的路径已经可以确定是其最短路径,因为未求出最短路径的集合中其他节点到V的路径之所以会变,是因为把当前最短加入到已求出集合后对其造成的影响)

3.代码分析与实现

根据上面的求解过程,假设我们已经有了用邻接表或邻接矩阵保存的节点间路径信息,我们需要一个数组来保存bool值,即节点是否已确定最短路径,一个数组来保存还未确定最短路径的节点,若我们需要得到中间路径,则还需要一个数组来保存path路径(即其前驱节点),上述三个数组的大小均为结点的个数。

typedef struct ArcNode //代表一条边
{
   
	int adjvex; //边指向的节点
	struct ArcNode * nextarc;//下一条边
	int weight;//权重
}ArcNode;

typedef struct VNode
{
   
	char *name; //节点的名字,标识
	ArcNode * firstarc; //指向可达的第一条边的指针
}VNode;

typedef struct
{
   
	VNode vertices[num]; //图中的节点数组
	int vexnum, arcnum; //图中节点的数目,边的数目
}MyGraph;

void DIJ(MyGraph &a, int v, int *lens, int *paths)
{
   
	int n = a.vexnum; 
	int *temp = new int[n];//保存临时最短路径
	const int max = ~(1<<31);
	//初始化
	for(int i=0; i<n; i++)
	{
   
		//lens表示节点是否已确定最短路径,本来可以是一个bool的数组,
		//这里用-1表示未确定,确认后用实际的最短路径进行填充。
		lens[i] = -1; 
		temp[i] = max;//初始所有节点不可达
		paths[i] = -1;//保存源节点到目的节点的路径上,目的节点的前一个节点
	}
	ArcNode *p = a.vertices[v].firstarc;
	//使用源节点的邻接边初始化一部分路径长度以及paths
	while(p)
	{
   
		temp[p->adjvex] = p->weight;
		paths[p->adjvex] = v;
		p = p->nextarc;
	}
	lens[v] = 0;
	paths[v] = 0;
	//开始主循环,每次求得源点到某个顶点的最短路径,并将此节点加入到已确定最短路径的集合中
	for(int i=1; i<n; i++)
	{
   
		int index = -1;
		int min = max;
		//选择一条当前最短路径
		for(int j=0; j<n; j++)
		{
   
			if(lens[j] < 0 && temp[j] < min)
			{
   
				min = temp[j];
				index = j;
			}
		}
		if(index == -1)//若没有可达路径,则退出
			break;
		lens[index] = min;//设置节点最短路径为已确定,并将最短路径保存起来
	
		//根据新确定最短路径的节点的邻接边,更新临时最短路径
		ArcNode *q = a.vertices[index].firstarc;
		while(q!=nullptr)
		{
   
			//若更小,则更新
			if(lens[
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值