C语言实现--校园导航系统

设计目的

现在的大学占地面积越来越大,建筑物越来越多,功能越来越多样,校内的道路也是纵横交错,校园导航系统可以帮助用户更加快速的了解学校的路线,建筑布局及建筑物的基本信息等(用户主要是新生、家长、教职工、外来参观人员等),在帮助用户了解校园路线、实现导航的功能的基础上,校园导航系统还录入了学校各个地点的相关信息,以供使用者更方便快捷的找到目的地。
随着科学技术的不断发展,计算机科学日渐成熟,其强大的功能已为人们所深刻认识,它己进入人类社会的各个领域并发挥着越来越重要的作用。采用计算机进行校园导航已成为衡量校园数字化的重要标志。校园导航效率的好坏对于来校参观的客人和学校管理者来说都至关重要,在很大程度上影响着校园的数字化建设和学校的影响力。因此,本次课程设计研究的校园导航系统具有一定的使用价值和现实意义。

设计需求

1.从西南大学的平面图中选取一些有代表性的景点,抽象成一个无向带权图.
2.使用迪杰斯特拉算法提供最优路径查询

设计内容

该校园导航的使用者分为游客和管理者,功能如下:

游客

-针对游客的校园导航使用说明
-查看校园全景图,附有校园地点的所有路线情况
-输入任意地点,查询该地点的信息,包括地点介绍和相关路线
-输入任意两地点,输出两点之间的所有简单路线
-输入任意两地点,输出两点之间的一条中转次数最少的最短路线
-输入任意两地点,输出两点之间的一条带权路径最短的最有路线
-输入任意地点,输出从该点出发的最佳布网方案

管理员(除游客功能外,还有以下功能)

-使用管理员功能首先需要登录,登陆成功方可使用导航管理员功能
-可以在地图中添加新地点
-可以在地图中添加新路线
-可以在地图中撤销旧路线
-注册新的管理员帐号

各个模块详细的功能描述

导航使用说明:描述该导航应该如何使用,具有什么功能

校园平面简图:输出一张有校园所有地点的平面图,可以直观的看出校园地点的分布。这是利用了每个地点所存储的坐标,通过对矩阵元素的遍历,输出了各地点的具体方位。并且在平面图下面以这样的形式附有校园两地点相连的所有路线信息:起点<—->终点:xxx m

查看地点信息:任意输入一个地点序号,输出该地点的介绍,以及所有与该地点连通的路线及其距离

查询简单路径:任意输入两个地点,输出两地点间所有的简单路径。利用图的深度搜索遍历,用栈将经过的地点序号存起来,然后每条路线的地点逐个输出,最后得到所有简单路径

查询最短路径:任意输入两个地点,输出两地点间一条中转次数最少的路线。利用图的广度搜索遍历,用队列将要遍历的地点存起来,通过对队列的操作得到中转次数最少的路线

查询最优路径:任意输入两个地点,输出两地点间一条带权路径最短的路线。利用迪杰斯特拉算法,通过对dist和 path的操作得出最终的最短路线

最佳布网方案:任意输入一个地点,输出从该点出发的最佳布网方案。这是利用了最小生成树的思想,运用了Prim算法的思想

添加新地点:输入新地点的名称和坐标,通过对文件增删改的操作,将新地点存储到文件里,就生成了一张新地图

添加新路线:输入新路线的起点、终点 、距离,通过对文件增删改的操作,将新路线存储到文件里,就生成了一条新路线

撤销旧路线:输入要撤销路线的起点、终点、距离,通过对文件增删改的操作,将改动后的路线信息存储到文件里

管理员的登录:管理员可在此输入帐号和密码进行登录,在输入密码时也可以选择是否隐藏密码,如果输入帐号密码不对应,则可重新输入,若错误三次则自动退出系统。通过对用户输入的帐号密码和“admin.txt”文件里保存的帐号密码进行比较,如果相同则可登录

管理员的注册:管理员可在此输入帐号和密码进行注册,密码需要输入两遍,相同则注册成功。通过对“admin.txt”文件增删改的操作,将新帐号和密码存储到文件里,就生成了一个新的管理员帐号

队列的操作:有队列的判空、队列的初始化、出队、入队函数

创建无向图:采用邻接矩阵的结构,通过对“路线信息”文件和“地点介绍”文件的读取,将信息存储到邻接矩阵中,然后创建出带权无向图

游客和管理员菜单:游客和管理员可在其对应的菜单页面进行功能选择

重点设计及相关代码

数据结构类型的选择:邻接矩阵

#define MAXVEX 50
#define INFINITY 32768
#define MAXL 20
#define MAXC 66

int visited[INFINITY];
int stack[INFINITY];
int count;

