|
|
|
@ -3,15 +3,9 @@
|
|
|
|
|
摘要:本项目针对城市地铁导航系统问题,可实现的功能有:
|
|
|
|
|
1、输出所有地点及其介绍
|
|
|
|
|
2、查询某一个地点及其介绍
|
|
|
|
|
3、增加一个地点
|
|
|
|
|
4、删除一个地点
|
|
|
|
|
5、更新一个地点
|
|
|
|
|
6、增加一条路
|
|
|
|
|
7、删除一条路
|
|
|
|
|
8、更新一条路
|
|
|
|
|
9、查询某一地点到其他所有地点的最短路径
|
|
|
|
|
10、查询某两个地点之间的最短路径
|
|
|
|
|
11、输出地图
|
|
|
|
|
3、查询某一地点到其他所有地点的最短路径
|
|
|
|
|
4、查询某两个地点之间的最短路径
|
|
|
|
|
|
|
|
|
|
*为有效地存储和处理数据,我们采用了图结构的数据结构。具体来说,我们使用邻接表存储每个站点及其相邻站点的信息,并使用哈希表存储站点名称和编号的映射关系。
|
|
|
|
|
*为了找出两点间最短路径,采用了Dijkstra算法,算法效率较高。
|
|
|
|
|
*项目的效果从整体来看运行流畅,可以为市民提供方便、快捷的地铁路线查询和导航服务。
|
|
|
|
@ -31,8 +25,8 @@
|
|
|
|
|
| 25 | 25 | 25 | 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. 系统分析
|
|
|
|
|
1.1 问题描述
|
|
|
|
|
#1. 系统分析
|
|
|
|
|
##1.1 问题描述
|
|
|
|
|
选择北京地铁,建立地铁站点导航地图,设计一个城市地铁导航系统。根据任意指定的两个站点,能够计算出任意两个站点之间路径长度最短的站点导航,并给出换乘方案。
|
|
|
|
|
|
|
|
|
|
1.2 可行性分析
|
|
|
|
@ -75,4 +69,141 @@
|
|
|
|
|
主要作用:在地图上展示各个站点和线路的位置和路线。
|
|
|
|
|
用户输入:无
|
|
|
|
|
系统输出:地铁线路和站点在地图上的显示,方便用户更直观地了解线路位置和路线。
|
|
|
|
|
2. 系统设计
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#2. 系统设计
|
|
|
|
|
##2.1 概要设计
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
系统划分为以下模块:
|
|
|
|
|
1.用户输入模块:用户通过输入起始站点和终点站点,触发系统查询和计算。
|
|
|
|
|
2.数据存储模块:系统将地铁线路和站点信息存储在一个数据结构中,并提供查询和修改功能。
|
|
|
|
|
3.路径计算模块:该模块通过获取用户输入的起始站点和终点站点,并利用存储在数据结 构中的地铁线路和站点信息,计算出最优路径。
|
|
|
|
|
4.输出模块:该模块将最优路径输出给用户,以便用户按照路径指引乘坐地铁。
|
|
|
|
|
2.2 数据结构设计
|
|
|
|
|
通过比较邻接矩阵、邻接表、查找表和不相交集等数据结构,我们选择使用邻接表作为数据结构。邻接表具有占用空间小、查询速度快等优势,适合储存大量的地铁线路和站点信息。
|
|
|
|
|
邻接表
|
|
|
|
|
邻接表是一种表示图形的数据结构,它用于描述地铁网络中的站点之间的连接关系。在邻接表中,每个站点对应一个链表,链表中的每个节点表示与该站点相邻的另一个站点。具体而言,我们可以用如下的结构体表示邻接表中的每个节点:
|
|
|
|
|
struct AdjListNode {
|
|
|
|
|
int destination; // 相邻站点编号
|
|
|
|
|
int weight; // 连接权重(例如两站之间的距离、换乘次数等)
|
|
|
|
|
struct AdjListNode* next; // 下一个相邻节点的指针
|
|
|
|
|
};
|
|
|
|
|
每个链表的头节点可以由一个数组来维护,例如:
|
|
|
|
|
|
|
|
|
|
struct Station {
|
|
|
|
|
char name[20]; // 站点名称
|
|
|
|
|
int id; // 站点编号
|
|
|
|
|
struct AdjListNode* head; // 相邻节点链表的头节点指针
|
|
|
|
|
};
|
|
|
|
|
struct Station stations[MAX_STATION_NUM]; // 站点数组
|
|
|
|
|
在这个结构中,我们为每个站点记录了它的名称、编号和相邻节点链表的头节点指针。这样的话,我们就可以通过遍历这些链表来获取某一站点的所有邻居站点。同时,由于链表中的每个节点包含了相邻站点的编号和连接权重,因此我们也可以在搜索路径时方便地计算出经过某一条路径的总长度或换乘次数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2.3 算法设计
|
|
|
|
|
我们选择Dijkstra算法作为路径计算模块的核心算法。Dijkstra算法是一种广泛应用于最短路径问题上的算法,具有速度快、结果正确性高、易于实现等优势。它通过不断更新起点到每个点的最短距离,并使用优先队列维护每个点的最短距离,直到计算出终点的最短路径。
|
|
|
|
|
Dijkstra算法
|
|
|
|
|
用户输入起点站和终点站,程序使用图论算法在地铁线路图中寻找到两个站之间的一条最短路径。此时使用Dijkstra算法找出最短路径。
|
|
|
|
|
#3. 系统实现
|
|
|
|
|
系统使用C++语言进行开发,使用VScode作为开发工具。
|
|
|
|
|
本系统的文件结构如下:
|
|
|
|
|
- SubwaySystem
|
|
|
|
|
- include
|
|
|
|
|
- SubwaySystem.h
|
|
|
|
|
- src
|
|
|
|
|
- SubwaySystem.cpp
|
|
|
|
|
- test
|
|
|
|
|
- test.cpp
|
|
|
|
|
- CMakeLists.txt
|
|
|
|
|
其中,SubwaySystem.h和SubwaySystem.cpp分别实现了地铁系统的数据结构和算法,test.cpp实现了测试用例。
|
|
|
|
|
以下是主要函数的功能:
|
|
|
|
|
|
|
|
|
|
SubwaySystem::addNode(Node node):向地铁系统中添加一个节点。
|
|
|
|
|
SubwaySystem::addEdge(Edge edge):向地铁系统中添加一条边。
|
|
|
|
|
SubwaySystem::shortestPath(Node from, Node to):计算从起点到终点的最短路径。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##3.1 核心数据结构的实现
|
|
|
|
|
数据结构的实现
|
|
|
|
|
|
|
|
|
|
本系统使用邻接表来表示地铁系统的图。具体实现如下:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Node {
|
|
|
|
|
int id; // 节点ID
|
|
|
|
|
string name; // 节点名称
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Edge {
|
|
|
|
|
int from; // 起点ID
|
|
|
|
|
int to; // 终点ID
|
|
|
|
|
int weight; // 权重(距离)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class SubwaySystem {
|
|
|
|
|
public:
|
|
|
|
|
/ 添加节点和边
|
|
|
|
|
void addNode(Node node);
|
|
|
|
|
void addEdge(Edge edge);
|
|
|
|
|
|
|
|
|
|
// 计算两个站点之间的最短路径
|
|
|
|
|
vector<Node> shortestPath(Node from, Node to);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 存储节点和边的数据结构
|
|
|
|
|
vector<Node> nodes_;
|
|
|
|
|
vector<vector<pair<int, int>>> adjacencyList_;
|
|
|
|
|
|
|
|
|
|
// 计算从起点到终点的最短路径
|
|
|
|
|
vector<int> dijkstra(int from, int to);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
其中SubwaySystem.h和SubwaySystem.cpp分别实现了地铁系统的数据结构和算法,test.cpp实现了测试用例。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##3.2 核心算法的实现
|
|
|
|
|
系统的核心算法主要包括最短路径算法和站点搜索算法。
|
|
|
|
|
|
|
|
|
|
最短路径算法采用Dijkstra算法实现,该算法的时间复杂度为O(n^2),其中n为站点数。具体实现方式如下:
|
|
|
|
|
|
|
|
|
|
1.初始化距离dist和最短路径标记visited数组。
|
|
|
|
|
2.将起点的距离dist设为0,将visited标记设为false。
|
|
|
|
|
3.对于每个未标记的站点,找出距离起点最近的站点v。
|
|
|
|
|
4.将v标记为已访问,对于v的每个邻居站点u,如果dist[u]>dist[v]+v到u的距离,更新dist[u]为dist[v]+v到u的距离。
|
|
|
|
|
5.重复以上步骤,直到所有站点都被标记为已访问或者没有可访问的站点。
|
|
|
|
|
|
|
|
|
|
站点搜索算法采用DFS算法实现,该算法的时间复杂度为O(n^2),其中n为站点数。具体实现方式如下:
|
|
|
|
|
|
|
|
|
|
1.初始化visited数组。
|
|
|
|
|
2.从起点出发,采用深度优先搜索方式,访问所有邻居站点。
|
|
|
|
|
3.将访问过的站点标记为visited。
|
|
|
|
|
4.重复以上步骤,直到找到终点或者没有可访问的站点。
|
|
|
|
|
|
|
|
|
|
通过以上算法的实现,我们可以实现在地铁图中查找两个站点之间最短路径和查找某个站点的所有邻居站点。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#4. 系统测试
|
|
|
|
|
|
|
|
|
|
(1)输入:1
|
|
|
|
|
结果:输出了所有的站点及简略介绍
|
|
|
|
|
(2)输入:2
|
|
|
|
|
结果:请问您要查询的地点编号是:10
|
|
|
|
|
编号:10
|
|
|
|
|
地点:雍和宫
|
|
|
|
|
介绍:位于北京市东城区北二环安定门东大街与雍和宫大街、和平里西街交汇处
|
|
|
|
|
按任意键返回!
|
|
|
|
|
(3)输入:3
|
|
|
|
|
结果:请输入查询的地点:3
|
|
|
|
|
到达地点 1的总距离为: 30 , 经过路径为:3
|
|
|
|
|
到达地点 2的总距离为: 60 , 经过路径为:3--->1--->2
|
|
|
|
|
到达地点 3的总距离为: 0 , 经过路径为:3
|
|
|
|
|
到达地点 4的总距离为: 100 , 经过路径为:3--->5--->4
|
|
|
|
|
到达地点 5的总距离为: 50 , 经过路径为:3--->5
|
|
|
|
|
…
|
|
|
|
|
(4)输入:4
|
|
|
|
|
结果:请输入查询的地点:3
|
|
|
|
|
请输入目的地点:5
|
|
|
|
|
总距离是: 50 , 经过路径为:3--->5
|
|
|
|
|
|
|
|
|
|
#5. 总结
|
|
|
|
|
我们设计的城市地铁导航系统旨在帮助用户方便快捷地查找和选择地铁线路及站点,并提供实时更新的地铁运行状态和乘车提示。我们在创建项目时遇到的问题有为降低空间复杂度,因而采用邻接表存储结构。Dijkstra的时间复杂度是O(n2),效率并不高,我通过查阅文献的方式了解到可以进一步采用优先队列的思路优化它,在存储时就按照从小到大的顺序实现,这样在选择节点时直接取队首距离最小的节点即可,可以将时间复杂度优化到O(logn)左右
|