武汉理工大学数据结构综合实验——图与景区信息管理系统实践


实验目的

掌握图的存储结构和定义
掌握图的创建方法和图的应用
掌握图的两种遍历方法和应用
掌握迪杰斯特拉算法和应用
理解最小生成树的概念
掌握普里姆算法和应用 使用 C++、定义图的数据结构,结合迭代开发思路实现“景区信息管理”专题编程。

主要仪器设备及耗材

1.安装了Windows 10操作系统的PC机1台
2.PC机系统上安装了Microsoft Visual Studio 2019开发环境


以下是本篇文章正文内容,下面案例可供参考

一、实验要求

开发景区信息管理系统,对景区的信息进行整理。使用图的数据结构来保存景区景点信息,为用户提供创建图,查询景点信息,旅游景点导航,搜索最短路径,铺设电路规划等功能。在确保书上例子正确的情况下,添加自己创建的图来检查自己实现的功能。

二、分析与设计

依据上述的实验目的与要求,可导出实现的图与景区信息管理系统的流程为:
(1)创建图:从Vex.txt和Edge.txt中分别读取景点信息和道路信息,根据读取的景区信息创建景区景点图。
(2)查询景点:根据输入的景点编号,查询该景点及相邻景点的信息。
(3)旅游景点导航:从起始景点开始,遍历景区所有景点,记录所有无重复的路径。
(4)搜索最短路径:搜索两个景点之间的所有路径,找到其中距离最短的路径。
(5)铺设电路规划:根据景区景点图,构造一棵最小生成树,设计出一套铺设线路最短,但能满足每个景点都能通电的方案。

1.数据结构的设计

代码如下(示例):

//定义Vex结构体,存储图的顶点
struct Vex
{
    
    
	int num;//景区编号
	char name[20];//景点名字
	char desc[1024];//景点介绍
};

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


//定义图的存储结构
struct Graph
{
    
    
	int m_aAdjMatrix[20][20];//邻接矩阵
	Vex m_Vexs[20];//顶点信息数组
	int m_nVexNum;//当前图的顶点个数

};

//定义链表来保存所有路径
typedef struct Path {
    
    

	int vexs[20];//保存一条路径
	Path* next;//下一条路径

}*PathList;

2.核心算法设计

改进DFS算法

代码如下(示例):

void DFS(int nVex, bool bVisited[], int& nIndex, PathList& pList) {
    
    

	bVisited[nVex] = true;//该顶点被遍历
	pList->vexs[nIndex++] = nVex;//访问顶点编号为nVex的顶点

	//判断所有的顶点是否都已经被访问过									
	int vexnum = 0;
	for (int i = 0; i < m_Graph.m_nVexNum; i++)
		//如果当前i节点被访问过,则vexNum自加
		if (bVisited[i]) vexnum++;

	//如果所有的顶点都已经被访问过,就保存这一条路径
	if (vexnum == m_Graph.m_nVexNum)
	{
    
    
		//创建一个新链表,将当前的pList中的数据保存起来
		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指针继续往下移动,寻找下一条路径
		pList->next = NULL;			//pList->next赋值为空
	}
	//若没有全部访问,则继续访问下一个相邻节点
	else
	{
    
    
		for (int i = 0; i < m_Graph.m_nVexNum; i++)//搜索nVex的所有邻接点
		{
    
    
			if (!bVisited[i] && m_Graph.m_aAdjMatrix[nVex][i] > 0)//i是nVex的邻接点
			{
    
    
				DFS(i, bVisited, nIndex, pList);			//递归调用DFS
				bVisited[i] = false;						//未访问
				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) 
			//初始化该顶点到其他顶点的最短距离
			nShortDistance[v] = m_Graph.m_aAdjMatrix[nVexStart][v];
		else 
			//如果顶点v和nVexStart不相连,设置之间的距离为最大值
			nShortDistance[v] = 0x7FFFFFFF;
		nShortPath[v][0] = nVexStart;   //起始点为nVexStart

		//初始化最短路径
		for (int w = 1; w < m_Graph.m_nVexNum; w++) nShortPath[v][w] = -1;
	}

	
	aVisited[nVexStart] = true;//将nVexStart顶点算在最短路径中
	int min;					//存放路径的最小值

	for (int i = 1; i < m_Graph.m_nVexNum; i++)
	{
    
    
		min = 0x7FFFFFFF;
		bool addon = false;		//判断是否还有顶点可以加入最短路径
		for (int w = 0; w < m_Graph.m_nVexNum; w++)
		{
    
    
			if (nShortDistance[w] < min &&!aVisited[w] )//w是距离nVexStart最近的点且w不在原先的最短路径中
			{
    
    
				v = w;						//w顶点距离nVexStart顶点最近
				min = nShortDistance[w];	//w到nVexStart的最短距离为min
				addon = true;				//有顶点加入最短路径
			}
		}

		//如果没有顶点可以加入到最短路径,则跳出循环
		if (!addon) break;
		aVisited[v] = true;			//将w顶点加入到最短路径
		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;

}

Prim算法(构建最小生成树)

//通过Prim算法来构建最小生成树
void FindMinTree(Edge aPath[]) {
    
    

	bool aVisited[20] = {
    
     false };		//判断某顶点是否在最小生成树中,false表示不在
	aVisited[0] = true;					//从0号顶点开始,加入到最小生成树中
	int min;
	int nVex1=0, nVex2=0;

	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;
	}


}

3.测试用例设计

使用书上例子,观察每个功能是否与书上有相同的结果。
使用自己创建的景点图,观察是否出现错误和结果是否合理。

4.测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


总结

详情可参考以下链接
链接:冲冲冲~
提取码:fv2n
复制这段内容后打开百度网盘手机App,操作更方便哦

猜你喜欢

转载自blog.csdn.net/mo_zhe/article/details/112771599
今日推荐