北京地铁出行路径规划
GitHUB源码
项目需求
需求1:实现一个支持显示地铁线路与计算换乘的程序
对于地铁路线的数据,将使用subway.txt文件来存储。
对于地铁线路信息图,采用参数 -map 作为标志,例如:
java subway -map subway.txt
需求2:实现地铁线路查询功能
对于地铁线路信息图,采用-a 来指定地铁路线,采用参数 -o 来输出到指定文件station.txt,例如:
java subway -a 1号线 -map subway.txt -o station.txt
需求3:实现最短路径查询
以 -b 参数加两个地铁站点名称分别作为出发与目的,将结果写入 routine.txt,例如:
subway.exe -b 洪湖里 复兴路 -map subway.txt -o routine.txt
具体思路
采用BFS求最短路径,本以为最麻烦的是BFS,后来才发现,数据存储方式,以及换乘站才是最麻烦的部分。
数据存储方式
站点存储格式(Stations中包含所有站点):
public class Station {
public static HashMap<String, Station> Stations = new HashMap<>();
private String name;
private boolean visited =false;
private Station preStation = null;//just for BFS
private List<String> lineBelong = new ArrayList<String>();
private List<String> nearStations = new ArrayList<String>();
public List<String> getNearStations() {
return nearStations;
}
public void addNearStations(String nearStation) {
this.nearStations.add(nearStation);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
public Station getPreStation() {
return preStation;
}
public void setPreStation(Station preStation) {
this.preStation = preStation;
}
public List<String> getLineBelong() {
return lineBelong;
}
public void addLineBelong(String lineBelong) {
this.lineBelong.add(lineBelong);
}
}
地铁线存储方式(Lines包含所有地铁线号):
public class Line {
public static HashMap<String, Line> Lines = new HashMap<>();
private int id;
private String name;
private LinkedList<String> Stations = new LinkedList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LinkedList<String> getStations() {
return Stations;
}
public void addStations(String name) {
this.Stations.add(name);
}
}
其他数据:
public class Parameter {
public static String FILE_IN=null;
public static String FILE_OUT=null;
public static String START_STATION=null;
public static String END_STATION=null;
}
首先,使用getSubWayMsg()
方法来读取subway.txt中的数据。
public void getSubWayMsg(String filepath) throws Exception {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filepath)),"UTF-8"));
String getfileline = null;
int linecount = 1;
while ((getfileline = bufferedReader.readLine()) != null) {
String[] list = getfileline.split(" ");
Line line = new Line();
line.setId(linecount++);
line.setName(list[0]);
String perStation="";
String nextStation="";
for(int i = 1; i < list.length; i++) {
if(i == list.length-1) {
nextStation="";
}else {
nextStation=list[i+1];
}
if(Station.Stations.containsKey(list[i])) {
Station.Stations.get(list[i]).addNearStations(perStation);
Station.Stations.get(list[i]).addNearStations(nextStation);
Station.Stations.get(list[i]).addLineBelong(line.getName());
line.addStations(Station.Stations.get(list[i]).getName());
}else {
Station station = new Station();
station.setName(list[i]);
station.addLineBelong(line.getName());
station.addNearStations(perStation);
station.addNearStations(nextStation);
Station.Stations.put(station.getName(), station);
line.addStations(station.getName());
}
perStation=list[i];
}
Line.Lines.put(line.getName(), line);
}
bufferedReader.close();
} catch (Exception e) {
System.err.println("error: " + e);
}
return ;
}
指定输出某条地铁线:
public String getLines(String lineName) {
try {
Line line = Line.Lines.get(lineName);
String lineMsg=line.getName()+":";
for(String name : line.getStations()) {
lineMsg = lineMsg + "->" + name;
}
return lineMsg;
}catch(Exception e) {
}
return null;
}
BFS算法求最短路径:
public void BFS(String st,String ed) {
for (Station s : Station.Stations.values()) {
s.setVisited(false);
}
Queue<String> queue = new LinkedList<>();
queue.add(st);
while(!queue.isEmpty()) {
String w =queue.poll();
if(w == ed) {
break;
}
for(String sName : Station.Stations.get(w).getNearStations()) {
if(sName.equals("")) {
continue;
}
Station s = Station.Stations.get(sName);
while(!s.isVisited()) {
s.setPreStation(Station.Stations.get(w));
s.setVisited(true);
queue.add(s.getName());
}
}
}
}
根据bfs中的pre(保存在station中)列出最短路径:
public List<String> getBestWayMsg() {
Station s = Station.Stations.get(Parameter.END_STATION);
List<String> way = new ArrayList<String>();
while(!s.getName().equals(Parameter.START_STATION)) {
way.add(s.getName());
s = s.getPreStation();
}
Collections.reverse(way);
return way;
}
}
Mian函数功能实现:
public static void main(String[] args) throws Exception{
boolean isMap = false;
boolean isGetline = false;
boolean isPutmsg = false;
boolean isCheck = false;
String line ="";
for(int i = 0; i < args.length; i++){
if(args[i].equals("-map")) {
Parameter.FILE_IN = args[++i];
isMap =true;
}
else if(args[i].equals("-a")) {
line = args[++i];
isGetline =true;
}
else if(args[i].equals("-o")) {
Parameter.FILE_OUT = args[++i];
isPutmsg =true;
}
else if(args[i].equals("-b")) {
Parameter.START_STATION = args[++i];
Parameter.END_STATION = args[++i];
isCheck =true;
}
else {
System.err.print(args[i]);
System.err.print("erro:"+"请输入正确的命令。");
}
}
if(isMap) {
Getmsg getmsg = new Getmsg();
getmsg.getSubWayMsg(Parameter.FILE_IN);
System.out.println("读取"+Parameter.FILE_IN+"的信息成功");
// for (Line lie : Line.Lines.values()) {
// System.out.println(lie.getName()+":");
// for(String name : lie.getStations()) {
// System.out.print(" "+name);
// }
// System.out.println();
// }
}
if(isMap&&isGetline&&isPutmsg) {
Getmsg getmsg = new Getmsg();
String l = getmsg.getLines(line);
// System.out.print(l);
try {
FileWriter fileWriter = new FileWriter(Parameter.FILE_OUT);
fileWriter.write(l);
fileWriter.flush();
fileWriter.close();
} catch (Exception e) {
System.err.println("error: "+e);
}
}
if(isMap&&isCheck&&isPutmsg) {
if(Station.Stations.get(Parameter.START_STATION)==null||
Station.Stations.get(Parameter.END_STATION)==null) {
throw new Exception("Error:输入的地铁站有误");
}
Getmsg getmsg = new Getmsg();
getmsg.BFS(Parameter.START_STATION,Parameter.END_STATION);
List<String> bestWay = getmsg.getBestWayMsg();
try {
FileWriter fileWriter = new FileWriter(Parameter.FILE_OUT);
fileWriter.write("总共有(站):");
fileWriter.write(bestWay.size() + "\r\n");
String NowLine = Station.Stations.get(bestWay.get(0)).getLineBelong().get(0);
fileWriter.write(Parameter.START_STATION);
for(int i = 0; i < bestWay.size(); i++) {
if(Station.Stations.get(bestWay.get(i)).getLineBelong().contains(NowLine)) {
fileWriter.write("->" + bestWay.get(i));
}
else {
System.out.println(NowLine);
System.out.println(Station.Stations.get(bestWay.get(i)).getLineBelong());
fileWriter.write("->" + bestWay.get(i));
for(int j = i+1;j< bestWay.size(); j++) {
if(Station.Stations.get(bestWay.get(j)).getLineBelong().size()==1){
fileWriter.write("("+NowLine+"转");
NowLine = Station.Stations.get(bestWay.get(j)).getLineBelong().get(0);
fileWriter.write(NowLine+")");
break;
}
if(Station.Stations.get(bestWay.get(j)).equals(Parameter.END_STATION)) {
break;
}
}
}
}
fileWriter.flush();
fileWriter.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
因为在实际编程中,原计划的文件存储方案不易编写,故数据存储方案稍有改变。
测试效果:
-map subway.txt
(从控制台打印Lines,line,Stations,Station):
-a 1号线 -map subway.txt -o station.txt
:
-b 鼓楼大街 后沙峪 -map subway.txt -o routine.txt
: