个人项目-地铁路线规划系统设计及实现
问题重述
问题需要实现两个功能:
- 输入地铁线路名称,显示整条地铁线路站点
- 输入两个地铁站名称,并为其规划最短线路
由于地铁数据并未给出,所以收集北京市地铁线路数据,自行设计数据存储方式。
解决思路
- 收集数据并设计数据存储方式(之前已经给出)
- 读入数据并构建地铁图的数据结构
- 设计并确定寻找最短路径算法
- 使用测试案例对程序进行debug测试
具体实现
1.数据储存形式
由于json格式数据较为简单易读,所以本项目使用json格式储存数据,具体形式如下
{
"lines": [
{ "lineNo":1,"lineName":"1号线" , "stations":[
{"stationName":"苹果园"},
{"stationName":"古城"},
{"stationName":"八角游乐园"},
....
] },
{ "lineNo":2,"lineName":"2号线" , "stations":[
{"stationName":"积水潭"},
{"stationName":"鼓楼大街"},
...
{"stationName":"西直门"},
{"stationName":"积水潭"}
] },
.....
]
}
2.地铁数据结构确定
由于地铁各站点和线路之间为类似图的关系,每个节点之间有边存在,所以毫无疑问我们使用图这种数据结构对地铁线路图进行重建。具体实现如下
public class SubwayGraph {
public ArrayList<Station> V=new ArrayList<>();
public HashSet<Edge> edges=new HashSet<>();
public ArrayList<Station> getV() {
return V;
}
public int findStation(String stationName){
for(int i=0;i<V.size();i++){
if (V.get(i).getStationName().equals(stationName))return i;
}
return -1;
}
public void addV(String stationName,int lineNo,int mark) {//mark 0代表不可换乘,1代表可换乘
int index=-1;
if (mark==1){
index=findStation(stationName);
}
if (index==-1){
V.add(new Station(stationName));
}else {
}
}
public HashSet<Edge> getEdges() {
return edges;
}
public void addEdge(int u,int v) {
this.edges.add(new Edge(u,v));
}
public int isInV(Station station){
int i;
for ( i=0;i<V.size();i++){
if (V.get(i).getStationName().equals(station.getStationName()))return i;
}
V.add(station);
return i;
}
}
public class Vertex {
private int id; // 顶点的标识
private LinkedList<Vertex> neighbors; // 这个顶点的邻居顶点
private boolean isSerched; // 这个顶点是否被搜索过了
private Vertex predecessor; // 这个顶点的前驱,用来记录路径的
public Vertex(int id) {
this.id = id;
this.neighbors = new LinkedList<>();
this.predecessor=null;
}
public void addNeighbor(Vertex... vertexes) {
for (Vertex vertex : vertexes) {
this.neighbors.add(vertex);
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public LinkedList<Vertex> getNeighbors() {
return neighbors;
}
public void setNeighbors(LinkedList<Vertex> neighbors) {
this.neighbors = neighbors;
}
public boolean isSerched() {
return isSerched;
}
public void setSerched(boolean isSerched) {
this.isSerched = isSerched;
}
public Vertex getPredecessor() {
return predecessor;
}
public void setPredecessor(Vertex predecessor) {
this.predecessor = predecessor;
}
}
3.最短路径算法的设计
在本次作业中,我并没有使用dijkstra算法,而是使用了广度优先遍历(BFS)来寻找最短路径。这样虽然没有dijkstra算法那么完善,但是足以满足寻找两点之间的最短值。本次作业是将两站点之间的距离换乘都不再考虑范围之内,简化了题目的难度。bfs算法具体实现如下
/*这里具体编码出现一点小失误,dij应为dijkstra算法缩写却是bfs算法*/
public ArrayList<Station> DIJ(SubwayGraph graph, int starta, int enda) {
Vertex[] vertices = new Vertex[graph.V.size()];
ArrayList<Station> plan=new ArrayList<>();
for (int i = 0; i < vertices.length; i++) {
vertices[i] = new Vertex(i);
}
for (Edge i : graph.edges) {
vertices[i.getU()].addNeighbor(vertices[i.getV()]);
vertices[i.getV()].addNeighbor(vertices[i.getU()]);
}
Vertex start = vertices[starta];
Vertex end = vertices[enda];
boolean hasPath = bfs(start, end);
if (hasPath) {
// print path
Vertex predecessor = end;
do {
plan.add(graph.getV().get(predecessor.getId()));
predecessor = predecessor.getPredecessor();
} while (predecessor != null);
} else {
System.out.println("不存在该起点到该终点的路径");
}
return plan;
}
public static boolean bfs(Vertex start, Vertex end) {
LinkedList<Vertex> queue = new LinkedList<>();
queue.addLast(start); // 添加到队尾
while (!queue.isEmpty()) {
Vertex vertex = queue.pollFirst(); // 从队首取出一个元素
// 如果这个顶点是否已经检索过了,则跳过
if (vertex.isSerched()) {
continue;
}
if (vertex == end) {
// 如果到了终点了就可以返回了
return true;
} else {
// 如果还不是终点,这把该顶点可以到达的邻居全部添加到队列末端
for (Vertex neighbor : vertex.getNeighbors()) {
if (neighbor.getPredecessor() == null && neighbor != start) {
neighbor.setPredecessor(vertex);
}
queue.addLast(neighbor);
}
}
vertex.setSerched(true);
}
return false;
}
4.使用测试案例对程序进行debug测试
输出结果第一行统计一共经过几个站点
下面输出经过站点和换乘信息
测试案例1:(有换乘)
java -classpath fastjson-1.2.47.jar subway -b 木樨地 前门 -map subway.json -o routine.txt
结果
7
木樨地
南礼士路
复兴门
西单
4号线大兴线
宣武门
2号线
和平门
前门
测试案例2:(无换乘)
java -classpath fastjson-1.2.47.jar subway -b 木樨地 *西 -map subway.json -o routine.txt
结果
5
木樨地
南礼士路
复兴门
西单
*西
5.个人总结
在这个项目中使用了命令行输入输出,核心算法为BFS算法计算最短路径,该项目简单复习了java项目的基本流程。