ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

数据结构与算法综合实验-图与景区信息管理系统

2021-03-30 17:01:55  阅读:127  来源: 互联网

标签:nVexNum cout int Graph void 算法 顶点 信息管理系统 数据结构


数据结构与算法综合实验-图与景区信息管理系统

  • 任务描述
    有一个景区,景区里面有若干个景点,景点之间满足以下条件:
    1)某些景点之间铺设了道路(相邻)
    2)这些道路都是可以双向行驶的(无向图)
    3)从任意一个景点出发都可以游览整个景区(遍历连通图)

在这里插入图片描述

  • 功能需求

在这里插入图片描述

源代码如下:

  • main.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Tourism.h"
#include"Graph.h"
using namespace std;

Graph m_Graph;

int main(void)
{
	int choice;

	//系统界面
	printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t\t\t");
	printf("*欢迎进入景区管理系统*");
	printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t\t\t");
	system("pause");
	system("cls");

	do {
		//输出系统菜单
		cout << "=====景区信息管理系统=====" << endl;
		cout << "*    1.创建景区景点图    *" << endl;
		cout << "*    2.查询景点信息      *" << endl;
		cout << "*    3.旅游景点导航      *" << endl;
		cout << "*    4.搜索最短路径      *" << endl;
		cout << "*    5.铺设电路规划      *" << endl;
		cout << "*    0.退出              *" << endl;
		cout << "==========================" << endl;

		//用户选择功能
		cout << "请输入菜单项编号(0-5):";
		cin >> choice;
		cout << endl;

		switch (choice)
		{
		case 1:CreateGraph(); break;
		case 2:GetSpotInfo(); break;
		case 3:TravelPath(); break;
		case 4:FindShortPath(); break;
		case 5:DesignPath(); break;
		case 0:cout << "谢谢您使用本系统!" << endl; break;
		default:cout << "您的输入有误!请重新输入!" << endl << endl;;
		}

	} while (choice != 0);

	return 0;
}
  • Graph.h
#pragma once
//存储图的顶点信息
struct Vex
{
	int num;   //景点编号
	char name[20];   //景点名字
	char desc[1024];   //景点介绍
};

//存储边的信息
struct Edge
{
	int vex1;   //边的第一个顶点
	int vex2;   //边的第二个顶点
	int weight;   //权值
};

//顶点数组和邻接矩阵,用来保存图的信息
struct Graph
{
	int m_aAdjMatrix[20][20];   //邻接矩阵
	Vex m_aVexs[20];           //顶点信息数组
	int m_nVexNum;            //当前图的顶点个数
};

//定义链表PathList来保存所有路径
typedef struct Path
{
	int vexs[20];    //保存一条路径
	Path* next;    //下一条路径
}*PathList;

//初始化图
void Init(void);   
//插入顶点信息
bool InsertVex(Vex sVex);
//插入边的信息
bool InsertEdge(Edge sEdge);
//通过传入的顶点编号,返回对应顶点信息结构体
Vex GetVex(int v);
//查询所有与指定顶点相连的边
int FindEdge(int v, Edge aEdge[]);
//使用深度优先搜索算法遍历图
void DFS(int nVex, bool isVisited[], int& nIndex, PathList& pList);
//通过调用DFS()函数,得到深度有限搜索遍历的结果
void DFSTraverse(int nVex, PathList& pList);
//寻找最短路径
int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[]);
//通过Prim算法构建最小生成树
void FindMinTree(Edge aPath[]);
  • Graph.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Graph.h"

extern Graph m_Graph;

//函数名:Init
//参数:void
//返回值:void
//功能:实现图的初始化,权值信息都初始化为0
void Init(void)
{
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			m_Graph.m_aAdjMatrix[i][j] = 0;   //权值信息初始化为0
		}
		m_Graph.m_nVexNum = 0;   //景点数目初始化为0
	}
}

//函数名:InsertVex
//参数:结构体vex
//返回值:true:顶点未满   false:顶点已满
//功能:通过传入结构体,将顶点的相关信息插入到顶点信息数组中
bool InsertVex(Vex sVex)
{
	if (m_Graph.m_nVexNum == 20) {
		//顶点已满
		return false;
	}
	m_Graph.m_aVexs[m_Graph.m_nVexNum++] = sVex;   //插入顶点信息
	return true;
}

