校园导游系统数据结构课程设计(附完整代码)

news/2025/3/12 12:28:43/

1 问题内容与目的要求

1.1 算法产生的背景:

Floyd 算法又称为加点法、插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。该算法名称以创始人之一、1978 年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特 · 弗洛伊德命名。它与 Dijkstra 算法类似,但Dijkstra 算法是基于贪心算法的思想。

1.2 题目内容:

基本要求:

针对XX大学YY校区,设计一个校园导游图系统,为来访的客人提供信息查询服务。要求:

1.在老师提供的“校园景点.txt”文件中,存储了YY校区的景点信息,信息分为两部分 ,二者用一个空行隔开。其中第一部分的每一行,以“编号>名称>简介”的格式描述了一个景点的信息,“>”起到将不同信息分隔开的作用;第二部分的每一行,以“编号>编号>距离”的格式描述两个景点之间路径的长度,例如0>1>200表示编号为0的景点与编号为1的景点之间的路径长度为200米,“>”还是起到分隔作用。

2.依据“校园景点.txt”提供的信息,将校园景点及景点之间的路径抽象为一个带权无向图,以图中顶点表示景点编号,以边的权值表示两个景点之间路径之长度,在实验报告上绘制这个带权无向图

3.编写程序实现以下功能:

(1)程序读取“校园景点.txt”,依所读取的数据创建上述带权无向图的存储结构,要求存储结构表示了各景点的信息(编号、名称、简介),还表示了景点之间的路径长度。

(2)程序在屏幕上按下述格式,显示所有景点的编号、名称、简介等。

(3)通过景点编号,可检索并显示该景点的全部信息

(4)通过景点名称,可检索并显示该景点的全部信息

(5)为来访客人提供查询任意两个景点之间的一条最短路径,其结果按“1>4>5>8=160”格式显示,表示从1号到8号景点的最短路径依次经过了编号为1、4、5、8的景点,路径长度为160米。

更高要求:

(6)提供校园平面图的编辑功能:增、删景点;增、删道路,修改已有信息等

(7)提供校园导游图的仿真界面—即将上面的第2点,路径的发布与走向尽量画得接近真实情况,并显示到屏幕上。

1.3 要实现的目的:

基本:针对XX大学YY校区,设计一个校园导游图系统,为来访的客人提供信息查询服务。更高:在基本的校园导游系统上,(1)除了给管理员提供查询的服务,再增加上增删改的服务;(2)大致提供校园导游图的仿真界面。

2 总体思路与工程结构

2.1 系统功能模块

根据功能分析,系统功能模块图如图1所示:
在这里插入图片描述

图1:系统功能模块图

2.2 项目结构

2.2.1 工程总体结构

建立名为“2020_校园导游系统”的工程,整个实验将在其中进行。该小工程包括头文件headPro.h,文件body1.cpp,文件main.cpp。如图2所示:
在这里插入图片描述

图2:工程结构

2.2.2 函数之间的调用关系

补充:由于小工程的函数多,画出会很丑陋,这里使用图3的方式的呈现,圆圈的数字与2.2.3函数及功能里的函数的编号,即函数(编号)一一对应。
在这里插入图片描述

图3:函数之间的调用关系图

2.2.3 函数及功能

函数(1):int inputString(char *filename,string str[])功能:将filename所指文件按行输出到数组str[]中,返回表达式的实际个数。函数(2):int f1(string str)功能:返回str中的数字字符串所对应的整数。函数(3):void f2(string str, string &str1, string &str2, string &str3)功能:将字符串str按'<'分为三个子字符串 str1, str2, str3。函数(4):void createGraph(MGraph &G)功能:创建无向图G,并将名为“校园景点.txt”的文件数据存储到图的景点、景点之间的关系——道路长所对应的邻接矩阵。函数(5):void printDataOfGraph(MGraph G)功能:打印图G的全部景点的信息。函数(6):void searchByNum(MGraph G)功能:根据用户输入的图G景点的编号,显示图G中该景点的所有信息。函数(7):void searchByName(MGraph G)功能:根据用户输入的图G景点的名称,显示图G中该景点的所有信息。函数(8):/*\* MGraph G: 是无向图\* int **dist: 是指向 dist[][] (存储图的最短路径的邻接矩阵)的指针\* int **path: 是指向 path[][] (记录图的最短路径的景点次序的矩阵)的指针*/void floyd(MGraph G, int **dist, int **path)功能: 使用floyd算法求图G的最短路径的所需的dist[][],path[][]函数(9):/*\* u 是最短路径的开端景点的编号\* v 是最短路径的末端景点的编号\* int **path: 是指向 path[][] (记录图的最短路径的景点次序的矩阵)的指针*/void printPath(int u, int v, int **path)功能:由于输入需要如1<2<3=160的格式显示,因而使用递归辅助打印最短路径函数(10):void displayShortestPath(MGraph G)功能:按格式显示图G任意两个景点u到v(这里的u, v是景点的编号)的最短路径的长度值。函数(11):void addNode(MGraph &G)功能:根据用户所输入的景点的名称、简介,来给图G增加新景点。函数(12):void addArc(MGraph &G)功能:根据用户所输入的两个景点的编号,来给图G增加直达道路。函数(13):void updateInformation(MGraph &G)功能:根据用户所输入的景点的编号和新简介,来修改图G中对应的景点的简介。函数(14):void updateName(MGraph &G)功能:根据用户所输入的景点的编号和新名称,来修改图G中对应的景点的名称。函数(15):void updateArc(MGraph &G)功能:根据用户所输入的两个景点的编号和新的路径长度值,来修改两个景点编号在图G中对应的直达道路的长度值。函数(16):void deleteArc(MGraph &G)功能:根据用户所输入的两个景点的编号,来删除两个景点编号在图G中对应的道路。函数(17):void deleteNode(MGraph &G)功能:根据用户所输入的景点的编号,来删除景点编号在图G中所对应的景点以及跟景点直接相连的道路。函数(18):void showMap()功能:将名为“校园景点.txt”的文件数据存储到图的景点、景点之间的关系——道路长所对应的邻接矩阵之后,大致显示在无向图最初(没有进行增删改的操作)的形状。函数(19):void menu1()功能:显示导游系统的功能菜单。函数(20):int main()功能:主函数(测试函数),呈现出导游系统的查询界面。

