C语言 单源最短路径 有权 邻接矩阵

运行结果正确
注意初始化的时候对path的特殊处理
在这里插入图片描述

#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include<malloc.h>
//邻接矩阵表示图
typedef struct g_node *g_point;
struct g_node{
	int ne;//边数 
	int nv;//节点数 
	int arr[100][100];
	int data[100];
};
//边的数据结构
typedef struct e_node *e_point;
struct e_node{
 	int v1;
 	int v2;
 	int weight;
 };
 int dist[100];
 int path[100];
 //遍历一个邻接矩阵的图
 void tra_g(g_point g,int n){
 	for(int i=0;i<n;i++){
	 	for(int j=0;j<n;j++){
	 		printf("%d ",g->arr[i][j]);
	 	}
	 	printf("\n");
	 }
 } 
 //创建一个空图
 void init(g_point &g,int v_num){
 	g=(g_point)malloc(sizeof(struct g_node));
 	g->nv=v_num;
 	g->ne=0;
 	for(int i=0;i<v_num;i++){
	 	for(int j=0;j<v_num;j++){
	 		g->arr[i][j]=1000;
	 	}
	 }
	 for(int i=0;i<v_num;i++){
 		g->data[i]=0;
 	}
 } 
 //给图插入边
 void  insert_edge(g_point &g,e_point e){
 	g->arr[e->v1][e->v2]=e->weight;
 	g->arr[e->v2][e->v1]=e->weight;
 }
 //造一张无向图 
 void  create_g(g_point &g){
 	//首先输入顶点个数
	 int v;
	 printf("请输入顶点数\n");
	 scanf("%d",&v);
	 init(g,v);
	 
	 printf("输入边数\n");
	 scanf("%d",&(g->ne));
	 //给边分配空间
	 e_point e=(e_point)malloc(sizeof(struct e_node)); 
	printf("输入边的信息\n");
	 for(int i=0;i<g->ne;i++){
	 	//把数据给边,将边插入图 
	 	
 		scanf("%d %d %d",&(e->v1),&(e->v2),&(e->weight));
 		insert_edge(g,e);
 		printf("输入下一组边\n");
 		
 	}
 	return;
 }
 //遍历dist,path
 void tra_dist_psth(g_point g, int dist[],int path[]){
 	printf("每个节点的最短路径权值为\n");
	for(int i=0;i<g->nv;i++){
	 	printf("%d ",dist[i]);
	 }
	printf("\n");
	printf("每个节点的最短路径的上一个顶点为\n");
	for(int i=0;i<g->nv;i++){
	 	printf("%d ",path[i]);
	 }
	printf("\n");
 } 
 //单源最小路径
 void dijks_tra(g_point g,int dist[],int path[],int v){
 	//建一个数组用来标记是否访问过
	 int visit[100];
	 //初始化所有数组
	 for(int i=0;i<g->nv;i++){
 		dist[i]=g->arr[v][i];
 		if(g->arr[v][i]<1000){
		 	path[i]=v;
		 } 
		 else{
 			path[i]=-1;
 		}
 		visit[i]=0;
 	} 
 	
 	//初始顶点加进去之后,对三个数组进行更新
	 visit[v]=1;
	 dist[v]=0;
	 //大循环
	 while(1){
	 	
 		//从所有没访问过的顶点中挑出一个dist最小的
 	   	 int min=1000;
 	   	 int min_id=0;
		 for(int i=0;i<g->nv;i++){
		 	//没访问过,但权值又要比当前最小值还要小 
 			if(visit[i]==0&&dist[i]<min){
			 	min=dist[i];
			 	min_id=i;
			 }
 		} 
 		//如果经过上述遍历之后,最小值还是1000,说明
		 //所有的顶点都被访问过了,此时结束循环
		 if(min==1000){
 			break;
 		} 
 		//此时就从当前这个最小的顶点重新开始
		 //先标记
		 visit[min_id]=1;
		 //找它的邻接点
		 for(int i=0;i<g->nv;i++){
		 	//如果邻接点没被访问过,且这次访问更新的权值比之前要小的话 
 			if(visit[i]==0&&g->arr[min_id][i]<1000){
 				if((g->arr[min_id][i]+min)<dist[i]){
				 	dist[i]=g->arr[min_id][i]+min;
			 		path[i]=min_id;
			 		
				 }
			 	
			 }
 		} 
 		
 	} 
 } 
 int main(){
 	g_point g;
 	create_g(g);
 	
 	int dist[100];
 	int path[100];
 	dijks_tra(g,dist,path,0);
 	
 	tra_dist_psth(g,dist,path);
 	return 0;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值