需求分析
功能需求:
查询景点信息:用户可以通过输入景点名称,查看该景点的名称和简介。
查询最短路径:用户可以输入起始景点和目标景点,系统会计算并显示最短路径,包括路径的长度和沿途经过的景点及描述。
退出:用户可以选择退出系统。
界面需求:
显示所有景点列表:在用户交互界面中,需要显示所有校园景点的列表,以便用户进行选择和操作。
用户操作菜单:提供用户选择的菜单,包括查询景点信息、查询最短路径和退出选项。
操作提示:在用户进行输入时,需要给予相应的提示,确保用户能够正确操作系统。
接口需求:
用户输入接口:系统需要能够接收用户输入,包括景点名称、起始景点和目标景点等。
查询结果显示接口:系统需要能够将查询结果显示给用户,包括景点信息、最短路径和相关描述。
系统操作接口:用户在交互界面上的操作需要与系统进行交互,包括添加顶点、添加边等操作。
概要设计
模块层次结构设计
程序的模块层次结构主要包括以下几个模块:
CampusGuide 类: 校园导游服务的核心类,包含了添加顶点、添加边、查询景点信息、查询最短路径等功能。
Vertex 结构体: 用于表示图中的顶点,包含名称和描述信息。
Edge 结构体: 用于表示图中的边,包含长度和描述信息。
主函数模块: 包括用户交互、系统初始化和调用 CampusGuide 类的功能。
接口设计
CampusGuide 类的公共接口:
void addVertex(const string& name, const string& description):
输入:顶点的名称 (name) 和描述 (description)。
输出:无。
void addEdge(int from, int to, int length, const string& description):
输入:起始顶点索引 (from)、目标顶点索引 (to)、边的长度 (length) 和描述 (description)。
输出:无。
void findShortestPath(int start, int destination) const:
输入:起始顶点索引 (start) 和目标顶点索引 (destination)。
输出:打印最短路径、路径长度以及沿途经过的景点和描述。
void viewAllVertices() const:
输入:无。
输出:以表格形式打印所有景点的列表。
void userInteraction():
输入:通过用户在控制台的选择,可能包括数字等。
输出:执行用户选择的操作,显示相应的信息。
其他接口:
int minDistance(const vector<int>& distance, const vector<bool>& visited) const:
输入:起始点到各点的最短距离 (distance) 和节点是否被访问的标志 (visited)。
输出:返回未访问节点中距离最小的节点索引。
void findAllPaths(int start, int destination, vector<bool>& visited, vector<int>& path) const:
输入:起始顶点索引 (start)、目标顶点索引 (destination)、节点是否被访问的标志 (visited) 和当前路径 (path)。
输出:打印所有从起始点到目标点的简单路径。
void findAndDisplayAllPaths(int start, int destination) const:
输入:起始顶点索引 (start) 和目标顶点索引 (destination)。
输出:打印所有从起始点到目标点的简单路径。
其他辅助函数的接口:
int findVertexIndex(const string& vertexName) const:
输入:待查找的景点名称 (vertexName)。
输出:返回景点在顶点列表中的索引,如果找不到返回 -1。
void displayShortestPath(int start, int destination, const vector<int>& distance, const vector<int>& previous) const:
输入:起始顶点索引 (start)、目标顶点索引 (destination)、起始点到各点的最短距离 (distance) 和最短路径中的前一个节点 (previous)。
输出:打印最短路径、路径长度以及沿途经过的景点和描述。
界面设计
数据结构设计
Vertex 结构体:
成员变量:string name(顶点名称)、string description(顶点描述)。
Edge 结构体:
成员变量:int length(边的长度)、string description(边的描述)。
CampusGuide 类:
成员变量:vector<Vertex> vertices(存储顶点信息的向量)、vector<vector<Edge>> adjacencyMatrix(邻接矩阵,存储边的信息)。
其他辅助数据结构:
vector<int> distance: 存储起始点到各点的最短距离。
vector<bool> visited: 记录节点是否被访问。
vector<int> previous: 记录最短路径中的前一个节点。
详细设计
#include <iostream>
#include <vector>
#include <limits>
#include <iomanip>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int INF = numeric_limits<int>::max();
//Vertex 结构体表示图中的顶点,包含两个字符串成员:name(顶点名称)和 description(顶点描述)。
struct Vertex {
string name;
string description;
};
//Edge 结构体表示图中的边,包含两个成员:length(边的长度)和 description(边的描述)。
struct Edge {
int length;
string description;
};
//CampusGuide类,处理具体的操作
class CampusGuide {
private:
vector<Vertex> vertices;//是一个向量(动态数组),存储类型为 Vertex 结构体的元素。
vector<vector<Edge>> adjacencyMatrix;//是一个二维向量(二维动态数组),存储类型为 Edge 结构体的元素。
public:
// 添加顶点
void addVertex(const string& name, const string& description) {
vertices.push_back({name, description});
// 初始化邻接矩阵
for (auto& row : adjacencyMatrix) {
row.push_back(Edge{INF, ""});
}
//作确保了在添加新顶点时,邻接矩阵的每一行都会有一个额外的元素,以表示新顶点到其他顶点的边。
//这样的设计使得邻接矩阵保持正确的结构,并与图的拓扑结构一致
adjacencyMatrix.push_back(vector<Edge>(vertices.size(), Edge{INF, ""}));
}
// 添加边(双向)
void addEdge(int from, int to, int length, const string& description) {
adjacencyMatrix[from][to].length = length;
adjacencyMatrix[from][to].description = description;
adjacencyMatrix[to][from].length = length; // 假设路径是双向的
adjacencyMatrix[to][from].description = description;
}
// Dijkstra找到最短路径,可选择是否打印所有最短路径
void findShortestPath(int start, int destination) const {
// 获取顶点数量
int n = vertices.size();
char key=0;
// 初始化距离、访问状态和前驱数组
vector<int> distance(n, INF);
vector<bool> visited(n, false);
vector<int> previous(n, -1);
// 设置起始顶点到自身的距离为0
distance[start] = 0;
// 进行 n-1 次迭代,找到从起始顶点到其他顶点的最短路径
for (int count = 0; count < n - 1; ++count) {
// 选择当前距离最短且未访问的顶点
int u = minDistance(distance, visited);
visited[u] = true;
// 更新从起始顶点到未访问顶点的距离和前驱信息
for (int v = 0; v < n; ++v) {
if (!visited[v] && adjacencyMatrix[u][v].length != INF &&
distance[u] + adjacencyMatrix[u][v].length < distance[v]) {
distance[v] = distance[u] + adjacencyMatrix[u][v].length;
previous[v] = u;
}
}
}
// 显示最短路径的信息
displayShortestPath(start, destination, distance, previous);
cout<<"是否显示全部简单路径?(y/n)"<<endl;
cin>> key;
if(key=='Y'||key=='y')
// 查找并显示所有从起始顶点到目标顶点的路径
findAndDisplayAllPaths(start, destination);
}
//显示景点选择
void viewAllVertices() const {
cout << "╔════════════════════════╗" << endl;
cout << "║ 所有景点列表 ║" << endl;
cout << "╠════════════════════════╣" << endl;
for (const auto& vertex : vertices) {
cout << "║ " << setw(22) << left << vertex.name << " ║" << endl;
}
cout << "╚════════════════════════╝" << endl;
}
// 用户交互
void userInteraction() {
int choice;
do {
system("cls");
viewAllVertices();
cout << "==========杭电校园导游服务==========" << endl;
cout << "1. 查询景点信息" << endl;
cout << "2. 查询最短路径" << endl;
cout << "3. 退出" << endl;
cout << "====================================" << endl;
cout << "请输入操作编号:";
while (!(cin >> choice) || choice < 1 || choice > 3) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "无效操作,请重新输入!" << endl;
}
switch (choice) {
case 1:
queryVertex();
break;
case 2:
queryShortestPath();
break;
case 3:
cout << "欢迎下次使用校园导游服务!" << endl;
break;
default:
cout << "无效操作,请重新输入!" << endl;
break;
}
} while (choice != 3);
}
private:
// 查找距离数组中未访问顶点的最小距离
int minDistance(const vector<int>& distance, const vector<bool>& visited) const {
int minDist = INF, minIndex = -1;
for (size_t v = 0; v < distance.size(); ++v) {
if (!visited[v] && distance[v] <= minDist) {
minDist = distance[v];
minIndex = v;
}
}
return minIndex;
}
// 深度优先搜索,找到所有从start到destination的路径
void findAllPaths(int start, int destination, vector<bool>& visited, vector<int>& path) const {
// 标记当前顶点为已访问,并将其添加到路径中
visited[start] = true;
path.push_back(start);
// 如果当前顶点是目标顶点,输出路径
if (start == destination) {
cout << "路径: ";
for (size_t i = 0; i < path.size(); ++i) {
cout << vertices[path[i]].name;
if (i < path.size() - 1) {
cout << " -> ";
}
}
cout << endl;
} else {
// 否则,继续深度优先搜索
for (size_t v = 0; v < vertices.size(); ++v) {
// 如果顶点未访问且有连接到下一个顶点的边
if (!visited[v] && adjacencyMatrix[start][v].length != INF) {
findAllPaths(v, destination, visited, path);
}
}
}
// 回溯:取消标记当前顶点为未访问,并将其从路径中移除
visited[start] = false;
path.pop_back();
}
// 显示最短路径信息
void displayShortestPath(int start, int destination, const vector<int>& distance, const vector<int>& previous) const {
vector<int> path;
for (int v = destination; v != -1; v = previous[v]) {
path.push_back(v);
}
cout << "从 " << vertices[start].name << " 到 " << vertices[destination].name << " 的最短路径为:" << endl;
for (int i = path.size() - 1; i >= 0; --i) {
cout << vertices[path[i]].name;
if (i > 0) {
cout << " -> ";
}
}
cout << endl;
cout << "路径长度为:" << distance[destination] << " 米" << endl;
// 显示路径上的景点和描述
cout << "沿途经过的景点和描述:" << endl;
for (int i = path.size() - 1; i > 0; --i) {
int u = path[i];
int v = path[i - 1];
cout << vertices[u].name << " -> " << vertices[v].name << ": " << adjacencyMatrix[u][v].description << endl;
}
}
// 查找并显示所有从start到destination的路径
void findAndDisplayAllPaths(int start, int destination) const {
vector<bool> visited(vertices.size(), false);
vector<int> path;
cout << "所有从 " << vertices[start].name << " 到 " << vertices[destination].name << " 的简单路径为:" << endl;
findAllPaths(start, destination, visited, path);
}
// 查询指定名称的景点信息
void queryVertex() const {
string vertexName;
cout << "请输入要查询的景点名称:";
cin.ignore(); // 忽略之前的回车符
getline(cin, vertexName);
viewVertexInfo(vertexName);
}
// 查询最短路径
void queryShortestPath() const {
string startVertex, endVertex;
cout << "请输入起始景点名称:";
cin.ignore(); // 忽略之前的回车符
getline(cin, startVertex);
cout << "请输入目标景点名称:";
getline(cin, endVertex);
int start = findVertexIndex(startVertex);
int destination = findVertexIndex(endVertex);
if (start != -1 && destination != -1) {
findShortestPath(start, destination);
system("pause");
} else {
cout << "找不到指定的景点,请确认输入的名称是否正确。" << endl;
system("pause");
}
}
// 辅助函数:查找指定景点名称的索引
int findVertexIndex(const string& vertexName) const {
for (size_t i = 0; i < vertices.size(); ++i) {
if (vertices[i].name == vertexName) {
return static_cast<int>(i);
}
}
return -1;
}
// 辅助函数:显示指定景点的信息
void viewVertexInfo(const string& vertexName) const {
for (const auto& vertex : vertices) {
if (vertex.name == vertexName) {
cout << "景点名称: " << vertex.name << endl;
cout << "景点简介: " << vertex.description << endl;
system("pause");
return;
}
}
cout << "找不到名称为 " << vertexName << " 的景点。" << endl;
system("pause");
}
};
int main() {
CampusGuide campus;
// 添加顶点
campus.addVertex("体育馆", "提供体育锻炼和比赛的场馆。");//0
campus.addVertex("羽毛球馆", "提供羽毛球运动的场地。");//1
campus.addVertex("足球场", "举办足球比赛和训练的场地。");//2
campus.addVertex("西篮球场", "提供篮球运动的场地。");//3
campus.addVertex("行政楼", "学校行政办公的地方。");//4
campus.addVertex("月雅湖", "宁静美丽的湖泊,供学生休闲娱乐。");//5
campus.addVertex("国际教育中心", "为国际学生提供学习和生活支持的场所。");//6
campus.addVertex("科技馆", "展示科技成果和进行科普教育的场所。");//7
campus.addVertex("问鼎广场", "学校的标志性广场,有杭电的标志性建筑。");//8
campus.addVertex("学生活动中心", "学生举办各类活动的中心。");//9
campus.addVertex("东操场", "学生进行体育锻炼的场地。");//10
campus.addVertex("美食城", "具有多种独特,种类不同的小吃店。");//11
campus.addVertex("清真餐厅", "具有独特的清真文化餐厅。");//12
campus.addVertex("西北体育场", "举办大型体育赛事的场地。");//13
campus.addVertex("游泳馆", "提供游泳的场馆。");//14
campus.addVertex("图书馆", "集读书、借书、自习于一体的文化场所。");//15
// 添加边
campus.addEdge(0, 1, 59, "一条宽敞的步行道连接体育馆和羽毛球馆。");
campus.addEdge(0, 12, 228, "一条马路连接体育馆和清真餐厅。清真在体育馆东面。");
campus.addEdge(0, 14, 293, "一条宽敞的马路连接体育馆和游泳馆,游泳馆在体育馆西北。");
campus.addEdge(0, 15, 246, "一条宽敞的东西方向步行道连接体育馆和图书馆,图书馆在体育馆正东。");
campus.addEdge(1, 2, 37, "羽毛球馆到足球场中间有一条小道。");
campus.addEdge(1, 3, 312, "羽毛球馆到西篮球场有南北方向校园主干道连接。");
campus.addEdge(1, 8, 431, "羽毛球馆到问鼎广场中间有一条小道。");
campus.addEdge(2, 3, 68, "西篮球场在足球场正南,中间有一条小道。");
campus.addEdge(3, 4, 186, "西篮球场出来沿校园主干道往南走即可到达行政楼(在南大门西侧)。");
campus.addEdge(3, 8, 176, "西篮球场与问鼎广场中间有一条宽敞的校园主干道。");
campus.addEdge(4, 5, 216, "行政楼与月雅湖中间有校园主干道,经过南大门。");
campus.addEdge(5, 6, 509, "月雅湖出来往校园主干道往北走第一个路口右转后沿路200米后路口右转可到达国际教育中心。");
campus.addEdge(5, 8, 311, "月雅湖与问鼎广场有南北方向校园主干道连接。");
campus.addEdge(5, 9, 524, "月雅湖与学生活动中心有南北方向校园主干道连接。");
campus.addEdge(6, 7, 28, "国际教育中心西北侧为科技馆。");
campus.addEdge(6, 9, 586, "国际教育中心与学会活动中心南北经过学校主要教学楼,横跨教学区南北。");
campus.addEdge(6, 8, 457, "国际教育中心与问鼎广场有几条条宽敞的步行道,途径9教,10教与3教。");
campus.addEdge(8, 15, 195, "问鼎广场与图书馆有校园主干道连接。");
campus.addEdge(9, 10, 65, "学生活动中心和东操场有南北方向小道相邻。");
campus.addEdge(9, 11, 111, "学生活动中心和美食城有南北方向道路相邻,需经过一条马路。");
campus.addEdge(9, 15, 240, "学生活动中心和图书馆相连。");
campus.addEdge(11, 12, 425, "美食城与清真餐厅有小路相连。");
campus.addEdge(12, 13, 167, "清真餐厅到西北体育场有一条步行道。");
campus.addEdge(11, 14, 600, "学活出来沿学林街往西是杭电游泳馆。");
campus.addEdge(9, 14, 600, "美食城出来沿学林街往西是杭电游泳馆。");
campus.userInteraction();
return 0;
}