校园导航系统(图实现)数据结构课程实践

需求分析

功能需求:

查询景点信息:用户可以通过输入景点名称,查看该景点的名称和简介。

查询最短路径:用户可以输入起始景点和目标景点,系统会计算并显示最短路径,包括路径的长度和沿途经过的景点及描述。

退出:用户可以选择退出系统。

界面需求:

显示所有景点列表:在用户交互界面中,需要显示所有校园景点的列表,以便用户进行选择和操作。

用户操作菜单:提供用户选择的菜单,包括查询景点信息、查询最短路径和退出选项。

操作提示:在用户进行输入时,需要给予相应的提示,确保用户能够正确操作系统。

接口需求:

用户输入接口:系统需要能够接收用户输入,包括景点名称、起始景点和目标景点等。

查询结果显示接口:系统需要能够将查询结果显示给用户,包括景点信息、最短路径和相关描述。

系统操作接口:用户在交互界面上的操作需要与系统进行交互,包括添加顶点、添加边等操作。

概要设计

模块层次结构设计

程序的模块层次结构主要包括以下几个模块:

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

​​​​​

  • 25
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值