数据结构:图的基本操作模拟-校园导游(c++)

一、实验题目

利用数据结构的知识,编写图的基本操作内容。

二、需求分析

[问题描述]
分别用邻接矩阵和邻接表实现以下操作:图的创建、遍历、插入、删除、最短路径。 参考题目为校园导游程序
[基本要求]
熟悉图的常用存储结构和基本操作。
[实现提示]
设图的结点不超过 30 个,每个结点用一个编号表示(如果一个图有 n 个结点,则它们的编号分别为 1,2,…,n)。通过输入图的全部边输入一个图,每个边为一个数对,可以对边的输入顺序作出某种限制。注意,生成树的边是有向边,端点顺序不能颠倒。
[选作内容]
(1)借助于栈类型(自己定义和实现)将深度优先遍历用非递归算法实现。
(2)以邻接表为存储结构建立深度优先生成树和广度优先生成树,再按凹入表或树形
打印生成树。

三、概要设计

初始化界面
在这里插入图片描述
运行代码:

#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char charType[20];//顶点信息存放数据类型
int visit[20];//顶点是否被访问过的标志数组
//表结点
typedef struct EdgeNode {
	int   adjvex;//存储该点对应的下标
	int   weight;//存储权值
	struct EdgeNode * next;//指向下一个邻接点
} EdgeNode;
//顶点
typedef struct TopNode {
	charType   data;//存储顶点信息
	int        dist;//存储最短路径(距离)
	int        len;//存储x到y经过多少个顶点
	int        path[20];//存储最短路径下标的数组
	EdgeNode  * firstedge;//边表头指针
} TopNode, AdjList[20];
//图信息
typedef struct Chart {
	AdjList    vertices;//存储顶点的数组
	int       topnum;//顶点数
	int       arcnum;//边数
} Chart;
//转化(查找)
int Change(Chart * G, charType v) {
	int i;
	for (i = 0; i < G->topnum; i++) {
		if ((strcmp(v, G->vertices[i].data)) == 0)//当找到输入两两关系的顶点某个顶点与输入顶点信息时某个顶点相等时,返回该顶点的下标(其实就是字符转换成整型数)
			return i;
	}
}
//邻接表建立有向图函数
void CreateAdjList(Chart * G) {
	int i,j, k, weight;
	charType v1, v2;
	EdgeNode * p;
	int m;
	cout<<"请输入 顶点数 和 边数:"<<endl;
	cin>>G->topnum>>G->arcnum;
	cout<<"请输入 顶点信息 :"<<endl;
	for (m = 0; m < G->topnum; m++) {
		cin>>G->vertices[m].data;
		G->vertices[m].firstedge = NULL;
	}
	//初始化(2)
	//确定顶点与顶点之间的关系(连接方向&边权值)
	cout<<"请输入"<<G->arcnum<<"条弧的 两两关系 及 边权值"<<endl;
	for (k = 0; k < G->arcnum; k++) {
		cin>>v1>>v2>>weight;
		i = Change(G, v1);//将字符转化成了整型
		j = Change(G, v2);//将字符转化成了整型
		EdgeNode * e = (EdgeNode *)malloc(sizeof(EdgeNode));
		e->adjvex = j; //表结点下标
		e->weight = weight;//表结点权值
		e->next = NULL;//该表结点暂时没有下一个表结点
		p = G->vertices[i].firstedge;//将第i个顶点的边表头指针赋值给表结点指针p
		//尾插
		if (p == NULL) { //如果p为空(即第i个顶点的边表结点为空)
			G->vertices[i].firstedge = e;//将表结点赋值给第i个顶点的firstedge(即实现两点相连)
		} else { //如果第i个顶点的边表结点不为空
			while (p->next) { //直到p==null
				p = p->next;
			}
			p->next = e;//在尾部插入表结点
		}
	}
}
//更新路径函数(存储最短路径每个下标)
void GetNewPathWay(Chart * G, int k, int i) {
	int j;
	for (j = 0; j <= G->vertices[k].len; j++)
		G->vertices[i].path[j] = G->vertices[k].path[j];
	G->vertices[i].path[j] = i;//为了在输出路径的时候判断是否存在有源点到i的最短路径
}
//输出路径函数
int ShowPathWay(Chart * G, int y) {
	int i, j;
	for (i = 0; i <= G->vertices[y].len; i++)
		if (G->vertices[y].path[i] == y) { //遍历数组path找到了最短路径在i下标,输出最短路径每个下标
			cout<<"最短路径是:"<<endl;
			for (j = 0; j < i; j++) {
				cout<< G->vertices[G->vertices[y].path[j]].data<<"->"<<endl;
			}
			cout<<G->vertices[G->vertices[y].path[j]].data<<endl;
			cout<<"最短距离为:"<<endl;
			cout<< G->vertices[y].dist;
			return 1;
		}
	cout<<endl<<"ERROR"<<endl;
	cout<<"没有通路"<<endl;
	return 0;
}
void Dijkstra(Chart * G) {
	cout<<"请输入 开始点 和 结束点:"<<endl;
	int x, y;
	while ((scanf("%d", &x))!= EOF, x != -1 && x != 0 && x <= G->topnum) { //开始点(要求:开始点不为-1,0,不大于顶点数)
		int i, j, k, m, min = 0, t;
		//初始化路径,初始化所有顶点的状态都是未访问过的状态
		for (i = 0; i < G->topnum; i++) {
			visit[i] = 6;
			G->vertices[i].dist = 0;
			G->vertices[i].len = 0;
			for (j = 0; j < G->topnum; j++)
				G->vertices[i].path[j] = 6;
		}
		G->vertices[x - 1].dist = 0;
		G->vertices[x - 1].path[0] = x - 1;//源点到其本身不算入最短路径
		k = x - 1;//每次找到最小路径顶点的下标
		EdgeNode * p;
		//每次求得x到某个顶点的最短路径
		for (i = 0; i < G->topnum; i++) {
			t = 6;
			p = G->vertices[k].firstedge;
			visit[k] = 1;
			while (p) {
				if (!visit[p->adjvex]) {
					if (G->vertices[k].dist == 6) { //说明该k点之前是在没有被找到的里面
						G->vertices[p->adjvex].dist = p->weight;//将x顶点的第一个表结点(前提存在该表结点)的权值赋值给该结点的dist(目的:为了求最小权值)
						G->vertices[p->adjvex].len = G->vertices[k].len + 1;//将x顶点的len+1赋值给表结点的len(记录x到某顶点的路径)
						GetNewPathWay(G, k, p->adjvex);//更新路径,存储最短路径下标
					} else if (G->vertices[k].dist + p->weight < G->vertices[p->adjvex].dist) { //如果源点->k->p的adjvex小于源点->p的adjvex,则修正当前最短路径及权值(x到k到此时p的权值小于x到p的的权值则执行)
						G->vertices[p->adjvex].dist = G->vertices[k].dist + p->weight;
						G->vertices[p->adjvex].len = G->vertices[k].len + 1;
						GetNewPathWay(G, k, p->adjvex);
					}
				}
				p = p->next;//下一个与k直接相连的顶点
			}
			//寻找离k最近的顶点
			for (j = 0; j < G->topnum; j++) {
				if (G->vertices[j].dist < t && !visit[j]) { //j没有被访问过
					t = G->vertices[j].dist;//j顶点距离k更近
					min = j;
				}
			}
			k = min;//找到源点到min是所求的该次的最短路径,下一次就从min开始找
		}
		while ((scanf("%d", &y)) != EOF, y != -1 && y != 0 && y <= G->topnum) {		
		ShowPathWay(G, y - 1);
			cout<<"请输入"<<x<<"--> 的下一个顶点(-1结束):"<<endl;
		}
		cout<<"请输入 开始点 和结束点 (-1结束):"<<endl;
	}
}
//深度遍历函数
void Dfs(Chart * G, int i) {
	visit[i] = 1;
	cout<< G->vertices[i].data;
	EdgeNode * p;
	p = G->vertices[i].firstedge;
	while (p) {
		if (!visit[p->adjvex])
			Dfs(G, p->adjvex);//对未访问的邻接顶点递归调用
		else
			p = p->next;
	}
}
void DfsTraverse(Chart * G) {
	int i, j;
	//初始化路径,初始化所有顶点的状态都是未访问过的状态
	for (i = 0; i < G->topnum; i++) {
		visit[i] = 0;
		G->vertices[i].dist = 65535;
		G->vertices[i].len = 0;
		for (j = 0; j < G->topnum; j++)
			G->vertices[i].path[j] = 65535;
	}
	//对未访问过的顶点调用DFS
	for (i = 0; i < G->topnum; i++)
		if (!visit[i])
			Dfs(G, i);
}
int main() {
	Chart G;
	cout<<"有向图操作"<<endl;
	CreateAdjList(&G);
	cout<<"深度遍历有向图:"<<endl;
	DfsTraverse(&G);
	Dijkstra(&G);
	return 0;
}

四、调试分析

在这里插入图片描述
如上图所示,运行结果无错误。

五、使用说明

第一步:输入顶点和边数
第二步:输入顶点信息
第三步:输入弧之间的关系
第四部:输出结果

六、测试结果

在这里插入图片描述

七、其他数据结构实例

数据结构:编程带你了解约瑟夫环
数据结构:简易停车场管理系统
数据结构:哈夫曼编/译码设计

以上内容为个人学习总结,如有遗漏或者错误请在评论区中指正!!!

如果看完觉得有所收获的话,记得一键三连哦,谢谢大家!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值