校园导航系统

该文讨论了一个利用Floyd算法解决校园导游程序中的最短路径问题。通过邻接矩阵存储图信息,使用Floyd算法计算任意两个景点之间的最短路径,以满足赛事系统中参赛者的导航需求。文章涉及图的存储、遍历以及Dijkstra和Bellman-Ford算法的对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 问题分析和任务定义

1.1 问题描述和要求

【问题描述】  赛事系统为参赛者提供赛地的校园导游程序。为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询,即查询任意两个目的地(建筑物)之间的一条最短的简单路径。

【基本要求】赛地目的地查询,需提供目的地(建筑物)名称、代号、简介等信息;最短路径的输出需包含途经地及最短路径值。

1.2 问题分析

 这是一个图论问题,校园内道路一般是双向通行的,所以这是一个无向图。下面先对图的基本概念进行介绍:

图由节点(顶点)和边组成,用 G=(V,E) 表示,其中 V 表示节点的集合,E 表示边的集合。边可以是有向的,也可以是无向的。图可以分为有向图和无向图。

2. 图的存储

图的存储方式有两种:邻接矩阵和邻接表。邻接矩阵是一个二维数组,其中矩阵中的每个元素表示两个节点之间的边的权重;邻接表是由链表构成的数组,每个节点包含一个指向与其相邻的节点的指针。

3. 图的遍历

图的遍历有两种方式:深度优先搜索(DFS)和广度优先搜索(BFS)。DFS 从一个起点开始,沿着一条路径尽可能深地访问节点,直到无法继续为止,然后回退到上一个节点,继续访问其他路径。BFS 从一个起点开始,先访问所有与起点相邻的节点,然后访问与这些节点相邻的节点,以此类推。

4. 最短路径

最短路径算法用于计算两个节点之间的最短路径,其中最著名的算法是 Dijkstra 算法和 Bellman-Ford 算法。Dijkstra 算法用于计算有向无环图(DAG)中的最短路径,而 Bellman-Ford 算法可以处理带有负权边的图。

对于图的存储结构而言,图中各个景点的存储结构有邻接表和邻接矩阵两种存储结构,考虑到顶点个数少于50个,所以邻接表和邻接矩阵的复杂度相同。本题中选择使用邻接矩阵来表示图。

任务中要求求解出图中景点的问路查询,即为给定两个源点,求解出两个顶点之间的最短路径。校园中道路没有负权边,可以不使用Bellman-Ford 算法。Dijkstra算法是求单元最短路径的算法,即是求某个顶点到其余各顶点的最短路径。而Floyd算法是动态规划算法,求任意两个顶点之间的最短路径。,floyd算法解决了所有顶点到所有顶点的最短路径问题。相比之下,floyd算法的时间复杂度为O(n ^ 3),空间复杂度是O(n ^ 2),算法优点是,可以算出任意两点间的最短路径,代码编写也较简单。缺点是,时间复杂度比较高,不太适合大量数据的计算。对于校园导航,景点很少,所以使用floyd算法

数据结构的选择

此问题需要用到邻接矩阵,因此采用了数组。

概述

本实验的编程语言采用 Java ,主要是求解通过Floyd算法求解图论问题

Graph类和Vertex类

结点信息的数据结构:类——View 用于存储各个结点的详细信息,如景点编号、名称和景点介绍等class Graph{//地图

    Vertex vex[]=new Vertex[20];

    int dis[][]=new int[20][20];

}

class Vertex{//景点

    String name;

    String info;

    public Vertex() {



    }

    public Vertex(String name,String info) {

        this.name=name;

        this.info=info;

    }

}

 GraphMain

这部分主要是学校地图的打印,程序中用到的校园平面图可以用制表符绘制出来,虽然过程繁琐,但是较为简单方便。

 PrintPath

这部分主要是存储了各个顶点之间的距离,并使用了Floyd算法对最短路径进行求解。

算法步骤:

弗洛伊德算法选取某个节点k作为i到j需要经过的中间节点,通过比较d(i,k)+d(k,j)和现有d(i,j)的大小,将较小值更新为路径长度,对k节点的选取进行遍历,以得到在经过所有节点时i到j的最短路径长度,通过不断加入中间点的方式更新最短路径。同时在path数组中存储i到j所经过的中间节点k,用于最后递归调用输出路径结果。

其中matrix[i,j]表示i到j的最短距离,k是穷举i到j之间可能经过的中间点,当中间点为k时,对整个矩阵即从i到j的路径长度进行更新,对所有可能经过的中间点进行遍历以得到全局最优的最短路径。算法的单个执行将找到所有顶点对之间的最短路径长度,与迪杰斯特阿拉算法的计算目标有一些差异,迪杰斯特拉计算的是单源最短路径,而弗洛伊德计算的是多源最短路径,其时间复杂度为O(n³)。虽然它不返回路径本身的细节,但是可以通过对算法的简单修改来重建路径,我们利用这个思想,通过递归的方式访问每条路径经过的中间节点,对最终的路径进行输出。

算法中的三层for循环,第一层循环设置中间点k,第二层循环设置起始点i,第三层循环设置结束点j。

下面是示意图图例

 

 

