迪杰斯特拉算法(图示+C语言实现)

迪杰斯特拉是单源最短路算法(即只能求一点,到其他任一点的最短路径,但可以加循环得到任意两点间的最短路径),无法处理带负权变的图

算法思路图示

初始化两个集合
S={A}(只包含源点,表示已经确定最短路径的节点,一旦S中包含所有元素那么算法终止)
U={B,C,D,E,F,G}

(1)初始化,所有距离初始化为无穷大

在这里插入图片描述

(2)选定点A,更新(A-A距离设为0)

在这里插入图片描述

(3)S集合为{A,B},考察B的所有邻接点

为什么选定B加入集合S?
因为不可能还有其他路径比2还短,我不管经过C到B还是D到B都不可能是路径小于2,所以我们得到了A->B的最短路径
在这里插入图片描述
做完这一步,下一步加入集合S的是D
因为目前A->D的路径长度最短,为3(我已经知道了A直接到D和A经过B到D的路径长度)
如果A->B->X->D小于min{A->D,A->B->D},那么A->B->X小于min{A->D,A->B->D},那么加入集合的应该是X,这是矛盾的(接下来的操作都是一样的道理)

(4)S集合为{A,B,D},在U中没有D的邻接点,不操作

(5)S集合为{A,B,D,C},在U中没有C的邻接点,不操作

(6)S集合为{A,B,D,C,F},更新在这里插入图片描述

(7)S集合为{A,B,D,C,F,E},在U中没有E的邻接点,不操作

(8)S集合为{A,B,D,C,F,E,G},在U中没有G的邻接点,不操作

代码实现:

#include <stdio.h>
#include <malloc.h>
#define MaxVex 1000 
typedef struct graph{
 int vnum, ednum;//顶点的个数,边的个数
 char vexs[MaxVex];  //用来存顶点数据
 int edges[MaxVex][MaxVex]; //用来存边的权值(两点代替一边)
}Mgraph,*Graph;
void create(Graph &g){
	g = (Graph)malloc(sizeof(Mgraph));
	printf("请输入顶点的个数\n");
	scanf("%d",&g->vnum);
	printf("请输入边的个数\n");
	scanf("%d",&g->ednum);
	
	printf("请输入顶点的信息\n");
	for(int i=0;i<g->vnum;i++){
		getchar();
		scanf("%c",&g->vexs[i]);
	}
	printf("请输入边的起点,终点和权值\n");
	for(int i=0;i<g->vnum;i++)
		for(int j=0;j<g->vnum;j++) {
		if(i!=j)	g->edges[i][j] = MaxVex;//初始化 
		else g->edges[i][i] = 0;
	}
	int start,end,value;
	for(int i=0;i<g->ednum;i++){
		scanf("%d%d%d",&start,&end,&value);
		g->edges[start][end] = value;
	}
}
void print(Graph g){
	for(int i=0;i<g->vnum;i++)
		for(int j=0;j<g->vnum;j++) 
		printf("%d ",g->edges[i][j]);
} 
void shortPath(int *path,Graph g,int start){//start为源点的下标 
	bool s[g->vnum];//S集合
	int dist[g->vnum]; 
/*
  初始化的过程,只能走一步的最短路径,对应图片第一张和第二张 
*/
	for(int i = 0;i<g->vnum;i++){
		s[i] = false;//初始化S集合,为空 
		dist[i] = g->edges[start][i];//初始化,源点到各个点的距离,不能直接到达值为MAX 
		if(dist[i]<MaxVex){
			path[i] = start;//能到达将这个点的前一点设为start; 
		}  else{
			path[i] = -1; //否则用-1表示不能到达 
		} 
	}
	 s[start] = true;//将源点加入S集合 
	 dist[start] = 0;
/*
  初始化结束,开始主过程 
*/	 
for(int i=1;i<g->vnum;i++){//除去源点,对剩下的每个点求最短路径 
    	int min = MaxVex; 
    	int v; //用来表示点 
    	//选择最短路径 
	for(int j = 0;j<g->vnum;j++){ 
	  if(s[j]==false&&dist[j]<min){//如果点在U集合里,且可以直接到达
	      v = j; //选择一条路径 
	      min = dist[j];//不断更新min和j,找到最小的min 
	  }
	} 
	s[v] = true;//将该点加入S集合
	for(int k=0;k<g->vnum;k++){
		if(s[k]==false&&(dist[v]+g->edges[v][k])<dist[k]){
			dist[k]=g->edges[v][k]+dist[v];
			path[k]=v;
		}
	} 
}

 for(int i = 0;i<g->vnum;i++) printf("%d ",dist[i]);
 printf("\n");
}
 

int main(){	
	Graph g;
	create(g);
	int path[g->vnum];
    shortPath(path,g,0);
    for(int i=0;i<g->vnum;i++) printf("%d ",path[i]); 
	return 0;
} 

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值