3 主要数据结构、关键问题和算法

3.1 数据结构

表1:校园景点表

景点编号景点名称景点简介
0励学楼也称“一教”,是一栋很有文化气息的教学楼,环境幽雅。
1笃行楼也称“二教”,是一栋很有现代化气息的教学楼,设计巧妙。
2厚德楼也称“行政楼”,是大学的行政办事中心。
3拓新楼也称“实验楼”,是计算机机房,有各类实验设备。
4图书馆高端大气,藏书丰富,建筑宏伟,环境幽雅。
5创业园区学生开展创新产业实践活动,激发创业意识,培养企业家精神的活动场所。
6李园宿舍园区,学生职工混住,较为混乱。
7桃园宿舍园区,环境优美,比较安静。
8竹园宿舍园区,有许多健身器材,方便广财学子户外娱乐。
9三饭菜色丰富,环境整洁。
10学而优方便购买生活必须品,学习用品。
11灯光球场篮球健儿的摇篮。
12沁湖美丽校园的缩影,情侣游园的好地方。
13中心花园场地空旷,马路宽广,正对大学西门。

将校园平面图抽象为图4所示的带权无向图:
在这里插入图片描述

图4:由校园平面图抽象所得的带权无向图

其中:顶点编号与“表1:校园景点表”中景点编号一一对应,代表相应景点;边上的权值代表两个景点之间的路径长度(单位:米)

数据结构的设计——邻接矩阵:

需要存储的信息有两个方面。一是校园景点表各景点的描述信息;二是各景点之间的联系,即各景点之间的路径信息。为此,一是用一维数组存储校园景点表的信息;二是二维数组表示各景点之间的联系。通过两个数组之间下标的对应关系,使得两方面的信息发生关联。

#include<string>   //引用字符串对象
#define MAXVER 50     //邻接矩阵(方阵)的最大行(列)数
#define INFINITY 32767   //INFINITY表示极大值、无穷大
//这个小工程里的顶点、节点、景点、结点为图的结点,表示为 Vertype,ver,node
//这个小工程里的弧、边、道路为图的边(权值边),表示为 arc
//校园景点的定义
typedef struct
{
​    int num;        //校园景点编号(权值)
​    string name;       //校园景点名
​    string information;    //校园景点的描述信息
}Vertype;//图的边的邻接矩阵表示
typedef struct
{
​    int arcs[MAXVER][MAXVER]; //邻接矩阵表示弧或边(两点距离长权值)
​    Vertype ver[MAXVER];    //景/顶点表
​    int vernum;          //图的当前景点数
​    int arcnum;          //图的当前边数
}MGraph;

思考:接下来执行 MGraph G; 命令,系统会如何给G分配空间,试着画出其示意图,试着把以下两方面信息存储进去:需要存储的信息有两个方面,一是校园景点表各景点的描述信息;二是各景点之间的联系,即各景点之间的路径信息。

3.2 关键问题

3.2.1 求导游图的任意两个景点的最短路径

(1)那什么是求导游图的任意两个景点的最短路径呢?

答:简言之,就是在导游图已有的景点(顶点)、道路(边),找连接两个景点的最短道路,得到最短道路的长度值(边的权值)、最短道路的经过的景点次序,即从开端景点到中间景点(可能没有,即直达),再到终端景点的次序。

(2)那怎么求导游图的任意两个景点的最短路径呢?

答:

1、通常使用Floyd算法求导游图的任意两个景点的最短路径;大体的关键步骤如下:

1)从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。

2)对于每一对顶点 u 和 v,看看是否存在一个顶点 w (一般称为中间点)使得从 u 到 w 再到 v 比已知的路径更短。如果是,更新它(专业术语为:松弛)。

3)遍历直到结束,这时候存储图的数据结构就得到了多源最短路径。

2、中间涉及两个比较关键数组:

1)二维数组dist[][]是用于存储图的景点之间的最短路径的邻接矩阵,比如dist[i][j] = 150;表示从编号为i的景点到编号为j的景点的最短路径的长度值为150米;比如dist[i][j] = INFINITY (32767)表示从编号为i的景点到编号为j的景点之间没有连通路径,也就是无法直接到达和间接到达。

2)二维数组path[][] 是记录图的最短路径的中间景点次序的矩阵,比如path[m][n] = -1;表示从编号为m的景点到编号为n 的景点是直达的,即没有中间景点;比如path[m][n] = 6; 表示从编号为m的景点到编号为n 的景点是间接到达的,即含有编号为6中间景点(可能还有其它中间景点);

3.3主要算法说明

3.3.1 Floyd算法

Floyd 算法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。该算法不是那么难且有效,关键的部分是对三道循环的理解。代码大致如下:
//三道循环实现

for(v = 0; v < n; ++v) //测试欲加入的节点
{for(i = 0; i < n; ++i) //路径的开端{
​    for(j = 0; j < n; ++j) //路径的终端
​    {  //判断原来的路径长度值是否大于加入新节点的路径长度值
​      if(dist[i][j] > dist[i][v] + dist[v][j])
​      {  //松弛边,更新最短路径的长度值
​        dist[i][j] = dist[i][v] + dist[v][j];
​        //记录或更新最短路径
​        path[i][j] = v;
​      }
​    }}
}

优点:难度系数不高,可以算出任意两个节点之间的最短距离,代码编写不难。

缺点:时间复杂度比较高,不适合计算大量数据。时间复杂度 O(n^3),空间复杂度 O(n^2)。

3.3.2 递归算法

那什么是递归算法呢?

答:递归算法是一种直接或者间接调用自身函数或者方法的算法。(俗话就说成“自己调用自己”)递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解。

本小工程主要使用递归算法辅助输出显示两个景点的最短路径,使用于printPath ()函数里面。

4 测试

此处自己测试功能,自行编写测试流程

5 总结

5.1 任务完成情况

5.1.1 已经完成的任务

