北京地铁出行规划
一、北京地铁线路图
station存储
/** * 站点名字. */ private String name; /** * 所属线路. * */ private String line; /** * 相邻连接站点. */ private List<Station> linkStations = new ArrayList<>();
读取subway.txt并且输出routine
ublic class subway { public static void main(String[] args) throws IOException { switch (args[0]){ case "-map": //-map subway.txt if(args.length==2){ DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[1]; //根据路径,读取地铁信息,并打印。 DistanceBuilder.readSubway(); System.out.println("成功读取subway.txt文件"); }else{ System.out.println("验证参数格式!"); } break; case "-a": //-a 1号线 -map subway.txt -o station.txt if(args.length==6){ DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[3]; DistanceBuilder.WRITE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[5]; DistanceBuilder.readSubway(); DistanceBuilder.writeLineData(args[1]); System.out.println("已将结果写入station.txt文件"); }else{ System.out.println("验证参数格式!"); } break; case "-b": //-b 洪湖里 复兴路 -map subway.txt -o routine.txt if(args.length==7){ DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[4]; DistanceBuilder.WRITE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[6]; DistanceBuilder.readSubway(); Result result = DijkstraUtil.calculate(new Station(args[1]), new Station(args[2])); DistanceBuilder.writePassStationLine(result); System.out.println("已将结果写入routine. txt文件"); }else{ System.out.println("验证参数格式!"); } break; } } }
用迪杰特斯拉算法计算
public class DijkstraUtil { /** * 结果集. *resultMap */ private static HashMap<Station, Result> resultMap = new HashMap<>(); /** * 分析过的站点集合. * */ private static List<Station> analysisList = new ArrayList<>(); /** * 迪杰斯特拉算法应用在地铁的实现. * * @param star the star * @param end the end * @return the result * @since hui_project 1.0.0 */ public static Result calculate(Station star, Station end) { //将开始站点加入到分析过的站点集合。 if (!analysisList.contains(star)) { analysisList.add(star); } //如果开始站点等于终止站点,则设置result,设置距离和station。 if (star.equals(end)) { Result result = new Result(); result.setDistance(0.0D); result.setEnd(star); result.setStar(star); return resultMap.put(star, result); } //第一次调用calculate,且起始点和终止点不同,则resultMap为空。 if (resultMap.isEmpty()) { //第一次调用获取起始点的相邻站点(在所有地铁线中,这里涉及转线交叉的周围站点) List<Station> linkStations = getLinkStations(star); //把相邻站点集合中的所有站点,加入resultMap中。 因为相邻,则可以直接获取Distance。 for (Station station : linkStations) { Result result = new Result(); result.setStar(star); result.setEnd(station); String key = star.getName() + ":" + station.getName(); Double distance = DistanceBuilder.getDistance(key); result.setDistance(distance); result.getPassStations().add(station); resultMap.put(station, result); } } Station parent = getNextStation(); //如果resultMap所有点keySet被分析完了,则返回的parent为null。 if (parent == null) { Result result = new Result(); result.setDistance(0.0D); result.setStar(star); result.setEnd(end); //put方法的返回值就是value值。 return resultMap.put(end, result); } //如果得到的最佳邻点与目标点相同,则直接返回最佳邻点对应的result对象。 if (parent.equals(end)) { return resultMap.get(parent); } //在路径经过点中加入parent后,更新resultMap集合,要么起始点经过parent达到parent相邻点是最优的,要么起始点到parent相邻点不可达,而通过parent可达。 //获取parent对象(最佳点)的相邻点。 //分析一个parent最佳点后,把它的相邻点都会加入到resultMap中,在下一次调用getNextStation获取resultMap中未被标记且距离(起始点到该station的距离)最短。 List<Station> childLinkStations = getLinkStations(parent); //D:B C E for (Station child : childLinkStations) { if (analysisList.contains(child)) { continue; } String key = parent.getName() + ":" + child.getName(); Double distance; distance = DistanceBuilder.getDistance(key); DistanceBuilder.getDistance(key); if (parent.getName().equals(child.getName())) { distance = 0.0D; } Double parentDistance = resultMap.get(parent).getDistance(); distance = doubleAdd(distance, parentDistance); List<Station> parentPassStations = resultMap.get(parent).getPassStations(); Result childResult = resultMap.get(child); if (childResult != null) { //既可以A->B,也可以通过最佳点D,从A->D->B if (childResult.getDistance() > distance) { //如果通过最佳点比直接到距离小,则更新resultMap中的对应result对象。 childResult.setDistance(distance); childResult.getPassStations().clear(); //路径更新为A->最佳点->child点。 childResult.getPassStations().addAll(parentPassStations); childResult.getPassStations().add(child); } } else { //如果在resultMap中没有最佳点的相邻点,则往resultMap中添加通过最佳点(初始为起始点的最佳邻点)到达该点。 childResult = new Result(); childResult.setDistance(distance); childResult.setStar(star); childResult.setEnd(child); childResult.getPassStations().addAll(parentPassStations); childResult.getPassStations().add(child); } resultMap.put(child, childResult); } //初始时,即第一次调用该方法时,在分析点中加入起始点的最佳相邻点,后面嵌套调用时,就为获取某点的最佳邻点,在用最佳邻点更新resultMap后,往analysisList中加入最佳邻点。 analysisList.add(parent); //加入最佳邻点后,更新resultMap,再次调用calculate return calculate(star, end); //或: // calculate(star, end); 继续往下走,选择最佳点,然后更新resultMap。 // return resultMap.get(end); } /** * 获取所有相邻节点. * * @param station the station * @return the link stations * @since hui_project 1.0.0 */ //传入起始点station对象。 public static List<Station> getLinkStations(Station station) { List<Station> linkedStaions = new ArrayList<Station>(); for (List<Station> line : DistanceBuilder.lineSet) { 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; } /** * 通过计算最小权值 计算下一个需要分析的点 * 将resultMap中的station集合循环遍历,获取“未被标记的点(未在analysisList中)”中,对应result对象中距离最小的终点station对象。 * @return the next station * @since hui_project 1.0.0 */ private static Station getNextStation() { Double min = Double.MAX_VALUE; Station rets = null; //获取resultMap中的station集合。 Set<Station> stations = resultMap.keySet(); for (Station station : stations) { //如果该点被标记为“已被分析”(已被分析表示起始点到该点的最短路径已求出) if (analysisList.contains(station)) { continue; } //循环分析resultMap中未被标记的点,求出最短路径的result对象。 Result result = resultMap.get(station); if (result.getDistance() < min) { min = result.getDistance(); //得到终点的station对象 rets = result.getEnd(); } } return rets; }
读取距离信息
public static HashMap<String,HashMap<String,Double>> distanceMap = new HashMap<String,HashMap<String,Double>>(); public static LinkedHashSet<List<Station>> lineSet = new LinkedHashSet<>();//所有线集合 public static HashMap<String,List<Station>> lineData; private DistanceBuilder() { } static { createlineData(); } public static void createlineData(){ lineData = new HashMap<>(); for (List<Station> stations : lineSet) { lineData.put(stations.get(1).getLine(),stations); } } public static String getLineNameByStation(Station station){ createlineData(); String startname = station.getName(); for (Map.Entry<String,List<Station>> entry : lineData.entrySet()) { List<Station> stations = entry.getValue(); for (Station sta : stations){ if(sta.getName().equals(startname)){ return entry.getKey(); } } } return ""; }
测试样例:java subway -b 万寿路 七里庄 -map subway.txt -o routine.txt
github:https://github.com/wuyuhanoch/wu