//函数名:InsertEdge
//参数:Edge结构体
//返回值:true:插入成功   false:下表越界
//功能:通过传入Edge结构体,将边的相关信息插入到权值矩阵中
bool InsertEdge(Edge sEdge)
{
	if (sEdge.vex1 < 0 || sEdge.vex1 >= m_Graph.m_nVexNum || sEdge.vex2 < 0 || sEdge.vex2 >= m_Graph.m_nVexNum) {
		//下标越界
		return false;
	}
	//插入边的信息
	m_Graph.m_aAdjMatrix[sEdge.vex1][sEdge.vex2] = sEdge.weight;
	m_Graph.m_aAdjMatrix[sEdge.vex2][sEdge.vex1] = sEdge.weight;
	return true;
}

//函数名:GetVex
//参数:输入的编号
//返回值:对应编号的顶点信息结构体
//功能:通过传入的顶点编号,返回对应顶点信息结构体
Vex GetVex(int v)
{
	return m_Graph.m_aVexs[v];
}

//函数名:FindEdge
//参数:nVex:想要查询的顶点   aEdge[]:
//返回值:边的条数
//功能:查询与指定顶点相连的边
int FindEdge(int nVex, Edge aEdge[])
{
	int k = 0;

	//遍历整个图的邻接矩阵
	for (int i = 0; i < 20; i++) {
		if (m_Graph.m_aAdjMatrix[nVex][i] != 0 && nVex != i) {
			//得到边的信息
			aEdge[k].vex1 = nVex;
			aEdge[k].vex2 = i;
			aEdge[k].weight = m_Graph.m_aAdjMatrix[nVex][i];
			k++;
		
		}
	}
	return k;
}

//函数名:DFS
//参数:int nVex:顶点编号  bVisted[]:bool类型的数组,用来记录某个顶点是否被遍历过   int &nIndex:记录遍历深度   PathList &pList:遍历得到的结果
//返回值:void
//功能:使用深度优先搜索算法遍历图
void DFS(int nVex, bool isVisited[], int& nIndex, PathList& pList)
{
	isVisited[nVex] = true;   //修改为已访问
	pList->vexs[nIndex++] = nVex;   //访问顶点nVex

	int num = 0;   //被访问过的节点数
	for (int i = 0; i < m_Graph.m_nVexNum; i++) {
		if (isVisited[i]) {//如果当前i节点被访问过,则num++
			num++;	
		}
	}

	if (num == m_Graph.m_nVexNum) {//如果所有节点都被访问过
		//保存一条路径
		pList->next = new Path;
		for (int i = 0; i < m_Graph.m_nVexNum; i++) {
			pList->next->vexs[i] = pList->vexs[i];
		}
		pList = pList->next;
		pList->next = NULL;
	}
	else {
		for (int w = 0; w < m_Graph.m_nVexNum; w++) {//搜索v的所有邻接点
			if (m_Graph.m_aAdjMatrix[nVex][w] > 0 && !isVisited[w]) {   //如果w是nVex的邻接点并未被访问
				DFS(w, isVisited, nIndex, pList);   //递归调用DFS
				isVisited[w] = false;   //改为未访问
				nIndex--;   //索引值减1
			}
		}
	}
}

//函数名:DFSTraverse
//参数:int nVex:顶点编号   PathList &pList:遍历得到的结果
//返回值:void
//功能:通过调用DFS()函数,得到深度有限搜索遍历的结果
void DFSTraverse(int nVex, PathList& pList)
{
	int nIndex = 0;
	bool bVisited[20] = { false };
	DFS(nVex, bVisited, nIndex, pList);
}

