个人git
一、项目需求
1.该程序能够准确地读出.txt文件中的数据,文件格式简洁易懂、可灵活扩展
2.在某号线路上,能够查询各个站点的信息,输出该号线路上所有站点信息
3.在出发站与目的站之间输出一个最短路径
二、文件存储
三、文件位置
一共三个package:control、main、model
control包里有Dijkstra.java,distance.java
Dijkstra.java(此代码为最短路径算法,这是最核心最难的地方,dijkstra算法能很好地解决最短路径问题,这段代码是借鉴了网上的代码,但是我还没能理解透彻):
package control; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import model.*; public class Dijkstra { private static HashMaph = new HashMap<>(); private static List l = new ArrayList<>(); public static lujing calculate(station star, station end) { if (!l.contains(star)) {//将开始站点加入到分析过的站点集合。 l.add(star); } if (star.equals(end)) {//如果开始站点等于终止站点,则设置result,设置距离和station。 lujing lujing = new lujing(); lujing.setDistance(0.0D); lujing.setEnd(star); lujing.setStart(star); return h.put(star, lujing); } if (h.isEmpty()) {//第一次调用calculate,且起始点和终止点不同,则h为空。 List ls = getLinkStations(star); //第一次调用获取起始点的相邻站点(在所有地铁线中,这里涉及转线交叉的周围站点) for (station station : ls) {//把相邻站点集合中的所有站点,加入h中。 因为相邻,则可以直接获取Distance。 lujing lujing = new lujing(); lujing.setStart(star); lujing.setEnd(station); String key = star.getSname() + ":" + station.getSname(); lujing.setDistance(1.0); lujing.getPassStations().add(station); h.put(station, lujing); } } station parent = getNextStation(); if (parent == null) { //如果h所有点keySet被分析完了,则返回的parent为null。 lujing lujing = new lujing(); lujing.setDistance(0.0D); lujing.setStart(star); lujing.setEnd(end); return h.put(end, lujing);//put方法的返回值就是value值。 } if (parent.equals(end)) {//如果得到的最佳邻点与目标点相同,则直接返回最佳邻点对应的result对象。 return h.get(parent); } //在路径经过点中加入parent后,更新h集合,要么起始点经过parent达到parent相邻点是最优的,要么起始点到parent相邻点不可达,而通过parent可达。 //获取parent对象(最佳点)的相邻点。 //分析一个parent最佳点后,把它的相邻点都会加入到h中,在下一次调用getNextStation获取h中未被标记且距离(起始点到该station的距离)最短。 List childLinkStations = getLinkStations(parent); //D:B C E for (station child : childLinkStations) { if (l.contains(child)) { continue; } String key = parent.getSname() + ":" + child.getSname(); Double distance; if (parent.getSname().equals(child.getSname())) { distance = 0.0D; } Double parentDistance = h.get(parent).getDistance(); distance = parentDistance+1.0; List parentPassStations = h.get(parent).getPassStations(); lujing childResult = h.get(child); if (childResult != null) { if (childResult.getDistance() > distance) { childResult.setDistance(distance); //如果通过最佳点比直接到距离小,则更新h中的对应result对象。 childResult.getPassStations().clear(); childResult.getPassStations().addAll(parentPassStations);//路径更新为A->最佳点->child点。 childResult.getPassStations().add(child); } } else { childResult = new lujing();//如果在h中没有最佳点的相邻点,则往h中添加通过最佳点(初始为起始点的最佳邻点)到达该点。 childResult.setDistance(distance); childResult.setStart(star); childResult.setEnd(child); childResult.getPassStations().addAll(parentPassStations); childResult.getPassStations().add(child); } h.put(child, childResult); } //初始时,即第一次调用该方法时,在分析点中加入起始点的最佳相邻点,后面嵌套调用时,就为获取某点的最佳邻点,在用最佳邻点更新h后,往l中加入最佳邻点。 l.add(parent); //加入最佳邻点后,更新h,再次调用calculate return calculate(star, end); //或: // calculate(star, end); 继续往下走,选择最佳点,然后更新h。 // return h.get(end); } public static List getLinkStations(station station) { //传入起始点station对象。 List linkedStaions = new ArrayList (); for (List line : distance.lset) { for (int i = 0; i < line.size(); i++) {//遍历每条地铁线,若地铁线中存在该站点,则判断,如果该站点位于地铁线的起始站,则相邻站为地铁线的第二个站点(i+1), //如果该站点位于地铁线的最后一个站,则相邻站为地铁线的倒数第二个站点(i-1), //如果该站点位于地铁线的其余位置,则相邻站点为该站点前后位置(i-1/i+1) if (station.equals(line.get(i))) { if (i == 0) { linkedStaions.add(line.get(i + 1)); } else if (i == (line.size() - 1)) { linkedStaions.add(line.get(i - 1)); } else { linkedStaions.add(line.get(i + 1)); linkedStaions.add(line.get(i - 1)); } } } } return linkedStaions; } private static station getNextStation() {//获取最短路径距离 Double min = Double.MAX_VALUE; station rets = null; Set stations = h.keySet();//获取h中的station集合。 for (station station : stations) { if (l.contains(station)) {//如果该点被标记为“已被分析”(已被分析表示起始点到该点的最短路径已求出) continue; } lujing result = h.get(station);//循环分析h中未被标记的点,求出最短路径的result对象。 if (result.getDistance() < min) { min = result.getDistance(); //得到终点的station对象 rets = result.getEnd(); } } return rets; } private static double doubleAdd(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); } public static void getResultToText(String filePath) throws IOException { if (filePath == null) { throw new FileNotFoundException("兄弟来个路径保存路径吧"); } BufferedWriter writer = null; //追加路径信息... writer = new BufferedWriter(new FileWriter(filePath, true)); Set > lineSet = distance.lset; for (List
stations : lineSet) { for (station station : stations) { for (List stations2 : lineSet) { for (station stationTarget : stations2) { Dijkstra d = new Dijkstra(); lujing lujing = d.calculate(station, stationTarget); h = new HashMap<>(); l = new ArrayList<>(); for (station s : lujing.getPassStations()) { if (s.getSname().equals(stationTarget.getSname())) { String text = station.getSname() + "\t" + stationTarget.getSname() + "\t" + lujing.getPassStations().size() + "\t" + lujing.getDistance() + "\t"; for (station test : lujing.getPassStations()) { text = text + test.getSname() + ","; } writer.write(text); writer.newLine(); } } } } } } writer.flush(); writer.close(); } }
distance.java:
通过站点名称获取线路信息:
public static String getLineName(station station){ createlineData(); String startname = station.getSname(); for (Map.Entry> entry : ldata.entrySet()) { List stations = entry.getValue(); for (station sta : stations){ if(sta.getSname().equals(startname)){ return entry.getKey(); } } } return ""; }
获取线路信息:
public static ArrayListgetLine(String l1,String l2){ ArrayList l = new ArrayList (); String[] a = l1.split(",");//每个站点之间用逗号分隔 for (String s : a) { l.add(new station(s,l2)); } return l; }
写入线路数据:
public static String writeLineData(String lname){ createlineData(); lname = lname.substring(0,1); Lista = ldata.get(lname); String lstr = a.stream().map(x->x.getSname()).collect(Collectors.joining(",")); try { Files.write(Paths.get(writedis), lstr.getBytes()); } catch (IOException e) { e.printStackTrace(); } return lstr; }
输出最短线路:
public static void shortline(lujing l){ FileWriter a= null; BufferedWriter b = null; try { a = new FileWriter(new File(writedis),true); b = new BufferedWriter(a); b.write((l.getPassStations().size()+1) + "\t\n");//写入总站数 b.write(l.getStart().getSname() + "\t\n");//写入起点站 String startlname = getLineName(l.getStart());//通过起点站名称得到线路名 String c = startlname; for (station station : l.getPassStations()){ if(!c.equals(station.getLname())){ b.write(station.getLname()+"号线" + "\t\n");//写入转乘站名 b.write(station.getSname()+ "\t\n"); c = station.getLname(); }else{ b.write(station.getSname() + "\t\n"); } } a.close(); b.close(); } catch (IOException e) { e.printStackTrace(); } }
读取文件:
public static void readinformation() { File file = new File(readdis); BufferedReader reader = null; try { InputStreamReader i = new InputStreamReader(new FileInputStream(file), "UTF-8"); reader = new BufferedReader(i); String l = null; String lname = "1"; while ((l = reader.readLine()) != null) { if (l.trim().startsWith("*")) { String[] a = l.substring(1).split("-"); lset.add(getLine(a[1].trim(), a[0].trim())); } } } catch (IOException e) { e.printStackTrace(); } finally { } }
输出线路信息:
public void readwj(){ try { FileReader f = new FileReader("station.txt"); BufferedReader b = new BufferedReader(f); String str=b.readLine(); while(str!=null) { System.out.println(str); str=b.readLine(); } f.close(); b.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("文件不存在"); } }
输出最短路径:
public void readshort(){ try { FileReader f = new FileReader("routine.txt"); BufferedReader b = new BufferedReader(f); String str=b.readLine(); while(str!=null) { System.out.println(str); str=b.readLine(); } f.close(); b.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("文件不存在"); } } }
model包里有lujing.java,station.java
lujing.java(是对于路径上站点变量函数的存储结构):
package model; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class lujing { private station start;//起点 private station end;//终点 private Double distance = 0.0D;//站点距离 private ListpassStations = new ArrayList<>();//经过的站点 public station getStart() { return start; } public void setStart(station start) { this.start = start; } public station getEnd() { return end; } public void setEnd(station end) { this.end = end; } public Double getDistance() { return distance; } public void setDistance(Double distance) { this.distance = distance; } public List getPassStations() { return passStations; } public void setPassStations(List passStations) { this.passStations = passStations; } }
station.java(是对于线路上变量函数的存储结构):
package model; import java.util.ArrayList; import java.util.List; public class station { private String sname; // 站点名称 private String lname; // 所属线路名称 private Listlstation = new ArrayList<>(); //相邻连接的站点 public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getLname() { return lname; } public void setLname(String lname) { this.lname = lname; } public List getLstation() { return lstation; } public void setLstation(List lstation) { this.lstation = lstation; } public station(String sname, String lname) { this.sname = sname; this.lname = lname; } public station(String sname) { this.sname = sname; } }
main包里有subway.java
subway.java:
package main; import java.io.File; import java.io.IOException; import control.Dijkstra; import control.distance; import model.lujing; import model.station; public class subway { public static void main(String[] args) throws IOException { distance d=new distance(); switch (args[0]){ case "-map": if(args.length==2){ distance.readdis=System.getProperty("user.dir") + File.separator + "\\" + args[1]; distance.readinformation(); System.out.println("成功读取subway.txt文件"); }else{ System.out.println("读取错误"); } break; case "-a": if(args.length==6){ distance.readdis = System.getProperty("user.dir") + File.separator + "\\" + args[3]; distance.writedis = System.getProperty("user.dir") + File.separator + "\\" + args[5]; distance.readinformation(); distance.writeLineData(args[1]); System.out.println("线路站点:"); d.readwj(); }else{ System.out.println("读取错误"); } break; case "-b": if(args.length==7){ distance.readdis = System.getProperty("user.dir") + File.separator + "\\" + args[4]; distance.writedis = System.getProperty("user.dir") + File.separator + "\\" + args[6]; distance.readinformation(); lujing l = Dijkstra.calculate(new station(args[1]), new station(args[2])); d.shortline(l); System.out.println("最短线路:"); d.readshort(); }else{ System.out.println("读取错误"); } break; } } }
四、运行方法
需求1:读取subway.txt文件的语句:
java subway -map subway.txt
需求2:输出指定线路的所有站点
java subway -a 1号线 -map subway.txt -o station.txt
需求3:输出两站点之间的最短路径
subway.exe -b 洪湖里 复兴路 -map subway.txt -o routine.txt
五、体会
由于是首次做一个感到如此艰难的个人项目,相比于暑期的短学期项目,这个明显难了很多,对于个人能力要求上了不止一个大档次。其次,刚开始写代码,一直卡在最短路径算法这个方向,后来想到了dijkstra算法,但是对这个算法又并没有那么熟悉,所以在这个个人项目中,借鉴了网上的算法代码,但是,在参考了代码之后,一直看的糊糊涂涂,了解了之后也并没有能学以致用,这是对于自己一个失望的地方。