北京地铁线路规划

一.项目介绍
GitHub链接:https://github.com/zhangyahui-0902/Subway
核心算法:Dijkstra算法
编写语言:java
需求分析:
1.-map subway.txt 读取地铁线路信息
2.-a 1号线 通过路线名获取所有站点信息
-o station .txt 将信息写在该文本文件中
3.-b 苹果园 八宝山 通过两站点获得最短路径
-o routine.txt 将经过的站点写在该文本文件中
所做的工作:
1.读取subway.txt的信息,将各个站点的名称、所属线路、相邻站点都存储起来进各线路,将各线路也存储起来
2.根据输入的线路名输出一整条线路
3.查找出发站点和结束站点是否存在,出发站点和结束站点是否相同等异常情况的处理

不能独立完成的原因:输入出发站点和结束站点,本想根据学过的迪杰斯特拉算法进行修改完成,但是原先学的是以矩阵形式存储,想了很久还是无法将矩阵形式转换为list形式完成最短路径算法,归根究底还是对于算法和list的认识不够
二.文件导入方式设计
subway.txt格式

1号线 苹果园 古城 八角游乐园 八宝山 玉泉路 五棵松 万寿路 公主坟 军事博物馆 木樨路 南礼士路 复兴门 西单 天安门西 天安门东 王府井 东单 建国门 永安里 国贸 大望路 四惠 四惠东
...

java读取方式
1.通过路径创建文件,如果这个文件不存在说明输入格式不对,输出文件不正确。
2.如果存在,通过文件将字节流转为字符流,再从字符输入流中读取文本并缓冲字符。
通过两重for循环,第一重for循环以线路数为基准,每次读一行即一条完整的线路,将线路存储在字符串数组中,字符串数组中的第一个就是线路名,设立一个专门存储站点信息的列表。第二重for循环通过遍历字符串数组,将站点的名称存储进站点,站点在存储进列表,并列的第二重for循环通过线路的大小将每个站点的相邻站点都存储进站点,站点存储进列表,最后将线路存储进一个hashMap中

File file=new File(path);
	   if(file.exists()) {
	   FileInputStream fl = new FileInputStream(file);
	   InputStreamReader br=new InputStreamReader(fl,"UTF-8");
	   BufferedReader reader=new BufferedReader(br);
	   String content="";
	   for(int i=0;i<22;i++) {
		   content=reader.readLine();
		   String[] lineArr=content.split(" ");
		   List<Station> line=new ArrayList<Station>();
		   String linename=lineArr[0];
		   for(int j=1;j<lineArr.length;j++) {
					   line.add(new Station(lineArr[j],linename));
		   }
	    		  for(int j=0;j<line.size();j++) {
	    			  List<Station> linkedStations=line.get(j).getLinkStations();
	    	             if (j == 0) {
	    	                        linkedStations.add(line.get(j + 1));
	    	                        line.get(j).setLinkStations(linkedStations);
	    	              } else if (j == (line.size()-1) ) {
	    	            	  linkedStations.add(line.get(j - 1)); 
	    	            	  line.get(j).setLinkStations(linkedStations);
	    	               }else {
	    	                        linkedStations.add(line.get(j+1));
	    	                        linkedStations.add(line.get(j-1));
	    	                        line.get(j).setLinkStations(linkedStations);
	    	               }
	   }
	    		  lineSet.add(line);
	   }
	   reader.close();
}
	   else
		   System.out.println("文件不正确");
}

三.存储结构设计
站点结构

public class Station {
    private String name;
    private String line;
    private List<Station> linkStations=new ArrayList<>();
}

线路结构

public class Routine {
      private Station begin;
      private Station end;
      private int distance=0;
      private List<Station> passStations=new ArrayList<>();
}

四.最短路径
1.analysisList用来存储站点
resultMap用来存储站点和线路
getLinkStations方法获得任意一个站点的相邻站点列表
getNextStation()方法找到距离最小的站点
2.首先判断开始站点是否存储在analysisList列表中,如果不存在则添加。判断resultMap是否为空,如果为空,通过开始站点得到相邻站点的列表,遍历列表的中的站点,设定线路中的开始站点、结束站点、距离、相邻站点,将这个站点和线路存储在resultMap中。找到距离最小的站点parent,通过parent找到相邻站点的列表,遍历列表中的站点,新建一个通过parent经过的站点列表的列表,通过站点找到线路,设置该线路上距离、经过的站点,将站点和该站点的线路存入resultMap中。遍历结束将parent存在analysisList中,递归执行该程序,最后返回由结束站得到的线路

