一、项目介绍
GitHub链接:https://github.com/Magazinediver/Subway
核心算法:Dijkstra算法
编写语言:Java
需求分析:
1.subway.txt导入地铁线路信息,routine.txt输出地铁线路信息
2.对地铁行程规划(最短路径查询),并输出
3.输出地铁信息 1线路信息2站点信息
二、文件导入方式设计
2.1导入文本txt格式
24 //线路总数 1 //线路编号 23 //线路中站点数目 一号线 //线路名 一号线 苹果园 否 //格式: 线路名 站点名 是否换乘,若换乘则列出站点名 一号线 古城 否 一号线 八角游乐园 否 一号线 八宝山 否 一号线 玉泉路 否 一号线 五棵松 否 一号线 万寿路 否 一号线 公主坟 十号线 一号线 军事博物馆 九号线 一号线 木樨地 否 一号线 南礼士路 否 一号线 复兴门 二号线 一号线 西单 四号线 ......
2.2 java文件导入设计
1.导入时先按照文档中第一个数字,即线路总数x,建立for循环,获取有x条线路的line_list
2.再按照每条线路的第一行的数字,获取线路id
3.利用每条线路中的第二行,取得每条线路中的站点总数y,建立for循环,获取有y个站点的station_list,即每条线路中的站点列表
4.利用每条线路中的第三行,取得每条线路中的站点中文名称
5.后面即是地铁站点的输入格式:线路名 站点名 是否换乘,若换乘则列出站点名
其中先按空格分开一行,存入String s[] ,s[0]所属线路,s[1]站点名,s[2]是否有换乘,若S[2]不是“否“(非换乘站),就将S[2]按照“,”分离,存入String s1[],即trans_list
2.3java文件导入概念图
2.4java文件导入代码实现
while((str=bufferedReader.readLine())!=null) { if(str.equals(String.valueOf(j)))// { Line a = new Line(); int k = Integer.parseInt(bufferedReader.readLine());// a.setLname(bufferedReader.readLine()); for(int h=0;h) { Station b = new Station(); if((str1=bufferedReader.readLine())!=null) { String[] s = str1.split(" "); b.setLine(s[0]); b.setSname(s[1]); if(!s[2].equals("否")) { String[] s1 = s[2].split(","); b.setStationrans(s1); u=0; for(int p=0;p ) { if(kb[p].equals(b.getSname())) { u=1; } } if(u!=1) { kb[t] = b.getSname(); t++; } } } a.setStation(b); } list.add(a); j++; } return list; }
三、存储结构设计
3.1.无向图站点结构设计
1.station作为node
2.每个node之间有边连接,默认权值99,若是两站链接则权值设为1
3.可获得node再无向图中的序号
4.可对图中node计数
5.设计无向图的邻接矩阵结构
public static Listmainlist = new ArrayList (); //线路list protected int[][] subTrainMatrix; // 邻接矩阵 private static final int MAX_WEIGHT = 99; // 初始各node间距离99 private int[] dist; //node间距离存储数组 private List vertex = new ArrayList (); // node private List edges; //node间距离结构 //各个方法 public int[][] getSubTrainMatrix() //get邻接矩阵 public void setVertex(List vertices) //set node public List getVertex() //get node public List getEdges() //get边 public int getVertexSize() //图中node数 public int vertexCount() //node编号 public String toString() public subway(int size) public subway(List vertices)
3.2无向图边结构设计
class Edge { private T start, dest; //起始站,目标站 private int weight; //边权值 public Edge() public Edge(T start, T dest, int weight) public String toString() }
3.3站点结构
public class Station { public String sname; //站点名 String[] trans = new String[3]; //换乘线路存储数组 public String line; //所属线路名 public void setSname(String sname) //set站点名 public String[] getStationrans() //get站点换乘线路列表 public void setStationrans(String[] trans) //set站点换乘线路列表 public String getLine() //get所属线路名 public void setLine(String line) //set所属线路名 public String getSname() //get所属站点名 }
3.4线路结构
public class Line { public String lname; //线路名 public Liststation = new ArrayList ();//站点列表 public List getStation() //get站点列表 public void setStation(Station station) //set站点列表 public String getLname() //get线路名 public void setLname(String lname) //set站点名 }
四、线路及线路站点输出设计
4.1站点输出要求
1.能显示站点所属线路
2.能体现出换乘
3.能体现路线所经过的站点数
public static void printstation()//站点输出 { for(int i=0;i
4.2输入输出设计
4.2.1输入设计
输入格式
1.获取地铁线路信息
java subway -map subway.txt
2.输出地铁特定线路信息
java subway -a 1号线 -map subway.txt -o station.txt
3.输出地铁线路规划信息
java subway.subway -b 古城 T2航站楼 -map subway.txt -o routine.txt
4.输入读取代码
-map 参数来获得对应的自定义地铁文件
-a 指定了用户希望查询的地铁线路
-o 指定输出文件
-b 指定出发站与目标站
if(args.length==0) System.out.println(""); for(int i=0;i) { if(args[i].equals("-map")) { flag1=1; flag2=1; if(args.length) { System.out.println(""); return; } mainlist =Input.getFileContext(args[i+1]); }else if(args[i].equals("-a")) { flag1=1; operate="-a"; if(args.length) { System.out.println("格式不正确"); return; } route=args[i+1]; }else if(args[i].equals("-b")) { flag1=1; operate="-b"; if(args.length) { System.out.println("格式不正确"); return; } start=args[i+1]; stop=args[i+2]; }else if(args[i].equals("-o")) { flag1=1; output=args[i+1]; } } if(flag1==0) { System.out.println("格式不正确"); return; } else if(flag2==0) { System.out.println("格式不正确"); return; } if(operate==null&&output!=null) { System.out.println("没有输出"); return; } else if(operate!=null&&output!=null) { if(operate.equals("-a")) { try { if(outPutRoute(route, output)==false) { System.out.println("没有输出,没有此线路"); return; } } catch (FileNotFoundException e) { e.printStackTrace(); } }else if(operate.equals("-b")) { if(start.equals(stop)) { System.out.println("出发站与到达站不能相同!!!!!"); return; } if(Mainoutput(start, stop, output)==false) { System.out.println("没有输出,无法到达"); return; } } } }
4.2.2输出设计
输出中的站点会携带所属线路
两个站点间会用->连接
最后会输出经过的站点数
控制台中输出
文件输出设计
五、测试及遇到的问题与解决方法
5.1输入上的问题
1.出发站与到达站相同
if(start.equals(stop)) { System.out.println("出发站与到达站不能相同!!!!!"); return; } if(Mainoutput(start, stop, output)==false) { System.out.println("没有输出,无法到达"); return; } }
输出:出发站与到达站不可以相同!
2.出发站或到达站不存在或者线路不存在
if(outPutRoute(route, output)==false) { System.out.println("没有输出,没有此线路"); return; }
3.出发站与到达站之间不可到达
if(Mainoutput(start, stop, output)==false) { System.out.println("没有输出,无法到达"); return; }
4.没有所需的命令参数或输入格式错误
if(args.length==0) System.out.println("");
for(int i=0;i) {
if(args[i].equals("-map")) {
flag1=1;
flag2=1;
if(args.length) { System.out.println(""); return; } mainlist =Input.getFileContext(args[i+1]); }else if(args[i].equals("-a")) { flag1=1; operate="-a"; if(args.length) { System.out.println("格式不正确"); return; } route=args[i+1]; }else if(args[i].equals("-b")) { flag1=1; operate="-b"; if(args.length) { System.out.println("格式不正确"); return; } start=args[i+1]; stop=args[i+2]; }else if(args[i].equals("-o")) { flag1=1; output=args[i+1]; } } if(flag1==0) { System.out.println("格式不正确"); return; } else if(flag2==0) { System.out.println("格式不正确"); return; } if(operate==null&&output!=null) { System.out.println("没有输出"); return; } else if(operate!=null&&output!=null) { ...... }
在用if进行条件筛选,若是没有参数则会输出:格式不正确
5.2遇到的问题
1.在cmd中运行文件始终无法找到主类,显示无法加载
原因:java文件在cmd中运行必须在bin目录进行带包运行
2.在cmd中运行报错,在eclipse中确成功运行
报错1:数组越界
原因1:因为cmd中的编码类型为gbk(936),而我的代码是utf-8(65001),所以if无法识别,for循环无法停止,导致数组越绝
报错2:显示乱码
原因2: 编码类型不同,识别不了,乱码
3.以为在eclipse中无法带参数运行,造成了很多困扰
解决办法:eclipse中run configuration...
4.站点重复输出
原因:因为换乘站在多条线路中都存在,导致无向图中站点重复
解决方法:在输入时,对换乘站去重,进行筛选,若是换乘站,只在图中插入一次
for(int j=0;j) { flag=0; Station st = new Station(); st.setSname("0"); for(int l=0;l //非换乘站 { if(mainlist.get(i).getStation().get(j).getSname().equals(kb1[l])) { flag = 1; } } if(flag==0)//是换乘站 { st.setSname(mainlist.get(i).getStation().get(j).getSname()); st.setLine(mainlist.get(i).getStation().get(j).getLine()); st.setStationrans(mainlist.get(i).getStation().get(j).getStationrans()); c++; } else{ for(int p=0;p ) { if((mainlist.get(i).getStation().get(j).getSname().equals(kb1[p]))&&(!(kb[p].equals("0")))) { st.setSname(mainlist.get(i).getStation().get(j).getSname()); st.setLine(mainlist.get(i).getStation().get(j).getLine()); st.setStationrans(mainlist.get(i).getStation().get(j).getStationrans()); kb[p]="0"; v++; } } } if(!st.getSname().equals("0")) { vertices.add(st); } }
5.邻接矩阵乱码,无法取得站点在list中编号
原因:原先我写的demo中node时string类型,可使用indexof(),后来node替换成station类型,导致系统自带函数失效
解决办法:用自己写的代码替换
public int getPosInvertex(Station start) { for(int i=0;i) { //System.out.println(vertex.get(i).getSname()); if(vertex.get(i).getSname().equals(start.sname)) { return i; } } //return vertex.indexOf(start); return -1; }