//函数名:FindShortPath
//功能:寻找最短路径
//参数:景点的起始跟目的编号;边的路径结构数组
//返回值:nIndex
int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[])
{
	int nShortPath[20][20];   //最短路径,行表示终点,列表示从起点到终点的最短路径的每一步
	int nShortDistance[20];   //保存从起点到任一顶点的最短距离
	bool aVisited[20];   //判断某点是否已在最短路径中
	int v;   //每一次找到的可以加入集合的顶点

	//初始化
	for (v = 0; v < m_Graph.m_nVexNum; v++) {
		aVisited[v] = false;
		
		if (m_Graph.m_aAdjMatrix[nVexStart][v] != 0) {
			//如果顶点v和nVexStart相连,则最短距离设置为两顶点间的距离
			nShortDistance[v] = m_Graph.m_aAdjMatrix[nVexStart][v];
		}
		else {
			//如果不相连,则最短距离设置为最大值
			nShortDistance[v] = 0x7FFFFFFF;
		}

		nShortPath[v][0] = nVexStart;   //起始点为nVexStart
		//初始化最短路径
		for (int w = 1; w < m_Graph.m_nVexNum; w++) {
			nShortPath[v][w] = -1;
		}
	}
	//初始化,将nVexStart顶点加入到集合中
	aVisited[nVexStart] = true;

	int min;   //暂存路径的最小值
	for (int i = 1; i < m_Graph.m_nVexNum; i++) {
		min = 0x7FFFFFFF;
		bool bAdd = false;   //判断是否还有顶点可以加入集合
		
		for (int w = 0; w < m_Graph.m_nVexNum; w++) {
			if (!aVisited[w] && nShortDistance[w] < min) {
				v = w;   //w顶点距离nVexStart顶点最近
				min = nShortDistance[w];   //w到nVexStart的最短距离为min
				bAdd = true;
			}
		}
		//如果没有顶点可以加入到集合,则跳出循环
		if (!bAdd) {
			break;
		}

		aVisited[v] = true;   //将w顶点加入到集合
		nShortPath[v][i] = v;   //每次找到最短路径后,就相当于从源点出发到了终点,所以nShortPath[v][i]=v

		for (int w = 0; w < m_Graph.m_nVexNum; w++) {
			//将w作为中间点计算nVexStart到所有顶点的最短距离
			if (!aVisited[w] && (min + m_Graph.m_aAdjMatrix[v][w] < nShortDistance[w]) && (m_Graph.m_aAdjMatrix[v][w] > 0)) {
				//如果有新的最短距离,则更新最短路径及距离
				nShortDistance[w] = min + m_Graph.m_aAdjMatrix[v][w];
				for (int i = 0; i < m_Graph.m_nVexNum; i++) {
					//如果通过w到达顶点i的距离比较短,则将w的最短路径赋值给i
					nShortPath[w][i] = nShortPath[v][i];
				}
			}
		}
	}

	int nIndex = 0;
	int nVex1 = nVexStart;

	//将最短路径保存到边的结构体数组中
	for (int i = 1; i < m_Graph.m_nVexNum; i++) {
		if (nShortPath[nVexEnd][i] != -1) {
			aPath[nIndex].vex1 = nVex1;
			aPath[nIndex].vex2 = nShortPath[nVexEnd][i];
			aPath[nIndex].weight = m_Graph.m_aAdjMatrix[nVex1][aPath[nIndex].vex2];
			nVex1 = nShortPath[nVexEnd][i];
			nIndex++;
		}
	}
	return nIndex;
}

//函数名:FindMinTree
//功能:通过Prim算法构建最小生成树
//参数:Edge aPath[]
//返回值:void
void FindMinTree(Edge aPath[])
{
	bool aVisited[20] = { false };   //判断某顶点是否在最小生成树中
	aVisited[0] = true;   //从0号顶点开始,加入到集合中
	int min;
	int nVex1, nVex2;

	for (int k = 0; k < m_Graph.m_nVexNum - 1; k++) {
		min = 0X7FFFFFFF;
		
		for (int i = 0; i < m_Graph.m_nVexNum; i++) {
			//从集合中取一个顶点
			if (aVisited[i]) {
				for (int j = 0;j < m_Graph.m_nVexNum; j++) {
					//从不在集合的顶点中取出一个顶点
					if (!aVisited[j]) {
						if ((m_Graph.m_aAdjMatrix[i][j] < min) && (m_Graph.m_aAdjMatrix[i][j] != 0)) {
							nVex1 = i;
							nVex2 = j;
							//找出最短边
							min = m_Graph.m_aAdjMatrix[i][j];
						}
					}
				}
			}
		}

		//保存最短边的两个顶点
		aPath[k].vex1 = nVex1;
		aPath[k].vex2 = nVex2;
		aPath[k].weight = m_Graph.m_aAdjMatrix[nVex1][nVex2];

		//将两个顶点加入集合
		aVisited[nVex1] = true;
		aVisited[nVex2] = true;
	}
}
  • Tourism.h
#pragma once
//读取文件,创建景区景点图
void CreateGraph(void);
//调用GetVex()函数,得到所有顶点信息并输出
void GetSpotInfo(void);
//通过调用DFSTraverse()函数,实现旅游景点导航功能,将查询到的景点导航路线显示在界面上
void TravelPath();
//调用Graph.cpp文件中的FindShortPath函数查询两个景点间的最短路径和距离
void FindShortPath(void);
//查询铺设电路规划图
void DesignPath();
  • Tourism.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