if (!analysisList.contains(star)) {
              analysisList.add(star);
          }
          if (resultMap.isEmpty()) {
              List<Station> linkStations = getLinkStations(star);
              for (Station station : linkStations) {
            	  Routine routine = new Routine();
            	  routine.setBegin(star);
            	  routine.setEnd(station);
                  int distance = 1;
                  routine.setDistance(distance);
                  routine.getPassStations().add(station);
                  resultMap.put(station, routine);
              }
          }
          Station parent = getNextStation();
          if (parent == null) {
        	  Routine routine = new Routine();
        	  routine.setDistance(0);
        	  routine.setBegin(star);
        	  routine.setEnd(end);
              return resultMap.put(end, routine);
          }
          if (parent.equals(end)) {
              return resultMap.get(parent);
          }
          List<Station> childLinkStations = getLinkStations(parent);
          for (Station child : childLinkStations) {
              if (analysisList.contains(child)) {
                  continue;
              }
             int distance = 1+resultMap.get(parent).getDistance();
              if (parent.getName().equals(child.getName())) {
                  distance = 0;
				  }
              List<Station> parentPassStations = resultMap.get(parent).getPassStations();
              Routine childResult = resultMap.get(child);
              if (childResult != null) {
                  if (childResult.getDistance() > distance) {
                      childResult.setDistance(distance);
                      childResult.getPassStations().clear();
                      childResult.getPassStations().addAll(parentPassStations);
                      childResult.getPassStations().add(child);
                  }
              } else {
                  childResult = new Routine();
                  childResult.setDistance(distance);
                  childResult.setBegin(star);
                  childResult.setEnd(child);
                  childResult.getPassStations().addAll(parentPassStations);
                  childResult.getPassStations().add(child);
              }
              resultMap.put(child, childResult);
          }
          analysisList.add(parent);
          shortest(star, end);
          return resultMap.get(end);

五.输入输出设计
输入设计
1.读取文件信息

-map subway.txt

2.根据线路名获取整条线路

-a 1号线 -map subway.txt -o station.txt

3.根据出发站和结束站获得最短路径

-b 苹果园 八宝山 -map subway.txt -o routine.txt

具体实现代码

 if(args.length==2&&args[0].equals("-map"))
    		 Subway.Data(args[1]);
    	 else if(args.length==6&&args[0].equals("-a")&&args[2].equals("-map")&&args[4].equals("-o")) {
    	  Subway.Data(args[3]);
  		   writeRoute(args[1],args[5]);//写入station.txt
  	   }
  	   else if(args.length==7&&args[0].equals("-b")&&args[3].equals("-map")&&args[5].equals("-o")){
  		 Subway.Data(args[4]);
  		   Result(args[1],args[2],args[6]);
  		   //写入routine.txt
  	   }
  	   else {
  		    System.out.println("命令不正确");
  	   }

输出设计
根据路线名获得整条线路
1.通过路径新建一个文件,用来存储站点信息
2.通过遍历所有站点,获得一条所有站点的线路名都是输入的那个的线路
3.通过遍历该线路,将该线路上的站点信息都写进文本

 List<Station> route=null;
   	  int flag=1;
   	  File file=new File(path);
	   FileWriter fw =new FileWriter(file);;
   	   for(List<Station> l:Subway.lineSet){
   		    flag=1;
   		   for(Station s:l) {
   		    if(!s.getLine().equals(linename))
   		    	flag=0;
   		   }
   		   if(flag==1) {
   			   route=l;
   	   }
   	   }
   		   if(route==null) {
   			   fw.write("路线名不正确");
   			   fw.close();
   		   }
   		   else {
   		   if(file.exists()&&file.isFile()) {
   		   try {
   			   fw.write(linename);
   			   fw.write("\r\n");
   			   for(Station s:route) {
   				   fw.write(s.getName());//将字符串写入到指定的路径下的文件中
   				   fw.write("\r\n");
   			   }
   		       fw.close();
   		       } catch (IOException e) {
   		    	   e.printStackTrace(); 
   		    	   }
   	   }
   		   else
   			   fw.write("文件不正确");
   		       fw.close();
   		   }

测试样例
1.正常情况
运行参数

-a 1号线 -map subway.txt -o station.txt

运行结果

1号线
苹果园
古城
八角游乐园
八宝山
玉泉路
五棵松
万寿路
公主坟
军事博物馆
木樨路
南礼士路
复兴门
西单
天安门西
天安门东
王府井
东单
建国门
永安里
国贸
大望路
四惠
四惠东

