北京市地铁图
GIthu地址:https://github.com/wuzufeng/beijingsubway
一.设计分析
在北京地铁换乘系统中,我将整个系统主要分成了3个主要模块,分别为:主控模块,IO模块,算法模块。而我认为在这3个模块中最复杂,也是最棘手的模块就是IO模块,因为在本次实验前我对Java的IO操作没有什么了解,所以我首先查询了关于Java的IO方面的资料和代码,对其有了一定的了解后,在按需求设计完成主模块后,我先设计了系统的读入文件模块。
主模块
package main; import manager.*; public class Main { //主函数 public static void main(String[] args) throws Exception { //-map 地图读入 if(args[0].equals("-map")){ readMap(args[1]); System.out.println("地图读取成功!"); } // -a 地铁线站点输出 else if (args[0].equals("-a")){ readMap(args[3]); manager.LineManager.check(args[1]); //读取 FileWrite.outstation(args[1],args[5]); System.out.println("车站信息输出成功!"); } // -b 最短路径查询 else if(args[0].equals("-b")){ readMap(args[4]); ShortestPath.makeTb(); //读取输出文件,起点和终点 FileWrite.outroutine(args[6],args[1],args[2]); System.out.println("路线信息输出成功!"); } else{ System.out.println("请输入指定命令进行相应操作!"); } } //地图文件读取 public static void readMap(String x) throws Exception { String readfile =x; manager.Map.in(readfile); manager.LineManager.statisticsStation(); manager.Map.getHashMap(); Map.setMap(); manager.LineManager.readline(readfile); } }
我先设计了station和line两个类,用于储存地铁站,地铁线路和其他相关信息
station
package model; import java.util.*; public class Station { private String stationName; //站点名称 private Set<Line>lineName; //所属地铁线 private Set<Station>linkStations; //相连的地铁站 //获得站点名称 public String getStationName() { return stationName; } //获得站点相连的站点 public Set<Station> getlinkStations() { return linkStations; } //为站点添加所在地铁线 public void addLineName(Line lineName) { this.lineName.add(lineName); } //为当前站点添加相邻站点 public void addlinkStations(Station linkStations) { this.linkStations.add(linkStations); } //添加一个站点包括它的名称,附近相连站点,所在线路站点 public Station(String stationName) { this.stationName=stationName; linkStations= new HashSet<>(); lineName= new HashSet<>(); } }
line
package model; import java.util.*; public class Line { private List<Station>stations; //所经过站点 //返回地铁站当前的站点 public List<Station> getStations() { return stations; } //为地铁线路添加站点 public void addStation(Station station) { this.stations.add(station); } //添加地铁线和其经过的站点 public Line() { stations= new ArrayList<>(); } }
再将subway.txt的格式设计为
s1号线 金安桥 四道桥 桥户营 上岸 栗园庄 小园 石厂 1号线 苹果园 古城 八角游乐园 八宝山 玉泉路 五棵松 万寿路 公主坟 军事博物馆 木樨地 南礼士路 复兴门 西单 天安门西 天安门东 王府井 东单 建国门 永安里 国贸 大望路 四惠 四惠东 2号线 西直门 车公庄 阜成门 复兴门 长椿街 宣武门 和平门 前门 崇文门 北京站 建国门 朝阳门 东四十条 东直门 雍和宫 安定门 鼓楼大街 积水潭 西直门
方便程序读入。
在这之后便是要将储存的数据转化为HashMap并制作矩阵(为后面使用弗洛伊德算法做准备),这里我设计了manager.Map类。
接下来就是算法模块的,本次需求要求实现的功能主要有3点,一是实现地图的读取(已在IO模块实现),二是输出指定路线所经过的站点,三是根据输入的2个不同站点,输出最短线路(经过站最少)。
输出指点站点线路的工作比较简单,我设计了line模块解决
package manager; import model.Station; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class LineManager { public static java.util.Map<String, model.Line> lines; public static List<String> check(String linename){ model.Line line=lines.get(linename); List<Station>stations=line.getStations(); List<String>strings=new ArrayList<String>(); for(Station station:stations){ strings.add(station.getStationName()); } return strings; } public static Set<List<String>> readline(String filename) throws Exception { FileInputStream inputStream = new FileInputStream(filename); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); Set<List<String>>set=new HashSet<List<String>>(); String str = null; while ((str = bufferedReader.readLine()) != null) { String[] lineInformations = str.split(" "); List<String>stations=new ArrayList<String>(); for (String s : lineInformations) { stations.add(s); } set.add(stations); } //close inputStream.close(); bufferedReader.close(); return set; } public static void statisticsStation() { for (List<String> lineList : manager.Map.listSet) for (int i = 1; i < lineList.size(); i++) manager.Map.set.add(lineList.get(i)); } }
接下来是比较难的寻找最短路径模块
package manager; import model.Station; import java.util.ArrayList; import java.util.List; public class ShortestPath { public static int len; public static int[][] path; public static int[][] dist; public static int[][] table; public static int INF = Integer.MAX_VALUE; //设置INF无限大 public static List<Integer> result = new ArrayList<Integer>(); public static void findFloydRoad(int[][] table) { int size = len; path = new int[size][size]; dist = new int[size][size]; //initialize dist and path System.out.println(size); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { path[i][j] = -1; dist[i][j] = table[i][j]; } } for (int k = 0; k < size; k++) { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; path[i][j] = k; } } } } } public static void makeTb(){ len = manager.Map.map.size(); table =new int[len][len]; for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ table[i][j]=INF; } } for(int i=0;i<len;i++){ Station station=manager.Map.map.get(i); for(Station s:station.getlinkStations()){ int j=manager.Map.numMap.get(s.getStationName()); table[i][j]=1; table[j][i]=1; } } } public static void findCheapestPath(int begin, int end, int[][] table) { ShortestPath.findFloydRoad(table); result.add(begin); findPath(begin, end); result.add(end); } public static void findPath(int i, int j) { int k = path[i][j]; if (k == -1) //当k=-1时,递归结束,否则一直递归 return ; else { findPath(i, k); result.add(k); findPath(k, j); } } }
在完成这些工作后,便要设计输出模块,将相关结果输出到txt文件中 这里我设计了FileWrite类专门解决这个问题
package manager; import main.Main; import model.Station; import java.io.*; public class FileWrite { public static void outstation(String linename,String fileName) throws Exception { if(fileName.equals("")||fileName.equals(" ")){ System.out.println("输出文件名不能为空!"); } else if(linename.equals("")||linename.equals(" ")){ System.out.println("查询线路名不能为空"); } else { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))); out.write(linename+"所经过的站点有"); out.newLine(); //换行 for (Station s : manager.LineManager.lines.get(linename).getStations()) { out.write(s.getStationName()); out.newLine(); } out.flush(); out.close(); } } public static void outroutine(String fileName,String a,String b) throws Exception { if(fileName.equals("")||fileName.equals(" ")){ System.out.println("输出文件名不能为空!"); } else { int x =manager.Map.numMap.get(a); int y =manager.Map.numMap.get(b); ShortestPath.findCheapestPath(x, y, ShortestPath.table); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))); out.write(" 从 " + manager.Map.map.get(x).getStationName() + " 到 " + manager.Map.map.get(y).getStationName() + " 一共历经" + ShortestPath.dist[x][y] + "站" + " 的最佳路径是 "); out.newLine(); //换行 for (int r : ShortestPath.result) { if (!manager.Map.map.get(r).getStationName().equals(manager.Map.map.get(x).getStationName())) { out.write(" |"); out.newLine(); } out.write(manager.Map.map.get(r).getStationName()); out.newLine(); } out.flush(); out.close(); } } }
完成到这一步,基本完成了实验需求
二.程序测试
1 -map subway.txt
2 -a 1号线 -map subway.txt -o station.txt
3 -b 苹果园 北京站 -map subway.txt -o routine.txt
4. -c
三.心得总结
本次个人实验让我个人有许多收获,在本次实验前,我对Java的理解与掌握更多是在数据库方面,而这次实验让我对Java的IO ,交互和算法实现的方面有了更清晰的认识。更重要的是,我对软件工程和软件设计过程有了一个比较清晰的认识,并了解了软件工程的具体流程。虽然这次实验参考了大量的外部资料并仍存在许多不足,但是这次实验就行打开软件工程大门的敲门砖,让我收获匪浅。
原文地址:https://www.cnblogs.com/31701052wzf/p/11679371.html