(1)程序读取“校园景点.txt”,依所读取的数据创建带权无向图的存储结构,要求存储结构表示了各景点的信息(编号、名称、简介),还表示了景点之间的路径长度。

(2)程序在屏幕上按下述格式,显示所有景点的编号、名称、简介等。

(3)通过景点编号,可检索并显示该景点的全部信息。

(4)通过景点名称,可检索并显示该景点的全部信息。

(5)为来访客人提供查询任意两个景点之间的一条最短路径,其结果按“1>4>5>8=160”格式显示,表示从1号到8号景点的最短路径依次经过了编号为1、4、5、8的景点,路径长度为160米。

(6)提供校园平面图的编辑功能:增、删景点;增、删道路,修改已有信息等。

(7)提供校园导游图的仿真界面—即将上面的第2点,路径的发布与走向尽量画得接近真实情况,并大致显示到屏幕上,但不牙雅观。

5.1.2尚未完成的任务

5.2不足与改进信息

不足之处主要表现在:

1)程序的交互性差,可改进为提供菜单选项,使得每个选项代表用不同的算法来进行搜索;

2)程序运行效率不高,可适当修改算法,进行优化;

3)图的景点之间关系,即图的邻接矩阵空间是有限的、静态定义(可能导致无法增加新的景点),且没有扩容的操作,建议可以使用动态定义或增加扩容操作

4)程序中只知道函数调用涉及栈、new操作涉及堆,了解还是不足,建议可更多地了解底层;

5)程序中对指针和引用的使用不熟,建议更多地了解相关、解析更多更易吸收的书籍或文档。

5.3 自评与诚信声明

自评:XX分

该数据结构课程设计的参考文献资料如后面所列。保证除了参考这些文献资料和与同学讨论之外,没有抄袭某同学的、某文献的,否则甘愿接受记0分的处罚。

附录一 实验环境

Windows 10 + CodeBlocks

附录二 用户手册

  1. 在Windows环境下,“校园景点.txt”文件跟.exe文件要放在同一目录,就可以直接打开.exe文件或者利用CodeBlocks编译器打开,这里有打开.exe文件的图片
    2)然后双击.exe文件就行,然后会看到导游系统的服务菜单,如图
  2. 然后键盘输入英文字母y(yes)进入服务,服务时多看菜单,多参考我那实验测试过程,多使用服务编号2进行全局看景点。当你不要服务时,就输入服务编号0,再按回车键,再按任意键退出校园导游系统。

附录三 校园景点.txt文件

0>励学楼>也称“一教”,是一栋很有文化气息的教学楼,环境幽雅。
1>笃行楼>也称“二教”,是一栋很有现代化气息的教学楼,设计巧妙。
2>厚德楼>也称“行政楼”,是大学的行政办事中心。
3>拓新楼>也称“实验楼”,是计算机机房,有各类实验设备。
4>图书馆>高端大气,藏书丰富,建筑宏伟,环境幽雅。
5>创业园区>学生开展创新产业实践活动,激发创业意识,培养企业家精神的活动场所。
6>李园>宿舍园区,学生职工混住,较为混乱。
7>桃园>宿舍园区,环境优美,比较安静。
8>竹园>宿舍园区,有许多健身器材,方便广财学子户外娱乐。
9>三饭>菜色丰富,环境整洁。
10>学而优>方便购买生活必须品,学习用品。
11>灯光球场>篮球健儿的摇篮。
12>沁湖>美丽校园的缩影,情侣游园的好地方。
13>中心花园>场地空旷,马路宽广,正对大学西门。0>1>200
0>4>200
0>5>100
0>6>90
0>7>370
0>13>120
1>2>600
1>4>300
1>8>90
1>13>90
2>4>350
2>3>330
2>5>410
2>8>700
3>4>20
3>5>170
5>12>100
6>7>350
6>10>180
6>13>130
7>10>800
7>12>350
8>9>80
8>13>250
9>11>270
10>11>180
11>13>130

附录四 源代码

头文件headPro.h如下:

#ifndef HEADPRO_H_INCLUDED
#define HEADPRO_H_INCLUDED#endif // HEADPRO_H_INCLUDED#include<string>           //使用字符串类
using namespace std;       //使用位于名称空间 std 的string类#define MAXVER 50          //邻接矩阵(方阵)的最大行(列)数
#define INFINITY 32767     //INFINITY表示极大值、无穷大//这个小工程里的顶点、节点、景点、结点为图的结点,表示为 Vertype,ver,node
//这个小工程里的弧、边、道路为图的边(权值边),表示为 arc//校园景点的定义
typedef struct
{int num;                   //校园景点编号(权值)string name;               //校园景点名string information;        //校园景点的描述信息
}Vertype;//图的边的邻接矩阵表示
typedef struct
{int arcs[MAXVER][MAXVER];   //邻接矩阵表示弧或边(两点距离长权值)Vertype ver[MAXVER];        //景/顶点表int vernum;                 //图的当前景点数int arcnum;                 //图的当前边数
}MGraph;

文件body1.cpp如下:

