数据结构 c语言 Dijkstra算法寻找最短路径 邻接表实现

  • Post author:
  • Post category:其他



提示:部分内容我设置了隐藏,点赞之后会自动显示



仅供借鉴参考,请勿抄袭



有不足的地方希望大佬能为我指出

依然是这周数据结构的ddl,这周的作业真的是太舒服了,一会儿就结束了
正好昨天刚买了一本科幻小说集可以有时间看了
nice



原题:

在这里插入图片描述



我遇到的问题

1.我定义了好几个数组用来记录目前的最短路径的数据,包括长度等,
实际上可以定义一个结构来记录,会比较清楚,不至于像我一样定义一堆变量和数组
2.再刷新权值信息时,一定要注意判断条件:
包括权值的比较,这个节点是否已被找到等,不然结果错的很诡异qaq
3.循环一轮之后最小值要刷新。



实现代码:



头文件 宏和结构的定义

#include<stdio.h>
#include<stdlib.h>
#define MAX_VER_TEX 20//定点的最大个数 
#define VertexType int 
#define ERROR -1
#define OK 0
#define MAX 10000
//typedef enum
//{	Digraph,//有向图 
//	Undigraph//无向图 
//}GraphKind;
typedef struct ArcNode{//弧结点结构 
	int adjvex;//本弧指向的结点的位置
	struct ArcNode *nextarc;//指向下一个弧的指针
	int weight;//权值 
}ArcNode;

typedef struct VNode{//定点结构
	VertexType data; //储存结点的信息 
	ArcNode* firstarc;//指向第一条弧的指针 
}VNode,AdjList[MAX_VER_TEX];
typedef struct{	//图的结构
	AdjList vertexs;//储存顶点的数组
	int vexnum;//顶点个数 
	int arcnum;//边的个数
	//GraphKind kind;//图的种类  
}ALGraph;



