校园导航(C++)

这是刚2020年7月份刚上完《数据结构与算法分析》这门课的时候提交的课程大作业。当时还取得了 不错的成绩,现在回头来看简直是太拉胯了,整个项目所有函数、过程等都放在了一个文件,还将各个函数特意用注释隔开为了让老师阅读方便觉得自己简直是良心学生,至于C++的面向对象这些特性更是完全没影子。

//----------------------------(没错,就是这样的横线)
void path_print(int start, int end,int path_arr[]) //打印最短路径

写这篇文章是打算将我的辣鸡代码重构一下,由于时间太长了,所以正好一边在这里梳理一边修改我的代码。
(这里提供的还是 过程性 C++,修改后的代码会随着上传)

1.题目:校园导游系统

1.1 问题描述

设计一个校园导游系统,为来校参观的人们提供建筑和道路信息查询服务。

1.2 功能描述

  1. 设计一个所在学校的建筑和道路平面图,所含建筑不少于10个,并建立全局坐标,按照全局右手定则确定角度;
  2. 存储各建筑点的信息,包括位置坐标(二维)和简要介绍(例如:G栋,理学楼);
  3. 提供图中任意建筑点的相关信息查询,即输入关键字可输出相关信息(例如:输入G栋;给出结果:G栋,理学楼,坐标(2, 3));
  4. 提供图中多个建筑点的最佳访问路线查选,即求途经n(任意)个景点的最短路径,并给出所经过的点的方位和长度。(给定开始和结束景点,并一共包含n个景点,从A栋到G栋,途径A-B-C-D-F-G,在B点位于A点30°方向并距离A点5);
  5. 提供任意建筑点问路查询,即查询某个建筑到其他任意一个建筑点的最短路径,并按照路径长度从小到大的顺序排列(不能使用迪杰斯特拉算法)。

1.3 实现提示

  1. 以图中顶点表示校内各建筑点,存放建筑名称、代号、简介等信息,以边表示道路,存放道路长度等相关信息
  2. 一般情况下,校园道路是双向通行,可设校园平面图是一个无向网,顶点和边均含有相关信息

2.实现过程

2.1 获取地图数据

2.1.1坐标测量

因为每个地点只需要获得二维坐标,因此以学校大门为原点建立坐标系,在高德地图(打钱!)上大致量出来距离即可。
坐标测量
(这里选多少点都无所谓,反正也不用手动规划路径,当然是越多可能分数越高)

