Dijkstra算法笔记

Dijkstra算法

       迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

图片以及案例来自简书的这篇博客https://www.jianshu.com/p/ff6db00ad866

 

#include<stdio.h>
#include<iostream>
#include<math.h>
#define INF 1e5+10  //此值当作无穷大
const int size=5;  //地点个数,即地图尺寸大小
/*
1.指定一个节点,例如我们要计算 'A' 到其他节点的最短路径
2.引入两个集合(S、U),S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点(以及A到该点的路径,注意 如上图所示,A->C由于没有直接相连 初始时为∞)
3.初始化两个集合,S集合初始时 只有当前要计算的节点,A->A = 0,
U集合初始时为 A->B = 4, A->C = ∞, A->D = 2, A->E = ∞,敲黑板!!!接下来要进行核心两步骤了
4.从U集合中找出路径最短的点,加入S集合,例如 A->D = 2
5.更新U集合路径,if ( 'D 到 B,C,E 的距离' + 'AD 距离' < 'A 到 B,C,E 的距离' ) 则更新U
6.循环执行 4、5 两步骤,直至遍历结束,得到A 到其他节点的最短路径
*/
typedef struct Graph_data  //地图数据结构体类型
{
	int mat[size][size];
	int fmat[size][size];//用于判断走最短路径时是否会结束此段i-j路径 
	int vnum;  //点数
	int edgenum;  //边数
	char vname[size];
} graph;

typedef struct Process_data
{
	int process[size];  //该数组用来存储行走路径的过程
	char name; 
	int dist;
	int prev;  //记录i点的前一点是谁
} ps; //可以理解成每个点的状态

void dijkstra(graph G,ps v[],int vs)
{
	//初始化
	int ok=1;
	int flag[size]={0};
	int fmat[size][size]={0};
	memcpy(G.fmat,fmat,sizeof(fmat));
	flag[vs]=1;
	int process[size]={0};
	for(int i=0;i<G.vnum;i++)
	{
		memcpy(v[i].process,process,sizeof(process));//初始化过程数组 
		v[i].dist=G.mat[vs][i];  //i点到起点的距离
		v[i].name=G.vname[i];
		v[i].prev=vs;
	}
	//遍历整张图,找到每个点的最短路径及其长度 
	int k=vs;
	while(ok)
	{
		ok=0;
		int min=INF,tmp;
		for(int i=0;i<G.vnum;i++)
		{
			if(flag[i]==0&&v[i].dist<min) //如果到i的距离不是最短的且当前i的距离小于min则该路径是当前最短的,就要选择该点i
			{
				k=i;
				min=v[i].dist;
			}
		} 
		flag[k]=1;//遍历更新为已遍历,即更新集合S
	    //注意理解遍历更新,尤其理解C点的最短路径和E点的最段路径的过程 
        //以下循环作用是更新集合U
		for(int i=0;i<G.vnum;i++)
		{
			tmp=(G.mat[k][i]==INF?INF:(min+G.mat[k][i]));
			if(flag[i]==0&&tmp<v[i].dist)
			{
				v[i].prev=k;
				v[i].dist=tmp;
				G.fmat[k][i]=1;
			} 
		}
		//判断是否都已遍历 
		for(int i=0;i<G.vnum;i++)
			if(flag[i]==0) ok=1;
	}
	//将过程输入结构体的process数组中 
	for(int i=0;i<G.vnum;i++)
	{
		int tp=i,j=size-1;
		while(tp!=vs)
		{
			v[i].process[j--]=tp;
			tp=v[tp].prev;
		}
	} 
}

int main()
{
	graph G;
	int vs=0;//起点 
	int mat[5][5]={
	{0  ,4  ,INF,2  ,INF},
	{4  ,0  ,4  ,1  ,INF},
	{INF,4  ,0  ,1  ,3  },
	{2  ,1  ,1  ,0  ,7  },
	{INF,INF,3  ,7  ,0  }
	};//输入无向图 
	memcpy(G.mat,mat,sizeof(mat));
	G.vnum=size;
	G.edgenum=7;
	char vname[5]={'A','B','C','D','E'};
	memcpy(G.vname,vname,sizeof(vname));
	ps v[size];
	dijkstra(G,v,vs);
	
	for(int i=1;i<G.vnum;i++)
	{
		printf("The distance of %c is %d\t",G.vname[i],v[i].dist);
		printf("%c-",G.vname[vs]); 
		for(int j=0;j<G.vnum;j++)
		{
			if(v[i].process[j]!=vs)
			{
				printf("%c%c",G.vname[v[i].process[j]],(v[i].process[j]==i?'\0':'-'));
			}
		} 
		printf("\n");
	}
	return 0;
} 

运行结果:

typedef与#define的比较

以上代码中涉及到一些typedef的用法,此博客对这个知识点有很透彻的介绍:

http://blog.sina.com.cn/s/blog_4826f7970100074k.html

在此博客讲到了#define来替换数据类型名称时只是简单的替换了对应字符串,在这一功能的实现上typedef要比#define更靠谱,我们来通过以下列子来比较:

#define PINT int*
typedef int* pint
//a,b都为int*类型
pint a,b;
//预处理时替换为int* c,d;则c为int* 类型,而d为int类型
PINT c,d;

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值