旅行无向图邻接矩阵法的建立、遍历、最小生成树、最短路径、修改名字等操作

该博客介绍了如何使用邻接矩阵来建立无向图,并实现深度优先搜索、广度优先搜索、最小生成树的构建以及最短路径查找等功能。此外,还提供了城市名称替换、航线价格修改、增加删除城市和航线等操作的代码模块和测试案例。
摘要由CSDN通过智能技术生成

题目要求:将如下无向图使用邻接矩阵的方法进行保存,并进行深搜、广搜、建立最小生成树操作。

 功能拓展:在实现要求的前提下,进行简单的名称替换、权值替换、找最短路径、删除城市、增加城市、增加航线、删除航线等操作。

模块代码:

1、定位输入城市模块:

int LocateVex(AMGraph G, VerTexType u[]) {  //查询输入的城市是否在无向图中  
	for (int i = 0; i < G.vexnum; i++)  //在图中循环将输入的城市与顶点一个个对比
		if(strcmp(u,G.vexs[i])==0) return i;  //如果输入的城市和第i个城市相同,返回i的值
	printf("你输入的城市不在该图中\n");  //如果输入的城市和顶点城市都不相同,打印"你输入的城市不在该图中",并且返回-1
	return -1;
}

2、建立无向图模块:

int CreateUDN(AMGraph& G) {  //创建一个无向的航班图 
	printf("请输入总城市数和总航班数(例如:1 1):");
	scanf("%d %d", &(G.vexnum),&(G.arcnum));  //将输入的值分别赋给图中边的个数和顶点个数
	for (int i = 0; i < G.vexnum; i++)  //利用for循环对图中的顶点进行赋值
	{
		printf("请输入第%d个城市的名称:",i+1);
		scanf("%s", &(G.vexs[i]));
	}
	for (int i = 0; i < G.vexnum; i++)  将图中所有的边初始化为无穷大
		for (int j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = MaxInt;
	for (int k = 0; k < G.arcnum; k++) {  //利用for循环和之前键入的边的个数对边进行赋值
		printf("请输入你想输出航班价格的两个城市(例如:北京 哈尔滨):");
		char v1[MVNum];  //定义两个字符数组存储输入的城市名称
		char v2[MVNum];
		scanf("%s %s", &v1,&v2);    //将两个城市名称分别赋值给v1,v2数组
		int i = LocateVex(G, &v1[0]);
		int j = LocateVex(G, &v2[0]);
		if(i==-1||j==-1){  //判断输入的城市是否不在图中,若不在图中则退出程序
			printf("输入错误,该图中没有这个城市,程序退出执行\n\n\n");
			exit(-1);
		}
		printf("请输入%s和%s两个城市之间的机票价格:",v1,v2);
		int w;  //定义一个整型变量来存储边的值
		scanf("%d",&w);  //将输入的值赋给w
		G.arcs[i][j] = w;  //由于该图是一个无向图,所以要对对称的位置都进行赋值
		G.arcs[j][i] = G.arcs[i][j];
	}
	return OK;
}

3、展示创建的邻接矩阵

char ShowUDN(AMGraph &G){  //展示创建的无向图 
	printf("        ");  //规范格式,使得输出看起来更加整齐
	for(int i=0;i<G.vexnum;i++)
		printf("%8s",G.vexs[i]);  //先将各个按顺序输入的城市名称打印出来,方便对应观察邻接矩阵
	printf("\n");  //规范格式,使得输出看起来更加整齐
	for(int i=0;i<G.vexnum;i++){
		printf("%8s",G.vexs[i]);  //打印出规范格式的城市名称
		{
			for(int j=0;j<G.vexnum;j++)
			printf("%8d",G.arcs[i][j]);  //打印出规范格式的边的权值
			printf("\n");  //换行,使得输出结果更加整齐
		}
	}
}

4、深搜模块

int sum;//用来计算机票价格
bool visited[MVNum];  //用来表示结点是否访问过
int DFS(AMGraph G, int v)  //对建立的图进行深度优先搜索
{
    visited[v]=TRUE;  //将本次访问的v对应的位置置为1
    printf("%s  ",G.vexs[v]);  //打印访问的顶点名字
    for(int w=0;w<G.vexnum;w++)
    {
    	if(G.arcs[v][w]!=MaxInt&&(!visited[w])){  //判断与访问顶点相邻的顶点是否被访问过,以及他们之间是否含有通路
    	sum=sum+G.arcs[v][w];  //计算航班总价格
    	DFS(G,w);  //递归算法继续找之后的邻接顶点
    	} 	
	}
	return sum;  //对航班总价进行返回
}

5、广搜模块:

由于广搜需要借助队列,因此将队列也一起放入广搜模块

typedef struct Queue{  //定义队列 
	int data[MVNum];  //队列大小 
	int head;  //队头 
	int wei;  //队尾 
}Queue; 

void InitQueue(Queue *q)  //初始化队列 
{
	q->head= 0;  //初始化队头、队尾 
	q->wei = 0;
} 

int EmptyQueue(Queue *q)  //判断队列是否为空
{
	if(q->head == q->wei)
		return 1;
	else{
		return 0;
	}		
} 

void PushQueue(Queue *q,int t)  //入队 
{
	if((q->wei+1)%MVNum == q->head)  //说明队列已经满了
		return;
	else{	
		q->data[q->wei] = t;	
		q->wei = (q->wei +1)%MVNum;  //队尾后移 
	}
} 

void PopQueue(Queue *q,int *x)  //出队 
{
	if(q->wei == q->head)  //出队完毕 
		return;	
	else{	 	
		*x = q->data[q->head];
		q->head = (q->head + 1)%MVNum;  //队头后移	
	}	
	
} 
 
void BFS(AMGraph G)  //通过输入的起点城市,对邻接矩阵进行广度优先的遍历 
{
	int i,j;
	int k;
	int sum=0;
	Queue Q;
	for(i=0;i<G.vexnum;i++)
	{
		visited[i] = 0;	 //初始化标记符 
	}
	InitQueue(&Q);  //队列初始化 
	for (i = 0; i < G.vexnum; i++)
	{
		if (!visited[i])  //判断以这个顶点为基准,有连接的其他顶点 
		{
			visited[i] = 1;	 //标记遍历的这个顶点 
			printf("%s  ",G.vexs[i]);
			PushQueue(&Q, i);  //入队 
			while (!EmptyQueue(&Q))	 //队列中还有数据,说明这个顶点连接的其他顶点还没有遍历完 
			{
				PopQueue(&Q,&i);  //出队 
				
				for (j = 0; j < G.vexnum; j++)
				{
					//以这个顶点为基准,遍历其他连接的顶点 
					if (!visited[j] && G.arcs[i][j] != MaxInt)
					{
						sum=sum+G.arcs[i][j];
						visited[j] = 1;  //与之连接的顶点作上标记,便于后序顶点跳过相同的遍历 
						printf("%s  ", G.vexs[j]);  //输出与之相邻连接的顶点 
						PushQueue(&Q, j);  //让与之连接的顶点其位置入队 
					}
				}
			}
		}
	}
	printf("\n在不考虑返程情况下总航班费为:%d\n",sum);
} 

6、建立最小生成树模块

void prim(AMGraph G,int v)  //利用Prim算法,通过输入的起点城市来建立最小生成树 
{
 	int con,row;
 	int min;
 	int parent[G.vexnum]={0};  //保存临接顶点下标的数组,所有顶点parent全部赋值为0,将0号顶点(以0号顶点作为第一个顶点)加入生成树
 	int dist[G.vexnum];  //记录当前生成树到剩余顶点的最小权值
 	for(row=1;row<G.vexnum;row++)
 	{
 		 dist[row]=G.arcs[0][row];  //将与下标为0的顶点有边的权值存入dist数组
 	}
 	printf("\n");
  //核心算法
 	for(con=1;con<G.vexnum;con++)  //只需要循环n-1次,n为顶点的个数
 	{
  		min=MaxInt;  //设置一个最大值来比较权值
  		int b,a;
  //找出最小的最小权值min并将下标赋给b
  		for(a=1;a<G.vexnum;a++)  //从1号顶点开始查找
  			{
   				if(dist[a]!=0&&dist[a]<min)  //不在生成树中的顶点且权值最小的
   				{
    			min=dist[a];  //更新最小的权值
    			b=a;  //更新找到新的顶点下标并赋值给b
  			 }  //a++,执行下一顶点直到a=Graph->Nv跳出循环
 			 }
  //Graph->Data[parent[b]]为Graph->Data[b]的父母顶点的信息
  		printf("(%s,%s,%d)\n",G.vexs[parent[b]],G.vexs[b],min);  //打印信息
  		dist[b]=0;  //将这个顶点加入生成树
  //生成树加入了新的顶点从下标为1的顶点开始更新parent数组值
  		for(a=1;a<G.vexnum;a++)
  			{
   				if(dist[a]!=0&&G.arcs[b][a]<dist[a])  //如果新加入树的顶点b使得权值变小
   				{
    			dist[a]=G.arcs[b][a];  //更新最小的权值
    			parent[a]=b;  //修改这条边邻接的顶点,也就是表示这条边是从选出的顶点b指过来的,方便打印
   				}
  			}
	}		
} 

7、查找最短路径模块

void shortestway(AMGraph G)  //根据输入的两个城市,找到一条机票价格最低的路径并打印 
{	int i,j,k;
	int a,b;
	int d[MVNum][MVNum],path[MVNum][MVNum];  //用来存储最短路径权值和和最短路径的下标
	char res1[MVNum],res2[MVNum];  //用来存放输入城市的名称
	for(i=0;i<G.vexnum;i++)  //对数组d和path进行初始化
	{
		for(j=0;j<G.vexnum;j++)
		{
			d[i][j]=G.arcs[i][j];
			path[i][j]=j+1;
		}
	}
	for(k=0;k<G.vexnum;k++)  //拿出每个顶点作为遍历条件
	{  //对于第k个顶点来说,遍历网中任意两个顶点,判断间接的距离是否更短
		for(i=0;i<G.vexnum;i++)
		{
			for(j=0;j<G.vexnum;j++)
			{
				if(d[i][k]+d[k][j]<d[i][j])  //判断经过顶点k的距离是否更短,如果判断成立,则存储距离更短的路径
				{
					d[i][j]=d[i][k]+d[k][j];
					path[i][j]=path[i][k];
				}
			}
		}
	}
	printf("输入要查找价格的两个城市(例如:北京 成都):");
	scanf("%s %s",&res1,&res2);
	a=LocateVex(G,&res1[0])+1;  //将输入城市分别在邻接矩阵中找到
	b=LocateVex(G,&res2[0])+1;
	printf("%s到达%s的最少价格为:%d元\n",res1,res2,d[a-1][b-1
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雁无笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值