#include <string.h>
#include<stdlib.h>
#include"Graph.h"
using namespace std;

extern Graph m_Graph;

//函数名:LoadVex
//参数:void
//返回值:void
//功能:实现从Vex.txt文件中读取景点信息并输出
void LoadVex(void)
{
	ifstream VexFile("Vex.txt");
	if (!VexFile) {
		cout << "Vex.txt文件打开失败,请检查!" << endl;
		return;
	}

	//暂存从Vex.txt读取到的一行数据
	char num[2];
	char name[20];
	char desc[1024];
	Vex sVex;

	//逐行读取Vex.txt中的数据
	VexFile.getline(num, 2);   //将第一行的数据读出丢掉

	cout << "景区数目:" << atoi(num) << endl;
	cout << "-----顶点-----" << endl;
	//将顶点信息保存到顶点数组中
	while (VexFile.getline(num, 2)) {
		sVex.num = atoi(num);
		VexFile.getline(name, 20);
		strcpy(sVex.name, name);
		VexFile.getline(desc, 1024);
		strcpy(sVex.desc, desc);

		//将顶点信息输出
		cout << sVex.num << "-" << sVex.name << endl;

		//设置图的顶点
		if (!InsertVex(sVex)) {
			cout << "新增景点失败!" << endl;
			continue;
		}
	}
	cout << "------------" << endl;
	VexFile.close();
}

//函数名:LoadPath
//参数:void
//返回值:void
//功能:实现从Edge.txt文件中读取路径信息并输出
void LoadPath()
{
	ifstream EdgeFile("Edge.txt");
	if (!EdgeFile) {
		cout << "Edge.txt文件打开失败,请检查!" << endl;
		return;
	}

	Edge edge;
	cout << "------边------" << endl;
	while (EdgeFile) {
		EdgeFile >> edge.vex1 >> edge.vex2 >> edge.weight;
		cout << "<" << edge.vex1 << "," << edge.vex2 << ">   " << edge.weight << endl;

		//设置图的边
		if (!InsertEdge(edge)) {
			cout << "新增路径信息失败!" << endl;
			continue;
		}
	}
	cout << "-------------" << endl;
	EdgeFile.close();
	cout << "======================" << endl;

}

//函数名:CreateGraph
//参数:void
//返回值:void
//功能:读取文件,获取景点信息和道路信息
void CreateGraph(void)
{
	cout << "\n=====创建景点景区图=====" << endl;

	Init();//初始化图
	LoadVex();//从Vex.txt文件中读取景点信息并输出
	LoadPath();//从Edge.txt文件中读取路径信息并输出
	cout << endl;
}

//函数名:GetSpotInfo
//参数:void
//返回值:void
//功能:调用GetVex()函数,得到所有顶点信息并输出
void GetSpotInfo(void)
{
	cout << "\n=====查询景点信息=====" << endl;
	int  nVexNum = m_Graph.m_nVexNum;
	if (nVexNum == 0) {
		cout << "请先创建图!" << endl;
		return;
	}

	//将景点信息罗列出来,供用户查询选择
	for (int i = 0; i < m_Graph.m_nVexNum; i++) {
		Vex sVex = GetVex(i);
		cout << i << "-" << sVex.name << endl;
	}

	cout << "====================" << endl;

	//提示用户根据编号进行查询
	cout << "\n请输入想要查询的景点编号:";
	int num;
	cin >> num;

	if (num < 0 || num >= m_Graph.m_nVexNum) {
		cout << "您的输入有误!请重新输入!" << endl;
		cout << "\n请输入想要查询的景点编号:";
		cin >> num;
	}
	else {
		Vex sVex = GetVex(num);
		cout << "----------------------------" << endl;
		cout << sVex.name << ":" << sVex.desc << endl;
		cout << "----------------------------" << endl;
		cout << "-----周边景区-----" << endl;
		Edge aEdge[20];
		int EdgeNum = FindEdge(num, aEdge);
		for (int i = 0; i < EdgeNum; i++) {
			Vex v1 = GetVex(aEdge[i].vex1);
			Vex v2 = GetVex(aEdge[i].vex2);
			cout << v1.name << "->" << v2.name << "   " << aEdge[i].weight << "m" << endl;

		}
		cout << "------------------" << endl;
	}
	cout << endl;
}