#include"headPro.h"
/*#include"header.h":表明当前文件和"header.h"处于同一工程同一目录*/
/*#include<header.h>:表明header.h和当前文件不属于同一工程,是外部引用*/#include<stdlib.h>    //使用exit()
#include<fstream>     //使用输入文件流ifstream
#include<iostream>   //使用cin(),cout()
#include<iomanip>     //使用setw()//1、将filename所指文件按行输出到数组str[]中,返回表达式的实际个数
int inputString(char *filename,string str[])
{//功能:定义输入文件流对象infile,打开磁盘filename所指文件,并使filename所指文件与流对象infile关联。ifstream infile(filename,ios::in);//如果infile关联的文件打开失败,infile返回0if(!infile){cout<<"文件打开出错!"<<endl; //输出错误信息exit(1); //异常强行退出exe,读不到会闪现}int i=0;while(!infile.eof()) //infile关联的文件尚未到文件尾{getline(infile,str[i]); //从输入流对象infile所关联的文件读取一行存入str[i]i++;}infile.close();     //关闭infile所关联的磁盘文件return i - 1;           //返回表达式的实际个数
}//2、返回str中的数字字符串所对应的整数
int f1(string str)
{int result = 0;//for循环遍历字符串for(unsigned int i = 0; i < str.length(); i++){if(str[i] >= '0' && str[i] <= '9'){//根据ASCII,00110000~00111001表示'0'~'9'及十进制的规则result = result * 10 + str[i] - 48;}}//返回字符串所对应的整数return result;
}//3、将字符串按'<'分为三个子字符串
void f2(string str, string &str1, string &str2, string &str3){//使用string类的find函数分隔字符串int m = str.find('>');int n = str.find('>', m + 1);//for循环for(int i = 0; i < str.length(); i++){if(i < m){str1 += str[i];}                 //读编号else if(i > m && i < n){str2 += str[i];}   //读景点名称或编号else if(i > n){str3 += str[i];}            //读景点简介或两个景点之间的距离}
}//4、创建无向图
void createGraph(MGraph &G)
{//静态定义文件字符串数组string fileString[50];//静态定义三个子字符串数组string subString1[50];string subString2[50];string subString3[50];//将文件读入文件字符串数组,并返回文件里的表达式的个数//在文件字符串数组的两部分信息的空字符串之后 的第 lines 个元素的下标等于这里的表达式的个数 linesint lines = inputString("校园景点.txt",fileString);//使用for循环将文件字符串数组读入三个子字符串数组for(int i = 0; i <= lines; i++){   //if条件用于判断文件的两部分信息的空行if(fileString[i] == "\0"){   //记录文件的两部分信息的空行的下标(即当前图的节点数)G.vernum = i;//记录边的数目G.arcnum = lines - i;}//调用f2()函数,对读出的字符串数组的元素进行分隔三个字符串f2(fileString[i], subString1[i], subString2[i], subString3[i]);}//图的节点的初始化赋值for(int i = 0; i < G.vernum; i++){   //f1()函数,将字符串转为整数,存为景点的编号G.ver[i].num = f1(subString1[i]);//将字符串存为景点的名称G.ver[i].name = subString2[i];//将字符串存为景点的简介G.ver[i].information = subString3[i];}//初始化邻接矩阵//这里不使用G.vernum, 而是使用MAXVER的原因:增加景点时,方便dist[][]的初始化赋值for(int m = 0; m < MAXVER; m++){for(int n = 0; n < MAXVER; n++){   //将邻接矩阵赋为无穷大G.arcs[m][n] = INFINITY;}}//将景点的距离存入邻接矩阵for(int r = G.vernum + 1; r <= lines; r++){   //由于是无向图,因而路径是双向的G.arcs[f1(subString1[r])][f1(subString2[r])] = f1(subString3[r]);G.arcs[f1(subString2[r])][f1(subString1[r])] = f1(subString3[r]);}
}//5、打印图的全部景点的信息
void printDataOfGraph(MGraph G)
{//设置输出格式,向左边靠cout.setf(ios::left,ios::adjustfield);//使用setw()输出cout << setw(10) << "编号" << setw(15) << "名称" << "简介" << endl;for(int i = 0; i < G.vernum; i++){   //大致按格式输出景点的编号、名称、简介cout << setw(10) << G.ver[i].num << setw(15)<< G.ver[i].name << G.ver[i].information << endl;}cout << endl;
}//6、根据景点的编号,输出该景点的所有信息
void searchByNum(MGraph G)
{int num1;cout << "您好!输入格式:编号(只能是自然数,如0,1,2,3…… )+回车键" << endl;cout << "请您按格式输入您要查询景点的编号:";cin >> num1;//for循环查询for(int i = 0;i <= G.vernum; i++){if (i == num1) //匹配景点的编号{cout <<"您所查询的景点信息:" << endl;//输出景点信息cout << "编号:" << G.ver[i].num << "\t\t名称:" << G.ver[i].name << "\t\t简介:" << G.ver[i].information << endl;cout << endl;return;}//这里也可以改为用flag1标志变量的操作if(i == G.vernum){   //找不到,则显示查找不到的提示语cout << "对不起!通过您输入的编号所查询的景点不存在!" << endl;cout << endl;return;}}
}//7、根据景点的名称,输出该景点的所有信息
void searchByName(MGraph G)
{string str1;cout << "您好!请您输入您要查询景点的名称:" ;cin >> str1;for (int i = 0; i <= G.vernum; i++){if (str1 == G.ver[i].name)  //匹配景点的名称{cout <<"您所查询的景点信息如下行显示:" << endl;//输出景点信息cout << "编号:" << G.ver[i].num << "\t\t名称:" << G.ver[i].name << "\t\t简介:" << G.ver[i].information << endl;cout << endl;return;}if(i == G.vernum){//找不到,则显示查找不到的提示语cout << "对不起!通过您输入的名称所查询的景点不存在!" << endl;cout << endl;return;}}
}//8、floyd算法求最短路径
/** MGraph G: 是无向图* int **dist: 是指向 dist[][] (存储图的最短路径的邻接矩阵)的指针* int **path: 是指向 path[][] (记录图的最短路径的景点次序的矩阵)的指针
*/
void floyd(MGraph G, int **dist, int **path)
{int i,j,v;//将图的景点数赋给 nint n = G.vernum;//对数组 dist ,path 赋值for(i = 0; i < n; i++){for(j = 0; j < n; j++){   //这里很关键dist[i][j] = G.arcs[i][j];//-1表示从节点i到节点j是直达的或不连通的//不连通的问题由if(dist[][] == INFINITY)判断处理path[i][j] = -1;}}//三道循环实现for(v = 0; v < n; ++v)  //测试欲加入的节点{for(i = 0; i < n; ++i)  //路径的开端{for(j = 0; j < n; ++j)  //路径的终端{   //判断原来的路径长度值是否大于加入新节点的路径长度值if(dist[i][j] > dist[i][v] + dist[v][j]){   //松弛边,更新最短路径的长度值dist[i][j] = dist[i][v] + dist[v][j];//记录中间景点path[i][j] = v;}}}}
}//9、递归辅助打印最短路径
/** u 是最短路径的开端景点的编号* v 是最短路径的末端景点的编号* int **path: 是指向 path[][] (记录图的最短路径的景点次序的矩阵)的指针
*/
void printPath(int u, int v, int **path)
{//判断最短路径是直达路径就直接输出景点;否则就是间接路径(最短路径含有中间景点)if(path[u][v] == -1){   //直接输出cout << u << ">";}else{int mid = path[u][v];       //mid用于记录景点u到景点v的路径的中间路径景点(靠u的景点)printPath(u, mid, path);    //递归,节点u到节点midprintPath(mid, v, path);    //递归,节点mid到节点v}
}//10、显示任意两个景点的最短路径
void displayShortestPath(MGraph G)
{int num1, num2;bool flag1,flag2;cout << "您好!请您输入要查询最短路径的两个不同的景点的编号!" << endl;cout << "输入格式:编号(必须是自然数,范围:0至" << MAXVER-1 <<")+回车键" << endl;cout <<"请您输入起点景点的编号:";cin >> num1;cout <<"请您输入终点景点的编号:";cin >> num2;//第一道检验,提示用户输入的两个景点编号相同if(num1 == num2){cout << endl;cout << "对不起!您所输入的两个景点的编号一样,其实指的是同一个景点!" << endl;cout << "请您规范输入,谢谢配合!" << endl;cout << endl;return;}//判断输入景点是否存在,并且记录下来for(int i = 0; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配第一个景点的编号{   //存在,将flag1 赋值为 trueflag1 = true;}if(num2 == G.ver[i].num)    //匹配第二个景点的编号{flag2 = true;}}//第二检验,提示用户输入的两个景点编号不存在if(!(flag1 || flag2)){cout << "您好!您所输入的两个景点的编号对应的两个景点都不存在!" << endl;cout << endl;return;}else if(!flag1){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第一个输入的编号对应的景点不存在!" << endl;cout << endl;return;}else if(!flag2){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第二个输入的编号对应的景点不存在!" << endl;cout << endl;return;}//n 是记录图的节点的数量int n = G.vernum;//数组 dist[][] 是存储图的边的邻接矩阵int **dist = new int *[n];//数组 path[][] 是记录图的最短路径的节点次序的矩阵int **path = new int *[n];for(int j = 0; j < n; j++){dist[j] = new int[n];path[j] = new int[n];}//调用floyd(),给数组 dist, path 赋值floyd(G,dist,path);//最短路径的长度值赋给length1int length1 = dist[num1][num2];//第三道检验,找不到两个景点的可达到路径,则显示查找不到的提示语if(length1 == INFINITY){cout << "对不起!您所输入的两个景点没有路径可以到达!" << endl;cout << endl;return;}//调用printPath(),输出最短路径的中间节点printPath(num1,num2,path);//输出所查询的最短路径的信息cout << num2 << "=" << length1 << endl;cout << endl;//数组在函数结束时就没了,这里只需释放指针delete dist;delete path;return;
}//11、增加景点
void addNode(MGraph &G)
{int n = G.vernum;string name1;string info1;cout << "您好!输入格式:名称+空格+简介+回车键" << endl;cout << "请您按输入格式输入您要增加的景点的名称、简介:" << endl;cin >> name1 >> info1;//判断景点表是否满了if(n >= MAXVER){//满了,便显示节点空间不足的提示语cout << "对不起!景点空间已满,目前暂时无法增加景点!" << endl;cout << endl;return;}//循环将要增加的景点已经存在for(int i = 0; i < n; i++){if(name1 == G.ver[i].name)  //匹配要新加景点的名称{//提示用户所输入景点的名称已经存在cout << "您好!您所输入的要增加的景点的名称已经存在!无法进行增加景点!" << endl;cout << endl;return;}}//对新增加的景点赋值G.ver[n].num = n;G.ver[n].name = name1;G.ver[n].information = info1;//景点数加1G.vernum++;//显示成功增加景点的提示语cout << "您好!您已成功增加景点!" << endl;cout << endl;return;
}//12、增加道路
void addArc(MGraph &G)
{int num1, num2, arc1;bool flag1, flag2;  //标志变量,默认值为 falsecout << "您好!输入格式:第一个景点编号+空格+第二个景点编号+空格+道路的长度(只能是正整数)+回车键" << endl;cout << "景点的编号必须是自然数,范围:0至" << MAXVER-1 << endl;cout << "请您按 输入格式 输入您要增加的景点道路:";cin >> num1 >> num2 >> arc1;if(arc1 < 0){cout << "您好!道路的长度只能是正整数!请规范输入,谢谢配合!" << endl;cout << endl;return;}//提示用户输入的两个景点编号相同if(num1 == num2){cout << endl;cout << "对不起!您所输入的两个景点的编号一样,其实指的是同一个景点!" << endl;cout << "请您规范输入,谢谢配合!" << endl;cout << endl;return;}for(int i = 0; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配第一个景点的编号{flag1 = true;}if(num2 == G.ver[i].num)    //匹配第二个景点的编号{flag2 = true;}}//检查两个景点都存在if(!(flag1 || flag2)){cout << "您好!您所输入的两个景点的编号对应的两个景点都不存在, 无法增加道路!" << endl;cout << endl;return;}else if(!flag1){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第一个输入的编号对应的景点不存在,无法增加道路!" << endl;cout << endl;return;}else if(!flag2){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第二个输入的编号对应的景点不存在,无法增加道路!" << endl;cout << endl;return;}//检查两个景点之间不存在道路,才能进行增加道路(路径长)if(G.arcs[num1][num2] == INFINITY){   //在无向图的邻接矩阵里增加道路G.arcs[num1][num2] = arc1;G.arcs[num2][num1] = arc1;//道路数目加1G.arcnum++;cout << "您好!您已成功增加道路!" << endl;cout << endl;return;}else{cout << "您好!您所输入的两个景点的编号对应的两个景点已存在,且两个景点之间存在道路,无法进行增加道路!" << endl;cout << endl;return;}
}//13、修改景点的简介
void updateInformation(MGraph &G)
{int num1;string info1;bool flag1;     //标志变量cout << "您好!编号的输入格式:编号+回车键" << endl;cout << "景点的编号必须是自然数,范围:0至" << MAXVER-1 << endl;cout << "请您按编号的输入格式输入您要修改的景点的编号:";cin >> num1;cout << "您好!名称的输入格式:简介+回车键" << endl;cout << "请您按名称的输入格式输入您要修改的景点的新简介:";cin >> info1;int i = 0;for(; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配要修改景点的编号{   //标志变量赋值为 trueflag1 = true;//匹配到就跳出循环break;}}if(flag1){//修改景点的简介G.ver[i].information = info1;//显示修改成功的提示语cout << "您好!您已成功修改您所输入的景点的简介!" << endl;cout << endl;return;}else{//显示无法修改成功的提示语cout << "对不起!您所输入的景点的编号对应的景点不存在,无法进行修改景点的简介!" << endl;cout << endl;return;}
}//14、修改景点的名称
void updateName(MGraph &G)
{int num1;string name1;bool flag1;     //标志变量cout << "您好!编号的输入格式:编号+回车键" << endl;cout << "景点的编号必须是自然数,范围:0至" << MAXVER-1 << endl;cout << "请您按编号的输入格式输入您要修改的景点的编号:";cin >> num1;cout << "您好!名称的输入格式:简介+回车键" << endl;cout << "请您按名称的输入格式输入您要修改的景点的新名称:";cin >> name1;int i = 0;for(; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配要修改景点的编号{//标志变量赋值为 trueflag1 = true;//匹配到就跳出循环break;}}if(flag1){//修改景点的简介G.ver[i].name = name1;//显示修改成功的提示语cout << "您好!您已成功修改您所输入的景点的名称!" << endl;cout << endl;return;}else{//显示无法修改成功的提示语cout << "对不起!您所输入的景点的编号对应的景点不存在,无法进行修改景点的名称!" << endl;cout << endl;return;}
}//15、修改道路的长度值
void updateArc(MGraph &G)
{int num1, num2, arc1;bool flag1, flag2;  //标志变量,默认值为 falsecout << "您好!输入格式:第一个景点编号+空格+第二个景点编号+回车键" << endl;cout << "景点的编号必须是自然数,范围:0至" << MAXVER-1 << endl;cout << "请您按 输入格式 输入您要修改的道路所对应的两个景点:";cin >> num1 >> num2;cout << "道路的长度(只能是正整数)+回车键" << endl;cout << "请您按 输入格式 输入您要修改的道路的长度值:";cin >> arc1;if(arc1 < 0){cout << "您好!道路的长度只能是正整数!请规范输入,谢谢配合!" << endl;cout << endl;return;}//提示用户输入的两个景点编号相同if(num1 == num2){cout << endl;cout << "对不起!您所输入的两个景点的编号一样,其实指的是同一个景点!" << endl;cout << "请您规范输入,谢谢配合!" << endl;cout << endl;return;}for(int i = 0; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配第一个景点的编号{flag1 = true;}if(num2 == G.ver[i].num)    //匹配第二个景点的编号{flag2 = true;}}//检查两个景点都存在if(!(flag1 || flag2)){cout << "您好!您所输入的两个景点的编号对应的两个景点都不存在, 无法修改道路的长度值!" << endl;cout << endl;return;}else if(!flag1){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第一个输入的编号对应的景点不存在,无法修改道路的长度值!" << endl;cout << endl;return;}else if(!flag2){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第二个输入的编号对应的景点不存在,无法修改道路的长度值!" << endl;cout << endl;return;}//在无向图的邻接矩阵里修改道路G.arcs[num1][num2] = arc1;G.arcs[num2][num1] = arc1;cout << "您好!您已成功增加道路!" << endl;cout << endl;return;
}//16、删除道路
void deleteArc(MGraph &G)
{int num1, num2;bool flag1, flag2;  //标志变量,默认值为 falsecout << "您好!输入格式:第一个景点编号+空格+第二个景点编号+回车键" << endl;cout << "景点的编号必须是自然数,范围:0至" << MAXVER-1 << endl;cout << "请您按输入格式输入您要删除的景点道路所对应的两个编号:";cin >> num1 >> num2;//第一道检验,提示用户输入的两个景点编号相同if(num1 == num2){cout << endl;cout << "对不起!您所输入的两个景点的编号一样,其实指的是同一个景点!" << endl;cout << "请您规范输入,谢谢配合!" << endl;cout << endl;return;}for(int i = 0; i < G.vernum; i++){if(num1 == G.ver[i].num)    //匹配第一个景点的编号{flag1 = true;}if(num2 == G.ver[i].num)    //匹配第二个景点的编号{flag2 = true;}}if(flag1 && flag2){if(G.arcs[num1][num2] != INFINITY) //两个景点都存在&两个景点之间存在道路,才能进行删除道路(路径长){   //在邻接矩阵里删除道路,赋值为无穷大G.arcs[num1][num2] = INFINITY;G.arcs[num2][num1] = INFINITY;//道路的数目减去1G.arcnum--;//显示成功删除道路的提示语cout << "您好!您已成功删除道路!" << endl;cout << endl;return;}else{cout << "您好!您所输入的两个景点的编号对应的两个景点存在,但两个景点之间不存在道路,无法进行删除道路!" << endl;cout << endl;return;}}else if(!(flag1 || flag2)){cout << "您好!您所输入的两个景点的编号对应的两个景点都不存在!" << endl;cout << endl;return;}else if(!flag1){cout << "您好!您所输入的两个景点的编号对应的两个景点中,第一个输入的编号对应的景点不存在,无法进行删除道路!" << endl;cout << endl;return;}else{cout << "您好!您所输入的两个景点的编号对应的两个景点中,第二个输入的编号对应的景点不存在,无法进行删除道路!" << endl;cout << endl;return;}
}//17、删除景点
void deleteNode(MGraph &G)
{int num1;int k = G.vernum;   //图的景点数目赋值给kbool flag;     //标志变量cout << "输入格式:编号(必须是自然数,范围:0至" << MAXVER-1 <<")+回车键" << endl;cout << "请您按输入格式输入您要删除的景点的编号:";cin >> num1;int i = 0;for(; i < k; i++){if(num1 == G.ver[i].num){   //找到则设置标志变量为trueflag = true;//找到,则跳出循环break;}}if(flag){   //在被删除的景点之后的景点数组的景点,应向前移动一位for(int j = i; j < k - 1; j++){   //通过覆盖数据实现移动G.ver[j].name = G.ver[j+1].name;G.ver[j].information = G.ver[j+1].information;}//将最后一个景点"清除"G.ver[k-1].num = -2;G.ver[k-1].name = "";G.ver[k-1].information = "";/**删除景点的同时顺便把道路给删除了(没了景点留着道路没什么意义)*实现:把图的边对应的邻接矩阵(有实际的意义那部分)从 N×N 变为 (N-1)×(N-1)*///for查找要删除的景点的编号,在边的邻接矩阵相关的元素,再减少图的边数目for(int a = 0; a < G.vernum; a++){   //由于是无向图,因而只需处理行if(G.arcs[i][a] != INFINITY){G.arcnum--;}}//将图的边对应的邻接矩阵,从删除的景点的编号开始按行上移for(int m = i; m < k - 1; m++){for(int n = 0; n < G.vernum; n++){   //从要删除的景点开始,其所对应的边的邻接矩阵按行上移G.arcs[m][n] = G.arcs[m + 1][n];}}//将图的边对应的邻接矩阵,从删除的景点的编号开始按列左移for(int r = i; r < k - 1; r++){for(int s = 0; s < G.vernum; s++){   //在按行上移的基础上,再让边的邻接矩阵按列左移G.arcs[s][r] = G.arcs[s][r + 1];}}//将图的边对应的邻接矩阵,最右一行、最下一行的元素赋值为无穷大for(int t = 0; t < G.vernum; t++){G.arcs[k - 1][t] = INFINITY;G.arcs[t][k - 1] = INFINITY;}//景点的数目减去1G.vernum--;//显示成功删除道路的提示语cout << "您好!您已成功删除景点!" << endl;cout << endl;return;}else{//显示无法删除景点的提示语cout << "您好!您所输入的景点的编号对应的景点不存在,无法进行删除景点!" << endl;cout << endl;return;}
}

文件main.cpp如下:

#include"headPro.h"
/*#include"header.h":表明当前文件和"header.h"处于同一工程同一目录*/
/*#include<header.h>:表明header.h和当前文件不属于同一工程,是外部引用*/#include<iostream>   //使用cin(),cout()
#include<stdio.h>    //使用printf(),scanf()/*extern: 实现C++代码跨文件调用函数*/
extern int inputString(char *filename,string str[]);
extern int f1(string str);
extern void f2(string str, string &str1, string &str2, string &str3);
extern void createGraph(MGraph &G);
extern void printDataOfGraph(MGraph G);
extern void searchByNum(MGraph G);
extern void searchByName(MGraph G);
extern void floyd(MGraph G, int **dist, int **path);
extern void printPath(int u, int v, int **path);
extern void displayShortestPath(MGraph G);
extern void addNode(MGraph &G);
extern void addArc(MGraph &G);
extern void updateInformation(MGraph &G);
extern void updateName(MGraph &G);
extern void updateArc(MGraph &G);
extern void deleteArc(MGraph &G);
extern void deleteNode(MGraph &G);//18、大致显示无向图最初的形状
void showMap()
{printf("\t\t|------------------------------------------------------------------------|\n");printf("\t\t|                                                                        |\n");printf("\t\t|                             |-------|      [350]                       |\n");printf("\t\t|                [800]        | 7桃园 |----------------------|           |\n");printf("\t\t|        |--------------------|-------|                 |------|         |\n");printf("\t\t|  |------------|        [350] |   |                    |12沁湖|         |\n");printf("\t\t|  |10学而优超市| [180]        |   |                    |------|         |\n");printf("\t\t|  |------------|---------|-----|  |                        |            |\n");printf("\t\t|        |          ------|6李园|  |[370]                   |            |\n");printf("\t\t|        |          |     |-----|  |                        |[100]       |\n");printf("\t\t|        |     [130]|       |      |                        |            |\n");printf("\t\t|   [180]|          |   [90]|      |                        |            |\n");printf("\t\t|        |          |       |      |                        |            |\n");printf("\t\t|        |          |     |---------|       [100]         |--------|     |\n");printf("\t\t|        |          |     | 0励学楼 |---------------------|5 创业  |     |\n");printf("\t\t|     |----------|  |     |(一教) |    |----------|-----|  园区  |     |\n");printf("\t\t|     |11灯光球场|  |     |---------|    | 3 拓新楼 |[170]|--------|     |\n");printf("\t\t|     |----------|  |       |  |  |      |(实验楼)|        |           |\n");printf("\t\t|      |      |     |  [120]|  |  |      |----------|-----|  |           |\n");printf("\t\t|      |      |     |       |  |  |[200]       |     [330]|  |           |\n");printf("\t\t|      | [130]|   |----------| |  |        [20]|          |  |           |\n");printf("\t\t|      |      |---|13中心花园| |  -----|---------|        |  |[410]      |\n");printf("\t\t|      |          |----------| |       | 4       |-----|  |  |           |\n");printf("\t\t|      |          |    |       |       | 图书馆  |[350]|  |  |           |\n");printf("\t\t| [270]|          |[90]|       |[200]  |---------|     |  |  |           |\n");printf("\t\t|      |          |    |       |            |          |  |  |           |\n");printf("\t\t|      |          |    |       |       [300]|    |-------------|         |\n");printf("\t\t|      |     [250]|  |---------|-------------    |   2厚德楼   |         |\n");printf("\t\t|      |          |  | 1笃行楼 |                 |  (行政楼) |         |\n");printf("\t\t|      |          |  | (二教)|-----------------|-------------|         |\n");printf("\t\t|     |-----|     |  |---------|      [600]            |                 |\n");printf("\t\t|     |9三饭|     |     |                              |                 |\n");printf("\t\t|     |-----|     |     |[90]                          |                 |\n");printf("\t\t|        |        |     |                              |                 |\n");printf("\t\t|        |        |     |                              |                 |\n");printf("\t\t|    [80]|    |-----|----                         [700]|                 |\n");printf("\t\t|        -----|8竹园|-----------------------------------                 |\n");printf("\t\t|             |-----|                                                    |\n");printf("\t\t|                                                                        |\n");printf("\t\t|------------------------------------------------------------------------|\n");printf("\n");
}//19、显示导游系统的功能菜单
void menu1()
{cout << endl;cout << "|---------------------------校园导游系统功能菜单图------------------------------|\n";cout << "|*******************************************************************************|\n";cout << "|      1.显示最初的校园图的仿真界面;          2. 显示全部景点的信息             |\n";cout << "|      3.输入编号显示该景点的信息;            4. 输入名称显示该景点的信息       |\n";cout << "|      5.显示任意两个景点间的最短路径;        6. 增加某个景点                   |\n";cout << "|      7.增加某条道路;                        8. 删除某个景点                   |\n";cout << "|      9.删除某条道路;                        10.修改某个景点的简介             |\n";cout << "|      11.修改某个景点的名称;                 12.修改某条道路的长度值           |\n";cout << "|      0. 退出                                                                  |\n";cout << "|*******************************************************************************|\n";cout << endl;return;
}//20、主函数(测试函数)
int main()
{MGraph G;createGraph(G);menu1();cout << "******欢迎您的到来!******" << endl;cout << endl;cout << "请问你是要进行服务(y/n)?" << endl;char c1;cin >> c1;while(c1 == 'y'){int option;cout << endl;cout << "您好!请您先细看功能菜单,然后输入您要服务的编号:";cin >> option;//根据 acsii 表,做检查if(!(option >= 0 && option <= 12)){cout << "您所输入的编号有误,请规范输入,谢谢您的配合!" << endl;cout << endl;}switch(option){case 1:showMap();break;case 2:printDataOfGraph(G);break;case 3:searchByNum(G);break;case 4:searchByName(G);break;case 5:displayShortestPath(G);break;case 6:addNode(G);break;case 7:addArc(G);break;case 8:deleteNode(G);break;case 9:deleteArc(G);break;case 10:updateInformation(G);break;case 11:updateName(G);break;case 12:updateArc(G);break;case 0:c1 = 'n';break;}}return 0;
}

参考文献

[1] 严蔚敏,李冬梅,吴伟民. 数据结构(C语言).北京:人民邮电出版社,2011年2月第一版

[2] 李春葆. 数据结构教程(第4版)上机实验指导. 北京:清华大学出版社,2013年1月第一版

[3] 史蒂芬·普拉达(Stephen Prata). C Primer Plus (第6版)中文版. 北京:人民邮电出版社

[4] 史蒂芬·普拉达(Stephen Prata). C++ Primer Plus (第6版)中文版. 北京:人民邮电出版社

[5] [美]Robert Sedgewick Kevin Wayne 著,谢路云 译. 算法(第4版). 北京:人民邮电出版社


http://www.ppmy.cn/news/523622.html

相关文章

如何在微信复制链接直接可以用浏览器打开 微信调用手机浏览器打开指定链接

由于微信的限制&#xff0c;应用文件在内置浏览器中下载全部被屏蔽掉&#xff0c;造成很多人用微信扫描二维码下载时&#xff0c;界面显示一片空白&#xff0c;容易误导以为在下载呢 <!DOCTYPE html> <html> <head> <meta charset"utf-8" />…

68款大规模机器学习数据集,涵盖CV、语音、NLP | 十年资源集

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑ 作者 | 琥珀 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 此前营长为大家分享过不少机器学习相关数据集的资源&#xff0c;例如 Mozilla 的 1400 小时开源语音数据集&#xff1b;ApolloScape 的大规模自动…

[APIO2009] 采油区域:动态规划

题目描述&#xff1a; Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井。被拍卖的整块土地为一个矩形区域&#xff0c;被划分为MN个小块。 Siruseri地质调查局有关于Navalur土地石油储量的估测数据。这些数据表示为MN个正整数&#xff0c;即对每一…

大学里

每个安慰你挂科算什么的人 最后都默默拿了奖学金&#xff1b; 每个夸你肥嘟嘟的脸好可爱的人&#xff0c; 最后都瘦成了万人迷&#xff1b; 每个在你面前说自己前途渺茫的人&#xff0c; 最后都身家过亿&#xff1b; 只有你&#xff0c; 在满床的薯片袋和电脑荧光照射下&#x…

表情识别论文《OAENet Oriented Attention Ensemble for Accurate FacialExpression Recognition》中文翻译

本篇博客为论文OAENet: Oriented Attention Ensemble for Accurate Facial Expression Recognition的中文翻译&#xff0c;如有翻译错误请见谅&#xff0c;同时希望您能为我提出改正建议&#xff0c;谢谢&#xff01; 论文链接&#xff1a;https://www.sciencedirect.com/scie…

腾讯员工用漫画自述悲惨职场经历,网友大呼:社会巨婴

最近微博上有几组“漫画”火了&#xff0c;但是却引发了巨大的争议&#xff0c;漫画作者微博昵称为“知春鹿可不这么想”&#xff0c;作者自称是腾讯的实习生&#xff0c;并通过漫画的形式描述着自己秋招、面试、实习等生活状态。 这是其中一篇漫画。 很多网友直接说出作者就是…

无线传感器网络:网络层

文章目录 Challenges for RoutingEnergy EfficiencyScalabilityAddressingRobustnessTopologyApplication Routing MetricsQuality-of-Service (QoS)Minimum HopEnergyMinimum energy consumed per packetMaximum time to network partitionMaximum average energy capacityMax…

元宇宙虚拟人迎来高峰期,哪个是你的最爱?

虚拟人从最初的不温不火&#xff0c;到现在步入“出生高峰期”&#xff0c;元宇宙可以说是功不可没。 此前&#xff0c;量子位发布了《虚拟数字人深度产业报告》&#xff0c;报告显示&#xff0c;到2030年我国虚拟数字人整体市场规模将达到2700亿元。其中&#xff0c;“身份型…