实现简单的查询,各风景的查询,调用各函数,实现课程设计的目标。其中包含三个功能,一个是直接进入导航系统,利用主函数中已有的数据,进行查询:一个是进行创建数据,本程序中初始数据为农大的导航数据,如果需要也可以自己建立一个;最后一个是退出功能。设计该函数的目的是为了能够多次得应用dijkstra函数进行查询最短路径。同时该函数可以列出各景点的代号和对应的名称,这样大家只要输入代号就行了。方便进行查询。下面分别描述这些函数,建立它们函数原型。 1、主函数 函数原型:void main(void) 功 能:控制程序。 参 数:void 返 回 值:void 要 求:管理菜单命令完成初始化。 2、菜单选择和处理函数 函数原型:int menu() 功 能:处理选择的菜单命令接收用户选择的命令代码。 参 数:int 返 回 值:int 工作方式:返回命令代码的整数值,根据命令,调用相应函数。 要 求:只允许选择规定键,如果输入不合要求,则提醒用户重新输入。 3、建立邻接矩阵函数 函数原型:void createadj() 功 能:重新建立一个学生信息的记录。 参 数:void 返 回 值:void 工作方式:在需要的时候就可以有主菜单中调用 void createadj()函数。 要 求:必需输入信息记录,然后才能调用出search()函数进行查询。 4、dijkstra函数 函数原型:void dijkstra(intx,inty) 功 能:求两点间的最短路径 参 数:void 返 回 值:void 工作方式: 该函数被其它一些函数调用。 5、结束程序 函数原型:int Exit() 功 能:使程序正常结束运行 参 数:int 返 回 值:1 工作方式:在操作都完成后,可以调用int Exit()函数,使函数最终返回 1 运行exit(1),程序正常结束。 要 求:运行Exit()函数后可以选择是否要保存,选择y则先保存再返 回1值;如果选择n直接返回1值。详细的程序设计应从下到上,在本设计中就要先设计createadj函数;然后设计dijkstra函数;接着是search函数;menu函数;最后才是main函数。如此设计能大大提升设计速度,因为从下往上使编程时的高试过程简单许多,而做课程设计花费时间最多的就是调试过程。对于各函数的详细设计,各函数的N—S图如下: (1)Createadj函数 (2)Dijkstra函数          (3)Search函数          (4)Menu函数          (5)main函数          2.4 程序编码   把详细设计的结果进一步求精为程序设计语言程序。同时入一些注解和断言,使程序中逻辑概念清楚;编写过程中参考各种的教材和材料,使程序编写的正确性大有提高,同时也许到许多实践知识,增了实践经验。 2.5 程序调试与测试    程序编写总是出现各种各样的错误,但是难点不是修改错误,而是找出错误。在大量的源程序中找出错误难度很大,但有了一定的方法,就能节省大量的时间,在这次课程设计中我运用的调试方法主要有2种:     一是借助调试工具。利用Turbo C中提供的程序专门调试工具Debugger程序,可以很容易找出程序中的各种语法错误。但是遇到一些逻辑错误时却又无从着手。这时我就用下面一种方法。     二是在程序中插入打印语句。猜测出大致的错误位置,选则一些主要变量,在关键部位插入打印语句,打印出这个主要变量,看其是否与理论上的一样,在多个位置插入,如果有个位置的值与理论值一样,另一个位置与理论值不一样,则错误就落在这两个位置之间,然后再多测试几个位置缩小范围,直到找出错误。  例如;我在调试main()主函数时,程序能够运行,三个选项都能选择,创建函数能够正常运行,也能正常退出,但在选第一条进入校园导航后,打印出来的列表却是空的,源程序中的初始化数据没有显示出来,我又尝试输入两个结点进行查找,发现没有输出路线,所以我猜测初始化数据没有被正常写入。但不知道为何没有被正常写入,首先怀疑是初始化时附值发生错误,查阅各种资料进行校验,发现没有错误。后来经过综合分析,发现最有可能是n值在search()函数中发生错误,于是我在search()函数中插入打印n 的语句,运行后发现输出的n为0,初始化数据中有11个结点,n应该为11,所以n 在这个地方发生错误,我又在main()主函数中打印出n 的值,n=11,是正确的。所以错误就在search()函数中,也就说是当运行case1,运行到search()函数时,n从11变为0,针对这个错误,我把变量n改为宏定义,因为n 是代表结点个数,不管在哪个函数中它的值都是一样的才对。改完后运行程序,成功! 本设计文件的注释如上,已给出详细的说明,下面仅以文件为单位说明各个函数的作用和特点,在必要的地方给予一定说明。  3.1、guide.h文件 使用条件编译。以下是头文件中语句 /********************************************* *头文件(.h) ********************************************/ #include "stdio.h" #include "conio.h" #include "alloc.h" #define n0 100 #define infi 32767 /*“无穷大*/ int adjmatrix[n0+1][n0+1];     /*邻接矩阵*/ int n=11; struct node             /*表结点*/ { char name[20];       /*下一个表结点与它们之间的距离*/ }place[12]={{"ShiDiGongYuan"},   /*表结点初始化,即写各景点名称*/    {"CangRongGongYu"},    {"YinHuiLou"},    {"TuoHuanGuanChang"},    {"DiBaShiTang"},    {"XiaoYiYuan"},    {"TuShuGuan"},    {"TiYuGuan"},    {"ZhongHuaGuanChang"},    {"ChuangXinLou"},    {"YiFuTuShuGuan"},    {"BoXueLou"}};  void createadj()          /*建立邻接表*/  void dijkstra( int x,int y)     /*dijkstra求最小生树*/  void search()            /*搜索最短路径*/  menu()               /*菜单函数*/          /********************************************* *建立邻接表 ********************************************/ void createadj()  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值