|
|
|
|
# UrbanHighwayNavigationSystem
|
|
|
|
|
|
|
|
|
|
# 项目名称 城市公路导航系统
|
|
|
|
|
|
|
|
|
|
杨腾泽,刘鑫成,李培毅,孙英皓
|
|
|
|
|
|
|
|
|
|
**摘要**:
|
|
|
|
|
(1) 基于真实的公路数据建立导航地图模型,编制成格式简单的数据文件包括城市线路名称、站点名称。
|
|
|
|
|
(2)系统能够读取公路导航地图数据文件,建立公路模型,也能够将模型输出成数据文件,以便验证模型的正确性。
|
|
|
|
|
(3)通过人机交互的方式输入起点和终点站名称,系统给出路径长度最短的导航路径。
|
|
|
|
|
(4)能够读取不同的地铁导航地图进行功能测试。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 1. 系统分析
|
|
|
|
|
通过各种算法,实现公路导航
|
|
|
|
|
|
|
|
|
|
## 1.1 问题描述
|
|
|
|
|
|
|
|
|
|
交通网络中常常提出这样的问题:从甲地到乙地之间是否有公路连通?在有多条通路的情况下,哪一条路最短?导航系统便可以解决这样的问题。与此同时,城市的扩建,新地点的添加,新道路的修建,需要导航系统具备添加新地点,添加新路线的功能。而受一些生态工程的实施,例如退耕还林还草,和自然条件的影响,本来存在的一些地点或道路需要删除或更改,此时导航图还应该及时的更新,以适应新的查找两点间最短路径的需要。
|
|
|
|
|
除此之外,用户的查找应是极为方便的,对于最短路线, 新添加的地点和路径以及删除的地点和路径的感知应是直观的,这样才能真正的给使用导航系统的人们提供方便。
|
|
|
|
|
|
|
|
|
|
## 1.2 可行性分析
|
|
|
|
|
|
|
|
|
|
明确解决问题的关键,核心数据结构,核心算法等。
|
|
|
|
|
|
|
|
|
|
确定解决问题的总体思路和方案。
|
|
|
|
|
|
|
|
|
|
## 1.3 需求分析
|
|
|
|
|
|
|
|
|
|
### (1)输入和输出
|
|
|
|
|
|
|
|
|
|
输入城市编号,即可显示该城市的具体信息,最短路径等。
|
|
|
|
|
/***********************
|
|
|
|
|
功能:查找某一个城市的信息
|
|
|
|
|
输入:城市的编号
|
|
|
|
|
输出:城市的编号,名称以及简介
|
|
|
|
|
***********************/
|
|
|
|
|
|
|
|
|
|
### (2)数据字典
|
|
|
|
|
|
|
|
|
|
描述系统中需要处理的所有数据包含的具体信息。例如:
|
|
|
|
|
|
|
|
|
|
学生 = 学号 + 姓名 + 成绩
|
|
|
|
|
|
|
|
|
|
### (3)数据文件
|
|
|
|
|
|
|
|
|
|
系统中需要读取xx数据文件以获取xx数据,或者需要导出xx数据。举例说明xx数据文件的具体格式。
|
|
|
|
|
|
|
|
|
|
### (4)参数设定
|
|
|
|
|
|
|
|
|
|
系统开始运行时,需要设置的参数。可以用户手册的形式给出设定参数的过程,如系统提示信息和用户输入等。
|
|
|
|
|
|
|
|
|
|
### (5)地图信息修改功能
|
|
|
|
|
|
|
|
|
|
输入修改编号,即可对指定城市进行修改
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 系统设计
|
|
|
|
|
|
|
|
|
|
## 2.1 概要设计
|
|
|
|
|
|
|
|
|
|
系统划分为几个模块,可以画模块图。
|
|
|
|
|
|
|
|
|
|
逐个说明每个模块的功能(输入、输出、做什么,这里不写怎么做)。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 2.2 数据结构设计
|
|
|
|
|
|
|
|
|
|
首先,分析对比几种可选的数据结构设计方案。如图可以采用邻接矩阵,也可以采用邻接表,表示集合可以用普通的查找表,还可以用不相交集。给出每一种设计方案的特点(优势、不足等)。然后,综合考虑各种因素(空间、时间、乃至团队成员的水平等),给出你的选择。
|
|
|
|
|
|
|
|
|
|
### (1)xxx结构
|
|
|
|
|
|
|
|
|
|
给出核心数据结构的设计,包括文字描述和示意图。讲清楚数据是如何组织的。多个数据结构,逐一列出。
|
|
|
|
|
|
|
|
|
|
### (2)xxx结构
|
|
|
|
|
|
|
|
|
|
给出核心数据结构的设计,包括文字描述和示意图。讲清楚数据是如何组织的。
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
## 2.3 算法设计
|
|
|
|
|
|
|
|
|
|
首先,分析对比几种可选的算法设计方案。如是否排序,广度优先或深度优先搜索等。给出每一种设计方案的特点(优势、不足)。然后,综合考虑各种因素(空间、时间、乃至团队成员的水平等),给出你的选择。
|
|
|
|
|
|
|
|
|
|
### (1)XXX算法
|
|
|
|
|
|
|
|
|
|
给出核心算法的设计,包括伪代码或流程图。多个核心算法,逐一列出。只列举解决问题的核心算法,重点讲清楚是如何解决问题的。
|
|
|
|
|
|
|
|
|
|
### (2)XXX算法
|
|
|
|
|
|
|
|
|
|
给出核心算法的设计,包括伪代码或流程图。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 系统实现
|
|
|
|
|
|
|
|
|
|
采用C++、利用VSCode实现。
|
|
|
|
|
|
|
|
|
|
本程序首先是用户编辑界面,用户根据自己的需求编写地图,从而加入顶点的数组之中,创建的地图用邻接矩阵存储,在从主函数之中进行调用,实现对两个算法的调用。用户在输入顶点以及边的信息都会存储,在存储成功之后会提示用户存储成功,之后进入到菜单界面,菜单界面提供两种选择口合,分别可以调运Dijkstra和Floyd算法调用之后输入相应的口令以及要查询的城市编号, 算法会根据邻接矩阵存储的地图进行计算,求出最短路径。在以后使用完系统后,可输入口合 0,系统会结束一切运算,退出程序。
|
|
|
|
|
|
|
|
|
|
## 3.1 核心数据结构的实现
|
|
|
|
|
|
|
|
|
|
利用循环结构实现查找某一个城市的信息
|
|
|
|
|
如下:
|
|
|
|
|
int search(MatGrath &G)
|
|
|
|
|
{ int a;
|
|
|
|
|
int flag=1;
|
|
|
|
|
printf("请输入您要查询的城市编号\n");
|
|
|
|
|
scanf("%d",&a);
|
|
|
|
|
while(flag)
|
|
|
|
|
{
|
|
|
|
|
if(a<=0||a>G.vexnum)
|
|
|
|
|
{
|
|
|
|
|
printf("编号不存在,请重新输入\n");
|
|
|
|
|
scanf("%d",&a);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ flag=0;
|
|
|
|
|
|
|
|
|
|
printf("编号 景点名称 简介 \n");
|
|
|
|
|
printf(" %-4d %-16s%-58s\n",G.vexs[a].no,G.vexs[a].sight,G.vexs[a].introduction);
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
利用深度遍历实现输出城市信息
|
|
|
|
|
如下:
|
|
|
|
|
|
|
|
|
|
bool visited[MAXV];
|
|
|
|
|
int DFS(MatGrath &G,int m)//深度优先搜索
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
printf("%d %s %s\n",G.vexs[m].no,G.vexs[m].sight,G.vexs[m].introduction);
|
|
|
|
|
visited[m]=true;
|
|
|
|
|
for(i=1;i<=G.vexnum;i++)
|
|
|
|
|
{
|
|
|
|
|
if(G.arc[m][i].length!=INF&&visited[i]==false)
|
|
|
|
|
{
|
|
|
|
|
DFS(G,i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 3.2 核心算法的实现
|
|
|
|
|
|
|
|
|
|
核心算法Dijkstra
|
|
|
|
|
算法floyd
|
|
|
|
|
|
|
|
|
|
如以下代码,采用迪杰斯特拉算法实现求取路径最短值
|
|
|
|
|
int Ppath2(MatGrath &G,int path[],int i,int v) //前向递归查找路径上的顶点
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
k=path[i];
|
|
|
|
|
if (k==v)
|
|
|
|
|
return k; //找到了起点则返回
|
|
|
|
|
Ppath2(G,path,k,v); //找顶点k的前一个顶点
|
|
|
|
|
printf("%s->",G.vexs[k].sight);//输出顶点k
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int danyuan(MatGrath &G,int v)//求两点之间的最短路径
|
|
|
|
|
{
|
|
|
|
|
int dist[MAXV],path[MAXV];
|
|
|
|
|
int s[MAXV];
|
|
|
|
|
int mindis,i,j,u;
|
|
|
|
|
for (i=1; i<=G.vexnum; i++)
|
|
|
|
|
{
|
|
|
|
|
dist[i]=G.arc[v][i].length; //距离初始化
|
|
|
|
|
s[i]=0; //s[]置空
|
|
|
|
|
if (G.arc[v][i].length<INF) //路径初始化
|
|
|
|
|
path[i]=v;
|
|
|
|
|
else
|
|
|
|
|
path[i]=-1;
|
|
|
|
|
}
|
|
|
|
|
s[v]=1;
|
|
|
|
|
path[v]=0; //源点编号v放入s中
|
|
|
|
|
for (i=1; i<=G.vexnum; i++) //循环直到所有顶点的最短路径都求出
|
|
|
|
|
{
|
|
|
|
|
mindis=INF; //mindis置最小长度初值
|
|
|
|
|
for (j=1; j<=G.vexnum; j++) //选取不在s中且具有最小距离的顶点u
|
|
|
|
|
if (s[j]==0 && dist[j]<mindis)
|
|
|
|
|
{
|
|
|
|
|
u=j;
|
|
|
|
|
mindis=dist[j];
|
|
|
|
|
}
|
|
|
|
|
s[u]=1; //顶点u加入s中
|
|
|
|
|
for (j=1; j<=G.vexnum; j++) //修改不在s中的顶点的距离
|
|
|
|
|
if (s[j]==0)
|
|
|
|
|
if (G.arc[u][j].length<INF && dist[u]+G.arc[u][j].length<dist[j])
|
|
|
|
|
{
|
|
|
|
|
dist[j]=dist[u]+G.arc[u][j].length;
|
|
|
|
|
path[j]=u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i=1; i<=G.vexnum; i++)
|
|
|
|
|
if (s[i]==1&&v!=i)
|
|
|
|
|
{
|
|
|
|
|
printf(" 从%s到%s的最短路径长度为:%d米\t路径为:",G.vexs[v].sight,G.vexs[i].sight,dist[i]);
|
|
|
|
|
printf("%s->",G.vexs[v].sight); //输出路径上的起点
|
|
|
|
|
Ppath2(G,path,i,v); //输出路径上的中间点
|
|
|
|
|
printf("%s\n",G.vexs[i].sight); //输出路径上的终点
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Ppath1(MatGrath &G,int path[][MAXV],int v,int w) //前向递归查找路径上的顶点
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
k=path[v][w];
|
|
|
|
|
if (k==-1) return 0; //找到了起点则返回
|
|
|
|
|
Ppath1(G,path,v,k); //找顶点i的前一个顶点k
|
|
|
|
|
printf("%s->",G.vexs[k].sight);
|
|
|
|
|
Ppath1(G,path,k,w); //找顶点k的前一个顶点j
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
如下采用floyd算法求给出的两点之间的最少费用
|
|
|
|
|
void ShortestMoney(MatGrath &G,int v,int w)//求花费最少的路径
|
|
|
|
|
{
|
|
|
|
|
int A[MAXV][MAXV],path[MAXV][MAXV];
|
|
|
|
|
int i,j,k;
|
|
|
|
|
for (i=0; i<G.vexnum; i++)
|
|
|
|
|
for (j=0; j<G.vexnum; j++)
|
|
|
|
|
{
|
|
|
|
|
A[i][j]=G.arc[i][j].money;
|
|
|
|
|
path[i][j]=-1; //i到j没有边
|
|
|
|
|
}
|
|
|
|
|
for (k=0; k<G.vexnum; k++)
|
|
|
|
|
{
|
|
|
|
|
for (i=0; i<G.vexnum; i++)
|
|
|
|
|
for (j=0; j<G.vexnum; j++)
|
|
|
|
|
if (A[i][j]>A[i][k]+A[k][j])
|
|
|
|
|
{
|
|
|
|
|
A[i][j]=A[i][k]+A[k][j];
|
|
|
|
|
path[i][j]=k;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (A[v][w]==INF)
|
|
|
|
|
{
|
|
|
|
|
if (v!=w)
|
|
|
|
|
printf("从%d到%d没有路径\n",v,w);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf(" 从%s到%s路径费用:%d元人民币 路径:",G.vexs[v].sight,G.vexs[w].sight,A[v][w]);
|
|
|
|
|
printf("%s->",G.vexs[v].sight); //输出路径上的起点
|
|
|
|
|
Ppath1(G,path,v,w); //输出路径上的中间点
|
|
|
|
|
printf("%s\n",G.vexs[w].sight); //输出路径上的终点
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 4. 系统测试
|
|
|
|
|
|
|
|
|
|
描述测试的思路和方法。比如,先用小数据量进行测试,再用真实数据进行测试。
|
|
|
|
|
|
|
|
|
|
测试应考虑到输入数据的特殊情况。
|
|
|
|
|
|
|
|
|
|
给出若干测试用例,包括输入、预期结果、运行结果或是否通过测试。运行结果和预期结果一致,为通过测试。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 5. 总结
|
|
|
|
|
|
|
|
|
|
概况项目和完成情况。
|
|
|
|
|
|
|
|
|
|
遇到的问题和解决方法。
|
|
|
|
|
|
|
|
|
|
个人小结:
|
|
|
|
|
|
|
|
|
|
杨腾泽:
|
|
|
|
|
|
|
|
|
|
刘鑫成:本次的系统研发研活动,让我体验到了程序开发的复杂性与程序开发成功的自豪感,一个项目的完成离不开一个团队的团结协作,在进行项目时,需要对其进行反复的纠错和改进,在更改和发现中不断地改进和提升自,从而丰富自己。这次团队体验,让我能够初步地体会到一个团队间的分工协作的重要性,成员分工以及项目领导者的重要性,让我受益匪浅
|
|
|
|
|
|
|
|
|
|
李培毅:
|
|
|
|
|
|
|
|
|
|
孙英皓:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 参考文献
|
|
|
|
|
|
|
|
|
|
列出参考的文献资料,根据情况自行添加。
|
|
|
|
|
|
|
|
|
|
[1] 严蔚敏, 吴伟民. 数据结构(C语言版). 北京: 清华大学出版社, 2007.
|
|
|
|
|
|