有向图操作相关子函数

	int Locate(ALGraph g,VertexType elem)//定位这个结点在数组中的位置
{	int i;
	for(i=0;i<g.vexnum;i++)
	{	if(elem==g.vertexs[i].data)
		return i; 
	}
	return ERROR;//找不到对应元素,返回-1表示不存在 
}
int CreateAlgraph(ALGraph *g)//输入图结构,图的顶点个数,边个数
{	
	int i;
	int a,b,c,pa,pb;
	ArcNode* p;
	printf("输入图的有关信息,\n输入格式:图顶点个数+空格+边个数\n");
	scanf("%d %d",&(g->vexnum),&(g->arcnum));
	printf("下面请输入第一个顶点信息:");
	for(i=0;i<g->vexnum;i++)
	{	scanf("%d",&g->vertexs[i].data);
		g->vertexs[i].firstarc=NULL;
		if(i!=g->vexnum-1)
		{	printf("请输入下一个结点的信息:");
		}
	}
	printf("下面输入第一条边的信息,\n输入格式:起点的信息+空格+终点的信息+权值\n");
	for(i=0;i<g->arcnum;i++)
	{	scanf("%d %d %d",&a,&b,&c);
		pa=Locate(*g,a);//起点在数组里的位置 
		pb=Locate(*g,b);//终点在数组里的位置
		if(pa<0||pb<0)
		{	printf("这个边并不存在,请重新输入\n");
			i--;
			continue; 
		}
		p=(ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex=pb;
		p->weight=c;
		//下面把这个边信息插到起点的弧信息的第一个 
		p->nextarc=g->vertexs[pa].firstarc;
		g->vertexs[pa].firstarc=p;
		if(i!=g->arcnum-1)
		printf("请输入下一条边的信息:"); 
		
	}
} 
void PrintOutAlgraph(ALGraph g)
{	int i,j=1;
	ArcNode *p;
	printf("\n*---------分割线---------*\n");
	printf("这个图共有%d个顶点%d条边:\n",g.vexnum,g.arcnum); 
	printf("这个图的顶点信息:\n");
	for(i=0;i<g.vexnum;i++)
	{	printf("该图结构的第%d个顶点的信息是%d\n",i+1,g.vertexs[i].data);
	}
	printf("这个图的边信息:\n");
	for(i=0;i<g.vexnum;i++)
	{	p=g.vertexs[i].firstarc;
		while(p)
		{	printf("第%d条边:(%d ,%d) 权值为:%d\n",j,g.vertexs[i].data,g.vertexs[p->adjvex].data,p->weight);
			j++;
			p=p->nextarc;
		}
	 }
	printf("*---------分割线---------*\n");  
}
//插入一个顶点,返回顶点在图数组里的位置,如果该顶点已经存在,或者数组已满返回-1; 
int InsertArc(ALGraph *g,int a,int b,int aweight)
{	int pa,pb;
	ArcNode*p;
		pa=Locate(*g,a);//起点在数组里的位置 
		pb=Locate(*g,b);//终点在数组里的位置
		if(pa<0||pb<0)
		{	printf("这个边并不存在,请重新输入\n");
			return ERROR;
		}
		p=(ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex=pb;
		p->weight=aweight;
		//下面把这个边信息插到起点的弧信息的第一个 
		p->nextarc=g->vertexs[pa].firstarc;
		g->vertexs[pa].firstarc=p;
		g->arcnum++;//边个数增加 
		return OK;
}
int DeleteArc(ALGraph *g,int a,int b)
{	int pa,pb;
	ArcNode *p,*temp;
	pa=Locate(*g,a);//起点在数组里的位置 
	pb=Locate(*g,b);//终点在数组里的位置
	if(pa<0||pb<0)
		return ERROR;
	p=g->vertexs[pa].firstarc;
	if(p->adjvex==pb)//p为头结点的情况 
		 {	temp=p;
		 	free(temp);
		 	g->vertexs[pa].firstarc=p->nextarc;
		 }

	while(p->nextarc!=NULL)
		{	if(p->nextarc->adjvex==pb)
			{	temp=p->nextarc;
				p->nextarc=temp->nextarc;	
				free(temp);
				break;
			}			
			p=p->nextarc;
		}
	g->arcnum--;//边个数减一 
	return OK;
		 
 } 
int InsertVex(ALGraph *g,int adata)
{	int i;
	if(g->vexnum==MAX_VER_TEX)
	return ERROR;
	for(i=0;i<g->vexnum;i++)
	{	if(adata==g->vertexs[i].data)
		return ERROR;
	}
	g->vertexs[g->vexnum].data=adata;
	g->vertexs[g->vexnum].firstarc=NULL;
	g->vexnum++;//顶点个数增加 
	return g->vexnum-1;
}
int Delete(ArcNode *p)//删除顶点的辅助函数:递归调用删除弧结点内容 
{	if(p)
	{
		Delete(p->nextarc);
		free(p);
		return OK;
	}
	else 
		return NULL;
}
int DeleteVex(ALGraph *g,VertexType adata)
{	int qq=0;
	ArcNode *p,*del,*pre;
	int pdata=Locate(*g,adata);//定位结点位置 
	if(pdata<0)//结点不存在,返回错误信息 
	return ERROR;
	//Delete(g->vertexs[pdata].firstarc);//删除这个结点储存的弧信息
	p=g->vertexs[pdata].firstarc;
	while(p)
	{	g->arcnum--;
		p=p->nextarc;
	 } 
	int i;
	for(i=pdata;i<g->vexnum-1;i++)//数组内容移位 
	{	g->vertexs[i].data=g->vertexs[i+1].data;
		g->vertexs[i].firstarc=g->vertexs[i+1].firstarc;//顶点信息和第一条弧的指针都移位 
	}
	g->vertexs[g->vexnum-1].data=-1;
	g->vertexs[g->vexnum-1].firstarc=NULL;
	g->vexnum--;//顶点个数减1 
	for(i=0;i<g->vexnum;i++)
	{	p=g->vertexs[i].firstarc;
		while(p)
		{	if(p->adjvex==pdata)
			{	
				if(p==g->vertexs[i].firstarc)
				{	del=p;
					p=p->nextarc;
					g->vertexs[i].firstarc=p;
					pre=NULL;
					free(del);
					g->arcnum--;
					break;
				}
				else
				{	del=p;
					p=p->nextarc;
					pre->nextarc=p;
					free(del);
					g->arcnum--;
					break;
				}
			}
			else if(p->adjvex>pdata)
			{	p->adjvex--;
			}
			pre=p;
			p=p->nextarc;
		}
		
	}
	return OK; 
}
int GetWeight(ALGraph g,VertexType a,VertexType b )//获取权值 
{	int pa,pb;
	pa=Locate(g,a);
	pb=Locate(g,b);
	ArcNode* p;
	p=g.vertexs[pa].firstarc;
	while(p!=NULL)
	{	if(p->adjvex==pb)
		return p->weight;
		else
		p=p->nextarc;
	}
	return -1;
}



Dijkstra算法函数

void Dijkstra(ALGraph g,VertexType start)
{	int i,j,min,minnum,pa;
	int sumweight[g.vexnum];//目前起始点到该点路径的权值和 
	int lastroad[g.vexnum];//当前最短路径 
	int lastnum; //当前最短路径长度
	int lastweight=0;//当前最短路径权值 
	int judge[g.vexnum]={0};//判断该点是否已经找到路径 
	sumweight[pa]=0;
	lastroad[0]=start;
	 
	//初始化操作 
	pa=Locate(g,start); 
	lastnum=1;
	lastroad[0]=start;
	judge[pa]=1;
	for(i=0;i<g.vexnum;i++)
	{	if(judge[i]==1)//已经找到 
		continue;
		sumweight[i]=lastweight+GetWeight(g,start,g.vertexs[i].data);//刷新权值表 
	}

for(j=1;j<g.vexnum;j++)	
{
	min=MAX;
	for(i=0;i<g.vexnum;i++)
	{	if(sumweight[i]>0&&judge[i]==0&&sumweight[i]<min)
			{	min=sumweight[i];//找到权值最小 
				minnum=i; //权值最小的位置 
			}	
	}
	//向最短路径数组中增加 
	printf("%d-->%d:",lastroad[0],g.vertexs[minnum].data);
	for(i=0;i<lastnum;i++)
	{
		printf("%d--->",lastroad[i]);
	}
	printf("%d 总权值为%d\n",g.vertexs[minnum].data,sumweight[minnum]);
	judge[minnum]=1;
	lastroad[lastnum]=g.vertexs[minnum].data;
	lastweight=sumweight[minnum]; 
	lastnum++;
	start=g.vertexs[minnum].data;
	for(i=0;i<g.vexnum;i++)
	{	if(judge[i]==1)//已经找到 
		continue;
		if(GetWeight(g,start,g.vertexs[i].data)!=-1&&(GetWeight(g,start,g.vertexs[i].data)+lastweight<sumweight[i]||sumweight[i]==-1))
		sumweight[i]=lastweight+GetWeight(g,start,g.vertexs[i].data);//刷新权值表 
	}
}
}



测试函数

int main()
{	ALGraph test;
	CreateAlgraph(&test);
	PrintOutAlgraph(test);
	Dijkstra(test,1);
	
}



输入和输出



相关数据:


最后测试的数据我采用了课件上的一个强连通图


在这里插入图片描述

输入大家自行输入,
也可用我的:5 7 1 2 3 4 5 1 2 10 2 3 50 4 3 20 5 4 60 1 5 100 3 5 10 1 	4 30



输出结果:

在这里插入图片描述



版权声明:本文为m0_46743327原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。