struct user //保存管理员帐号密码的结构体
{
    char id[20];  //管理员帐号
    char passwd[20];  //管理员密码
    struct user *next;
};
typedef struct //保存地点信息的结构体
{
    int No;    //校园地点序号
    char name[20];    //校园地点名
    char description[200];  //地点描述
}Vextype;
typedef struct //邻接矩阵
{
    int arcs[MAXVEX][MAXVEX];   //边集
    Vextype vex[MAXVEX];        //顶点集
    int vexnum;                 //顶点数目
    int arcnum;                 //边数目
}AdjMatrix;
typedef struct //坐标矩阵
{
    int point; //该点是否为校园地点
    char name[20]; //该点校园地点名
    int No; //该点校园地点序号
}SchoolMap;

typedef struct Node
{
    int date;  //队列元素的值,存储地点序号
    struct Node *next;
}LinkQueueNode;
typedef struct
{
    LinkQueueNode *front; //头指针
    LinkQueueNode *fear; //尾指针
}LinkQueue;
int IsEmpty(LinkQueue *Q) //队列判空
{
    if(Q->front == Q->fear)
        return 1;
    else
        return 0;
}
int InitQueue(LinkQueue *Q)//队的初始化
{
    Q->front = (LinkQueueNode *)malloc(sizeof(LinkQueueNode));
    if(Q->front != NULL) {
        Q->fear = Q->front;
        Q->front->next = NULL;
        return 1;
    }
    else {
        return 0;
    }
}

创建带权无向图

// 采用邻接矩阵创建无向图
int Create(AdjMatrix *G,SchoolMap M[MAXL][MAXC])
{
    int i,j,weight,m,n;

    FILE *fp1;
    fp1=fopen("路线信息.txt","r");

    //从"路线信息.txt"文件中读取校园图的景点数目和路线数目
    fscanf(fp1, "%d %d", &G->vexnum, &G->arcnum);

    //初始化邻接矩阵
    for(i = 1; i <= G->vexnum; i++)
        for(j = 1; j<= G->vexnum; j++) {
            G->arcs[i][j] = INFINITY;
    }
    //读取"路线信息.txt"文件中两点序号及距离,并赋值给邻接矩阵
    while(fscanf(fp1,"%d %d %d",&i,&j,&weight) != EOF) {
            G->arcs[i][j] = weight;
            G->arcs[j][i] = weight;
    }
    fclose(fp1);

    FILE *fp2;
    fp2 = fopen("地点介绍.txt", "rt");

    //从"地点介绍.txt"文件中读取校园图中的景点名及描述
    for(i = 1; i <= G->vexnum; i++) { 
        G->vex[i].No = i; // 将顶点集中的地点序号设为i值
        // fscanf()函数是根据数据格式(format),从输入流(stream)中读入数据,存储到argument中,遇到空格和换行时结束。
        // 数据依次是:地点名称、、、地点简介
        fscanf(fp2, "%s %d %d %s", G->vex[i].name,&m,&n,G->vex[i].description);
        M[m][n].point = 1;
        M[m][n].No = i;
        strcpy(M[m][n].name,G->vex[i].name);
    }
    fclose(fp2);
    return 1;
}

查询所有简单路径:深度搜索遍历DFS算法

void DFS(AdjMatrix *G, int m, int i, int end)
{
    int j,k;
    for(j = 1; j <= G->vexnum; j++){
        if(G->arcs[i][j] != INFINITY && visited[j] == 0) {
            visited[j] = 1;
            if(j == end) {
                count++;
                printf("★%d.",count);
                for(k = 1; k < m; k++) {
                    printf("%s->", G->vex[stack[k]].name);
                }
                printf("%s\n", G->vex[end].name);
                visited[j] = 0;
            }
            else {
                stack[m] = j;
                m++;
                DFS(G, m, j, end);
                m--;
                visited[j] = 0;
            }
        }
    }
}

查询中转次数最少路径:广度搜索遍历BFS算法

void BFS(AdjMatrix *G, int start, int end)
{
    int vis[INFINITY];
    int i, num;
    int w, v;
    LinkQueue *Q;

    Q=(LinkQueue*)malloc(sizeof(LinkQueue));
    if(start == end)
        return;
    memset(vis, 0, INFINITY);
    vis[start] = 1;
    InitQueue(Q);
    EnterQueue(Q, start);
    while(Q->front != Q->fear){
        DeleteQueue(Q, &v);
        num = v;
        for(i = 1;i <= G->vexnum; i++){
            if(G->arcs[num][i] != INFINITY) {
                w = i;  //求出当前节点的第一个邻接点(求出序号)
                while(w != -1){
                    if(vis[w] == 0){
                        if(w == end){
                            BFS(G, start, num);
                            printf("%s->",G->vex[num].name);
                            return;
                        }
                        vis[w] = 1;
                        EnterQueue(Q, w);
                        w = NextAdjVertex(G, w, v);
                        //w是求的得第一个邻接点,v是相对w下一个邻接点(求出下一个邻接点的序号)
                    }
                    break;
                }
            }
        }
    }
}

查询带权路径最短:Dijkstra算法