2.异常情况
运行参数(线路不存在)

-a 2号线 -map subway.txt -o station.txt

运行结果

路线名不存在

运行参数(命令参数不对)

-a 1号线 -map subway.txt -m station.txt

运行结果

命令不正确

运行参数(命令不正确)

-c 1号线 -map subway.txt -o station.txt

运行结果

命令不正确

根据两个站点获得最短路径经过的站点
1.通过站点名查找站点是否存在,是否相同
2.如果存在且不同,进行最短路径方法,获得最短线路
3.如果不存在或者相同,输出相应信息

File file=new File(path);
     	Station b;
     	Station o;
 		   FileWriter fw;
 		   try {
 			   fw=new FileWriter(file);
 			   Routine routine;
 			   b=Dijkstra.findStation(begin,Subway.lineSet);
 			   o=Dijkstra.find(end,Subway.lineSet);
 			   if(o!=null&&b!=null&&!o.getName().equals(b.getName())) {
 				  routine=Dijkstra.shortest(b,o);
 			   if(routine!=null) {
 				   if(b.getLinkStations().contains(o)) {
 					   fw.write("->乘坐"+b.getLine());
 					   fw.write("\r\n");
 					   fw.write(b.getName());
 					   fw.write("\r\n");
 					   fw.write(o.getName());
 					   fw.close();  
 				   }
 				   else {
 			   fw.write("->乘坐"+routine.getPassStations().get(1).getLine());
 			   fw.write("\r\n");
 			   fw.write(b.getName());
 			   fw.write("\r\n");
 			   for(int i=0;i<routine.getPassStations().size()-1;i++) {
 				   fw.write(routine.getPassStations().get(i).getName());
 				   fw.write("\r\n");
 				   if(!routine.getPassStations().get(i+1).getLine().equals(routine.getPassStations().get(i).getLine())) {
 					   fw.write("->换乘"+routine.getPassStations().get(i+1).getLine());
 					   fw.write("\r\n");
 				   }
 			   }
 			   fw.write(o.getName());
 			   fw.write("\r\n");
 			   fw.write("共经过站点数"+routine.getPassStations().size());
 		       fw.close();
 			   }
 			   }else {
 				   fw.write("该线路不存在");
 				  fw.close();
 			   }
 			   }
 			   else if(b==null) {
 				   fw.write("起点不存在");
 				   fw.close();
 			   }
 			   else if(o==null) {
 				   fw.write("终点不存在");
 				   fw.close();
 			   }
 			   else if(begin.equals(end)) {
 				   fw.write("起点和终点相同");
 				   fw.close();
 			   }
 		   }
 		      catch (IOException e) {
 		    	   e.printStackTrace(); 
 		    	   }
 			   }

测试样例
正常情况
1.不存在换乘
1.1两个站点相邻
运行参数

-b 苹果园 古城 -map subway.txt -o routine.txt

运行结果

->乘坐1号线
苹果园
古城

1.2两个站点不相邻
运行参数(都是单站点)

-b 苹果园 万寿路 -map subway.txt -o routine.txt

运行结果

->乘坐1号线
苹果园
古城
八角游乐园
八宝山
玉泉路
五棵松
万寿路
共经过站点数6

运行参数(都是换乘站点)

-b 平安里 西单 -map subway.txt -o routine.txt

运行结果

->乘坐4号线大兴线
平安里
西四
灵境胡同
西单
共经过站点数3

运行参数(一个单站点,一个换乘站点)

-b 平安里 动物园 -map subway.txt -o routine.txt

运行结果

->乘坐4号线大兴线
平安里
新街口
西直门
动物园
共经过站点数3

2.存在换乘
运行参数(都是单站点)

-b 西四 湾子 -map subway.txt -o routine.txt

运行结果

->乘坐4号线大兴线
西四
灵境胡同
西单
宣武门
菜市口
->换乘7号线
广安门内
达官营
湾子
共经过站点数7

异常情况
运行参数

-b 哈哈哈 湾子 -map subway.txt -o routine.txt

运行结果

起点不存在

运行参数

-b 湾子 哈哈哈 -map subway.txt -o routine.txt

运行结果

终点不存在

运行参数

-b 湾子 湾子 -map subway.txt -o routine.txt

运行结果

起点和终点相同
posted @ 2019-10-13 18:09  31701066张雅慧  阅读(301)  评论(0编辑  收藏  举报