struct building//建筑信息结构体
{
    string name;//建筑名称
    int x;//坐标
    int y;
    string information;//建筑信息
};
const int BUILDING_NUMBER=16;
//结构数组存储所有建筑信息
building arr[BUILDING_NUMBER] = {//序号,名称,坐标,信息};

2.1.2路径测量

路径测量
图中的点不全代表关键结点,有的只是为了使测量准确设置的中继点。
接下来用邻接矩阵将所有信息存起来

const int MAX_NUMBER = 9999;//定义一个很长的路径代表不通,直接用INT_MAX会导致后续计算溢出
 int weight[BUILDING_NUMBER][BUILDING_NUMBER] = {//详细路径}

2.1.3 地图显示

(这一步完全是内卷的真实体现,在和同学交流的过程中发现大家竟然用符号把地图绘制出来了,震惊!赶紧自己也安排上)
地图打印
(我弄的就是这效果,完全是cout+各种符号拼成的,听说卷王们画得很优美)

void campus_maps()//打印地图
{
    cout << " _______________________________________________________________________________________________________" << endl;
    cout << "|-------------------------------哈尔滨工业大学(深圳)平面图--------------------------------------------|" << endl;
    cout << "|                                                                                                       |" << endl;
    cout << "|     *(E栋)-----*(D栋)------*(F栋)------*---------\\                                                |" << endl;
    cout << "|     |           |           /            /  (C栋)   \\------*(B栋)                                 |" << endl;

2.2 功能实现

2.2.1 使用指引

引导

int main()
{
    campus_maps();//校园地图全貌
    short_path_floyd(weight, path_matrix, short_path_table);//求取所有最短路径
    char mode;
    int a=1;//循环标志
    while (a==1)
    {
        cout << "输入1进入查询模式,2进入问路模式,3进入路径规划模式,q退出:" << endl;

        cin >> mode;

        while (mode != '1' && mode != '2' && mode != '3' && mode != 'q' && mode != 'Q')
        {
            cout << "输入有误,请重新输入!\n输入1进入查询模式,2进入问路模式,3进入路径规划模式,q退出:" << endl;
            cin >> mode;
        }
        //-----------------------------------------------
        while (mode == '1')//查询模式
        {
            string find_name;
            cout << "你想要查:";
            cin >> find_name;
            int sequence = find_sequence(find_name);
            while (sequence == -1)
            {
                cout << "无此信息,请重新输入:";
                cin >> find_name;
                sequence = find_sequence(find_name);
            }
            cout << "所查信息为:" << arr[sequence].name << "  简介:" << arr[sequence].information << "  坐标:( " << arr[sequence].x << " , " << arr[sequence].y << " ) " << endl;
            cout << endl; 
            break;
        };
        //------------------------------------------------
        while (mode == '2')//问路模式,查询指定点到所有点的最短路径
        {
            string start_name;
            cout << "输入起点:";
            cin >> start_name;
            int sequence = find_sequence(start_name);
            while (sequence == -1)
            {
                cout << "无此信息,请重新输入:";
                cin >> start_name;
                sequence = find_sequence(start_name);
            }

            int end_arr[BUILDING_NUMBER - 1];//定义一个终点数组
            int j = 0;
            for (int i = 0; i < BUILDING_NUMBER; i++)
            {
                //int j = 0;
                if (i != sequence)
                {
                    end_arr[j] = i;
                    j++;
                }

            }
            length_sort_all(sequence, end_arr, path_matrix, short_path_table);//对给定起点到所有终点按路径长度进行排序
            cout << "从这里到其他所有地方的最短路径为:" << endl << endl;
            for (int i = 0; i < BUILDING_NUMBER - 1; i++)
            {
                int path_arr[BUILDING_NUMBER - 1];
                path_print(sequence, end_arr[i], path_arr);
                cout << endl;
            }
            cout << endl;
            break;
        }
        //-------------------------------------------------
        while (mode == '3')//路径规划模式
        {
            cout << "输入起点和终点:";
            
            string front, behind;
            cin >> front >> behind;
            int front_sequence = find_sequence(front);
            int behind_sequence = find_sequence(behind);
            while (front_sequence == -1 || behind_sequence == -1)
            {
                cout << "无此信息,请重新输入:";
                cin >> front >> behind;
                front_sequence = find_sequence(front);
                behind_sequence = find_sequence(behind);
            }

            cout << "输入途径景点数量:";
            int node_number;
            cin >> node_number;
            stack[0] = front_sequence;//将起点入栈
            for (int i = 0; i < BUILDING_NUMBER; i++)//初始化所有未访问
                visited[i] = false;
            visited[front_sequence]=true;//初始化起点为访问
            dfs(front_sequence, behind_sequence, node_number);//求解
            int fit_path_number=0;//符合要求的路径数目
            
            dfs_sort_print(path_vector, node_number, path_amount, fit_path_number);
            cout << endl; 
            path_amount = 0;//路径数重置为0
            break;
            
        };
        while (mode == 'q' || mode == 'Q')//退出
        {
            cout << "谢谢,再见!\n";
            a = 0;//循环标志置0
            cout << endl;
            break;
        };

    }
}

2.2.2 功能:查询模式—打印相关点的信息

这个功能没什么难度。

int find_sequence(string name)
{
    int i = 0;
    for (i; i < BUILDING_NUMBER; i++)
    {
        if (arr[i].name == name)
        {
            return i;
            break; 
        }; 
    };
    return -1;//没找到返回-1
}

本来直接输入输入string遍历查询就可以了,但是由于后面要用到矩阵的时候,还是需要某一点的序号,所以这里也干脆先找到序号,然后再访问arr[i]。
实现效果:
查询模式

2.2.3 功能:问路模式—实现指定点到所有点的最短路径

这个需求有点特别,需要给定一个点,求出对其他所有点的最短路径,这里使用弗洛伊德(Floyd)算法。这个算法是照着《大话数据结构》一步一步码出来的。

void short_path_floyd(int weight[][BUILDING_NUMBER], int path_matrix[][BUILDING_NUMBER], int short_path_table[][BUILDING_NUMBER])
{
    int v, w, k;
    for (v = 0; v < BUILDING_NUMBER; v++)//初始化  path_matrix  和  short_path_table
    {
        for (w = 0; w < BUILDING_NUMBER; w++)
        {
            short_path_table[v][w] = weight[v][w];
            path_matrix[v][w] = w;
        }
    }
    for (k = 0; k < BUILDING_NUMBER; k++)
    {
        for (v = 0; v < BUILDING_NUMBER; v++)
        {
            for (w = 0; w < BUILDING_NUMBER; w++)
            {
                if (short_path_table[v][w] > short_path_table[v][k] + short_path_table[k][w])
                {
                    short_path_table[v][w] = short_path_table[v][k] + short_path_table[k][w];
                    path_matrix[v][w] = path_matrix[v][k];
                }
            }
        }
    }
}

2.2.4 输入任意起点和终点以及需要途径点的数量,打印最短路径和导航

记得这个需求跟老师确认了很久才搞清楚是要干嘛。演示如下图:
导航演示
利用深度优先搜索将所有符合要求的路径找出来再排序:

void dfs(int start,int stop,int node_number)//深度优先搜索路径
{
    int i, j;
    for (i = 0; i < BUILDING_NUMBER; i++)
    {
        if (weight[start][i] != MAX_NUMBER&& m<node_number&&visited[i]==false)
        {
            if (i == stop)//如果深搜到了终点,就输出刚才经过的路径
            {
                path_length += weight[start][i];

                for (j = 0; j < m; j++)
                {
                    path_vector[path_amount].path_arr[j] = stack[j];//存路径

                }
                path_vector[path_amount].path_arr[m] = stop;//存终点
                path_vector[path_amount].node_amount = m + 1;//存途径点的数量
                //cout << "此条路径长度为" << path_length << endl;
                path_vector[path_amount].path_total_length = path_length;//存长度
                path_amount++;//每到一次终点,路径数目+1
                path_length -= weight[start][i];
            }
            else///如果该点不是终点
            {
                visited[i] = true;
                path_length += weight[start][i];
                int length = weight[i][start];//暂存路长信息
                weight[start][i] = MAX_NUMBER;
                weight[i][start] = MAX_NUMBER;
                stack[m] = i;//将该点存起来
                m++;
                dfs(i,stop,node_number);//接着深搜
                visited[i] = false;
                weight[start][i] = length;
                weight[i][start] = length;
                path_length -= weight[start][i];
                m--;
            }
        }
    }
}

这个DFS的的编写历程颇为坎坷,是折磨我最久的一个部分,看过很多博主的写法,在各路大神的基础上有了我这个魔改版本。主要是那时候还没有理解递归的精髓,我一直以为递归返回之后后面的语句就不再执行了,打通了这个心结之后,自我感觉数据结构和算法算是真正入门了。(菜鸡本鸡)

递归的终极奥义:
递归==套娃

求方位:

double angle(int front, int behind)//求方位角
{
    double x1 = arr[front].x;
    double y1 = arr[front].y;
    double x2 = arr[behind].x;
    double y2 = arr[behind].y;
    
    double angle_rad=atan( (y1 - y2)/ (x1 - x2));//计算两点间的方向(弧度表示)
    angle_rad = angle_rad * 180 / acos(-1);//返回角度表示
    if (x2 <= x1 && y2 > y1)
        return angle_rad + 180;
    else
        if (x2 <= x1 && y2 < y1)
            return angle_rad - 180;
        else
            if (x2 < x1 && y2 == y1)
                return angle_rad + 180;
            else
                if (x2 > x1&& y2 == y1)
                    return 0;
                else
                    return angle_rad;
}

或许这就是程序开发的精髓所在——一个if else解决不了的,那就再加一个。

2.2.5 其他的支撑功能

没什么技术难点了,完全是为了成绩好看点做的表面功夫——设计的奥义?

3.总结

这个作业是我接触coding/C++/算法与数据结构以来做的第一个小项目,所有功能都通过暴力实现,完全没考虑有设计模式这个东西(现在知道但还没学到这一块来:( hhh)

随着代码量的上升和阅读量的提高,动手前规划的更多了,通过复盘也知道了做这个作业时欠缺的各种考虑。

关于博客:
也算是培养自己的程序员开源精神,一路写下来还真是挺麻烦的,希望后面能坚持下去。求一键三连

2021/1/17更新:我还是没抽出时间把我的代码优化 :(
2024/6/25更新:代码链接见github:点击跳转github campus_map_guide代码仓库

  • 43
    点赞
  • 190
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 以下是一个简单的c++校园导航程序,可以根据用户输入的起点和终点,输出最短路径和路线。 ```cpp #include <iostream> #include <vector> #include <queue> using namespace std; // 存储每个点的邻接点和对应边的距离 vector<pair<int, int>> graph[1000]; // 存储每个点的最短距离和是否访问过 int dist[1000]; bool visited[1000]; // 存储路径 vector<int> path; // Dijkstra算法求最短路 void Dijkstra(int start, int end) { // 初始化 for (int i = 0; i < 1000; i++) { dist[i] = INT_MAX; visited[i] = false; } dist[start] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, start)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (u == end) { break; } if (visited[u]) { continue; } visited[u] = true; for (int i = 0; i < graph[u].size(); i++) { int v = graph[u][i].first; int w = graph[u][i].second; if (!visited[v] && dist[u] + w < dist[v]) { dist[v] = dist[u] + w; pq.push(make_pair(dist[v], v)); } } } } // 输出最短路径 void printPath(int start, int end) { path.push_back(end); int u = end; while (u != start) { for (int i = 0; i < graph[u].size(); i++) { int v = graph[u][i].first; int w = graph[u][i].second; if (dist[u] == dist[v] + w) { path.push_back(v); u = v; break; } } } cout << "最短路径为:"; for (int i = path.size() - 1; i >= 0; i--) { cout << path[i]; if (i > 0) { cout << " -> "; } } cout << endl; } int main() { // 建 graph[1].push_back(make_pair(2, 10)); graph[1].push_back(make_pair(6, 5)); graph[2].push_back(make_pair(1, 10)); graph[2].push_back(make_pair(3, 6)); graph[2].push_back(make_pair(4, 5)); graph[3].push_back(make_pair(2, 6)); graph[3].push_back(make_pair(4, 4)); graph[4].push_back(make_pair(2, 5)); graph[4].push_back(make_pair(3, 4)); graph[4].push_back(make_pair(5, 3)); graph[5].push_back(make_pair(4, 3)); graph[5].push_back(make_pair(6, 8)); graph[6].push_back(make_pair(1, 5)); graph[6].push_back(make_pair(5, 8)); // 输入起点和终点 int start, end; cout << "请输入起点和终点(1~6):"; cin >> start >> end; // 求最短路径 Dijkstra(start, end); printPath(start, end); return 0; } ``` 该程序建立了一个简单的无向,每个点对应一个数字(1~6),通过输入起点和终点,使用Dijkstra算法求出最短路径,并输出路径。 ### 回答2: 校园导航c程序功能介绍: 校园导航是一个简单的C语言程序,用于帮助用户在校园中找到不同建筑物的位置。该程序主要包括菜单功能和地点查询功能。 程序开始时,用户将看到一个主菜单,包括以下选项: 1. 显示所有建筑物及其位置 2. 查询某个建筑物的位置 3. 退出程序 如果用户选择菜单选项1,程序将显示所有建筑物及其位置的列表。列表中的每个建筑物都有一个唯一的编号和名称。用户可以通过查找这个编号或名称来了解建筑物的位置。 如果用户选择菜单选项2,程序将提示用户输入要查询建筑物的编号或名称。程序将在建筑物列表中查找与用户提供的查询信息匹配的结果,并显示该建筑物的位置。 如果用户选择菜单选项3,程序将退出。 程序实现代码示例: ```c #include <stdio.h> #include <string.h> // 建筑物结构体 typedef struct { int id; char name[50]; char location[100]; } Building; // 全局的建筑物列表 Building buildings[] = { {1, "教学楼A", "A校区一号楼"}, {2, "教学楼B", "B校区三号楼"}, {3, "书馆", "B校区五号楼"} }; // 显示所有建筑物及其位置 void showBuildings() { int size = sizeof(buildings) / sizeof(Building); printf("建筑物列表:\n"); for (int i = 0; i < size; i++) { printf("%d. %s - %s\n", buildings[i].id, buildings[i].name, buildings[i].location); } } // 查询某个建筑物的位置 void searchBuilding() { int size = sizeof(buildings) / sizeof(Building); char query[50]; printf("请输入要查询的建筑物编号或名称:"); scanf("%s", query); for (int i = 0; i < size; i++) { if (strcmp(query, buildings[i].name) == 0 || atoi(query) == buildings[i].id) { printf("%s的位置是:%s\n", buildings[i].name, buildings[i].location); return; } } printf("未找到匹配的建筑物。\n"); } int main() { int choice; do { printf("\n校园导航菜单:\n"); printf("1. 显示所有建筑物及其位置\n"); printf("2. 查询某个建筑物的位置\n"); printf("3. 退出程序\n"); printf("请选择菜单选项:"); scanf("%d", &choice); switch (choice) { case 1: showBuildings(); break; case 2: searchBuilding(); break; case 3: printf("程序已退出。\n"); break; default: printf("无效的选项。\n"); break; } } while (choice != 3); return 0; } ``` 以上就是一个简单的校园导航C程序的实现。用户可以通过程序菜单选择查看建筑物列表或查询特定建筑物的位置。程序会根据用户的选择展示相应的结果。 ### 回答3: 校园导航C是一个简单的校园导航程序,主要帮助学生和访客在校园内快速找到目的地。该程序基于C语言编写,使用了简单的文本界面。 首先,用户启动程序后,会看到一个欢迎界面,提供了校园导航的功能和快捷键说明。用户可以通过输入不同的指令来实现不同的功能。 首先,用户可以输入指令查看校园地,程序会显示校园的平面,并用字符表示建筑物和道路。用户可以通过地上的编号来查找特定的建筑物。 用户还可以选择输入指令来获取建筑物的具体信息。比如,输入编号或名称,程序会返回该建筑物的相关描述,以及周围环境说明和使用注意事项。 另外,程序还提供了路径导航功能。用户可以输入起点和终点的编号或名称,程序会通过路径算法计算出最短路径,并逐步指引用户前往目的地。 此外,用户还可以输入指令来查询校园内的服务设施和活动信息。比如,用户可以输入“食堂”或“书馆”的关键词,程序会返回相关的服务设施信息和活动安排。 最后,用户可以通过输入“退出”指令来退出校园导航C程序。 总之,校园导航C是一个简单实用的校园导航程序,可以帮助用户快速找到校园内的目的地,方便学生和访客的校园生活。该程序使用了简单的文本界面,方便用户操作和查找信息。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值