// Dijkstra算法
void Dijkstra(AdjMatrix *G, int start, int end, int dist[], int path[][MAXVEX])
{
    int mindist, i, j, k, t = 1;
    for(i = 1; i <= G->vexnum; i++) {
        dist[i] = G->arcs[start][i];  //对dist数组初始化
        if(G->arcs[start][i] != INFINITY)
            path[i][1] = start;  //如果该弧存在,则path[i][1]为源点
    }
    path[start][0] = 1; //start加入到S中
    for(i = 2; i <= G->vexnum; i++) {  //寻找各条最短路径
        mindist = INFINITY;
        for(j = 1; j <= G->vexnum; j++)
            if(!path[j][0] && dist[j] < mindist) {
                k = j;
                mindist = dist[j];
            }

            if(mindist == INFINITY)
                return ;
            path[k][0] = 1;   //找到最短路径,将该点加入到S集合中
            for(j = 1; j <= G->vexnum; j++) {  //修改路径
                if(!path[j][0] && G->arcs[k][j] < INFINITY && dist[k]+G->arcs[k][j] < dist[j]) {
                    dist[j] = dist[k] + G->arcs[k][j];
                    t = 1;
                    while(path[k][t] != 0) {
                        path[j][t] = path[k][t];
                        t++;
                    }
                    path[j][t] = k;
                    path[j][t+1] = 0;
                }
            }
    }

    for(i = 1; i <= G->vexnum; i++)
        if(i == end)
            break;
    printf("\n    ★★★%s--->%s的最短路线为: 从%s",G->vex[start].name,G->vex[end].name,G->vex[start].name);
    for(j = 2; path[i][j] != 0; j++) {
        printf("->%s",G->vex[path[i][j]].name);
    }
    printf("->%s, 距离为%d m\n",G->vex[end].name,dist[i]);
    printf("\n\t\t\t\t\t按任意键返回...");
    getch();
}

最佳布网方案:最小生成树Prim算法

// prim算法构建最小生成树
void Prim(AdjMatrix *G, int start)
{
    struct
    {
        int adjvex;
        int lowcost;
    }closedge[MAXVEX];
    int i, e, k, m, min;
    closedge[start].lowcost = 0;

    // 对除了出发点以外deep所有顶点初始化对应的closedge数组
    for(i = 1; i <= G->vexnum; i++) {
        if(i != start) {
            closedge[i].adjvex = start;
            closedge[i].lowcost = G->arcs[start][i];
        }
    }

    for(e = 1; e <= G->vexnum-1; e++)  //控制选中的n-1条符合条件的边
    {
        //选择权值最小的边
        min = INFINITY;
        for(k = 1; k <= G->vexnum; k++) {
            if(closedge[k].lowcost != 0 && closedge[k].lowcost < min) {
                m = k;
                min = closedge[k].lowcost;
            }
        }
        printf("\t\t\t\t\t从%s---%s:%d m\n", G->vex[closedge[m].adjvex].name,G->vex[m].name,closedge[m].lowcost);
        closedge[m].lowcost = 0;

        for(i = 1; i <= G->vexnum; i++) {
            if(i != m && G->arcs[m][i] < closedge[i].lowcost) {
                closedge[i].lowcost = G->arcs[m][i];
                closedge[i].adjvex = m;
            }
        }
    }
    printf("\n\t\t\t\t\t按任意键返回...");
    getch();
}

测试结果

初始界面

image.png

游客界面
image.png

管理员登录

管理员界面
image.png

导航说明界面
image.png

校园平面简图


查询景点信息

查询简单路线

查询中转次数最少的路径

查询最优路径

查询最佳布网方案
image.png

添加新地点

添加新路线

撤销旧路线

管理员注册
image.png

写在后面

终于写完啦!!!
刚了好几个星期!!!
这个项目几乎囊括了数据结构大部分知识,在这个过程中查了不少的资料,也看了不少视频,总结了许多。虽然这个demo还有bug,后面会继续改进!

详细代码

https://github.com/ljr7822/iwenHub

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容

  • 一、设计目的 现在的大学占地面积越来越大,建筑物越来越多,功能越来越多样,校内的道路也是纵横交错,校园导航系统可以...
    ggdd5151阅读 657评论 0 2
  • 1.设计思想 利用迪杰斯特拉求单源最短路算法,设计出郑州升达经贸管理学院的校园导航,求出学校一个景点到另一个景点的...
    LEMFOooO阅读 1,217评论 0 0
  • 1 需求分析 设计并显示某学校的校园平面图 地点(地点名称、地点介绍) 路线(公里数)均不少于10个(文件存储) ...
    ggdd5151阅读 609评论 0 1
  • 一直以为只要自己努力了,就会有收获,才发现付出和收获不是成正比的,也许自己太过于急功近利,亦或是自己太在意这份收获...
    奕聿心言阅读 85评论 0 0
  • 下周我们要进行一次辩论赛,主题是,无友不如己。 我们支持的是不交。 我觉得不应该交和自己志向不同的朋友,如果志向不...
    TATA鸭阅读 513评论 2 1