//函数名:TravelPath
//参数:void
//返回值:void
//功能:通过调用DFSTraverse()函数,实现旅游景点导航功能,将查询到的景点导航路线显示在界面上
void TravelPath()
{
	cout << "\n=======旅游景点导航======" << endl;
	
	int nVexNum = m_Graph.m_nVexNum;
	if (nVexNum == 0) {
		cout << "请先创建图!" << endl;
		return;
	}

	for (int i = 0; i < m_Graph.m_nVexNum; i++) {
		Vex sVex = GetVex(i);
		cout <<"*\t"<< i << "-" << sVex.name <<"\t\t*"<< endl;
	}
	cout << "=========================" << endl;

	//输入景点编号
	cout << "请输入想要导航的起始点编号:";
	int startNum;
	cin >> startNum;
	if (startNum < 0 || startNum >= m_Graph.m_nVexNum) {
		cout << "您输入的编号有误!" << endl;
		return;
	}

	//遍历景区景点图
	PathList pList = new Path;
	PathList pHead = pList;
	DFSTraverse(startNum, pList);

	cout << endl;

	//输出遍历结果
	cout << "导航路线为:" << endl;
	int i = 1;
	pList = pHead;
	while (pList->next != NULL) {
		Vex vex = GetVex(pList->vexs[0]);
		cout << "路线" << i++ << ":" << vex.name;
		for (int j = 1; j < m_Graph.m_nVexNum; j++) {
			vex = GetVex(pList->vexs[j]);
			cout << "->" << vex.name;
		}
		cout << endl;
		pList = pList->next;
	}
	cout << endl;

	delete pList;
	pList = NULL;
	pHead = NULL;
}

//函数名:FindShortPath
//功能:调用Graph.cpp文件中的FindShortPath函数查询两个景点间的最短路径和距离
//参数:void
//返回值:void
void FindShortPath(void)
{
	cout << "\n======搜索最短路径======\n";

	int nVexNum = m_Graph.m_nVexNum;

	if (nVexNum == 0) {
		cout << "请先创建图!" << endl;
		return;
	}

	for (int i = 0; i < m_Graph.m_nVexNum; i++) {
		Vex sVex = GetVex(i);
		cout << "*\t" << i << "-" << sVex.name << "\t\t*" << endl;
	}
	cout << "========================\n";

	//输入两个景点的编号
	int start_place, end_place;
	cout << "请输入起点的编号:";
	cin >> start_place;
	cout << "请输入终点的编号:";
	cin >> end_place;

	if (start_place < 0 || start_place >= m_Graph.m_nVexNum || end_place < 0 || end_place >= m_Graph.m_nVexNum) {
		cout << "输入错误!请重新输入!!!" << endl;
		return;
	}

	Edge aPath[20];    //边信息数组,依次保存最短的路径

	for (int i = 0; i < 20; i++) {   //初始化边信息数组
		aPath->vex1 = -1;
		aPath->vex2 = -1;
		aPath->weight = -1;
	}

	//搜索最短路径
	int index = FindShortPath(start_place, end_place, aPath);
	int length = 0;   //最短路径总长度
	Vex sVex = GetVex(aPath[0].vex1);

	//得到最短路径和最短距离
	cout << "\n最短路径为:" << sVex.name;

	for (int i = 0; i < index; i++) {
		sVex = GetVex(aPath[i].vex2);
		cout << "->" << sVex.name;
		length += aPath[i].weight;
	}

	cout << endl;
	cout << "最短距离为:" << length << "米" << endl << endl;
}

//函数名:DesignPath
//功能:查询电路铺设规划图
//参数:void
//返回值:void
void DesignPath()
{
	cout << "在以下两个景点之间铺设电路";
	cout << "\n=======铺设电路规划=======" << endl;

	Edge aPath[20];

	FindMinTree(aPath);   //构建最小树

	int nVexNum = m_Graph.m_nVexNum;

	if (nVexNum == 0) {
		cout << "请先创建图!" << endl;
		return;
	}

	//输出铺设线路图
	int nAllLength = 0;


	for (int i = 0; i < m_Graph.m_nVexNum - 1; i++) {
		Vex nVex1 = GetVex(aPath[i].vex1);
		Vex nVex2 = GetVex(aPath[i].vex2);

		cout << "\t" << nVex1.name << "-" << nVex2.name << ":" << aPath[i].weight << "m" << endl;
		nAllLength += aPath[i].weight;
	}
	cout << "==========================\n";
	cout << "铺设电路的总长度是:" << nAllLength << "m" << endl << endl;
}

标签:nVexNum,cout,int,Graph,void,算法,顶点,信息管理系统,数据结构
来源: https://blog.csdn.net/weixin_51008866/article/details/115329769

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有