地鐵最短路徑(程式碼部分)
阿新 • • 發佈:2020-11-04
地鐵線路的資訊儲存在一份文字文件中,格式為:
地鐵線路總數
線路名1 站名1 站名2 站名3 ...
線路名2 站名1 站名2 站名3 ...
線路名3 站名1 站名2 站名3 ......
1.主要功能
1.實現一個支援顯示地鐵線路與計算換乘的程式
2.查詢指定地鐵線經過的站點
3.使用者希望能獲得以最少的站數從出發點到達目的地的路徑
2.實現語言
java
3.實現演算法
BFS(廣度優先演算法)
4.類職責劃分
public static HashMap<String,station> Map = new HashMap<>();//查詢站點資訊
public static List
5.核心程式碼(主要部分)
public static void readSubway(String way) {//從TXT中讀入線路資料 try { InputStreamReader reader = new InputStreamReader(new FileInputStream(way)); BufferedReader read1 = new BufferedReader(reader); String read = ""; read = read1.readLine();//線路數量 int num = 0; num = Integer.parseInt(read); for (int i = 0; i <= num; i++) { line line = new line();//當前存的路線 read = read1.readLine(); if(read==null){ return; } String[] stations = read.split(" ");//讀入的line對應的所有station line.setLineName(stations[0]);//地鐵線路名 for (int j = 1; j < stations.length - 1; j++) { station station1 = new station();//當前line中的station station station2 = new station(); if (Map.containsKey(stations[j])) {//如果map中已經有該站點則把這個站點拿出來處理 station1 = Map.get(stations[j]); Map.remove(stations[j]); } else { station1.setStationName(stations[j]); station1.setVisited(false); } if (Map.containsKey(stations[j + 1])) {//Map中已經有該站後面的站點拿出來處理 station2 = Map.get(stations[j + 1]); Map.remove(stations[j + 1]); } else { station2.setStationName(stations[j + 1]); station2.setVisited(false); } if (!station1.getLine().contains(line.getLineName()))//如果當前站未加入line中,則在line中當前站名 station1.AddStationLine(line.getLineName()); if (!station2.getLine().contains(line.getLineName())) station2.AddStationLine(line.getLineName()); if (!station1.getLinkStations().contains(station2)) station1.AddLinkStation(station2); if (!station2.getLinkStations().contains(station1)) station2.AddLinkStation(station1); station1.setPreStation(station1.getStationName()); station2.setPreStation(station2.getStationName()); Map.put(stations[j], station1);//把station1放回Map Map.put(stations[j + 1], station2);//把station2放回Map if (!line.getStations().contains(station1.getStationName())) { line.stationAdd(station1.getStationName()); } if (!line.getStations().contains(station2.getStationName())) { line.stationAdd(station2.getStationName()); } } LineSet.add(line);//把線路加入LineSet } read1.close(); }catch(Exception e){ e.printStackTrace(); } } public static void searchline(String line){ //根據線路名字查詢該線路所有站點 int flag = 0; int index = -1; for (line line1 :LineSet){ index++; if(line1.getLineName().equals(line)) { flag = 1; break; } } if (flag==0) System.out.println("該地鐵線路不存在"); else { System.out.print(line + ": "); for (String str : LineSet.get(index).getStations()) { System.out.print(str + " "); } } } public static void BFS(String start,String end){//使用BFS廣度優先演算法計算 int sign = 0; if (!Map.containsKey(start)){//判斷start是否存在 System.out.println("start不存在"); sign = 1; } if (!Map.containsKey(end)){ System.out.println("end不存在");//判斷end是否存在 sign = 1; } for (String temp :Map.keySet()){ Map.get(temp).setVisited(false);//初始化都設為false Map.get(temp).setDistance(0);//初始化距離為0 } station nowStation = new station(); Queue<String> queue = new LinkedList<>();//存放遍歷過的站點 nowStation = Map.get(start); queue.add(start); while(!queue.isEmpty()){ String nowStationName = queue.poll(); Map.get(nowStationName).setVisited(true); if (nowStation.getStationName().equals(end)){ break; } for (station station1 :Map.get(nowStationName).getLinkStations()){ if(!Map.get(station1.getStationName()).isVisited()){//未訪問過的臨近站點 Map.get(station1.getStationName()).setPreStation(nowStationName);//為preStation賦值 Map.get(station1.getStationName()).setDistance(Map.get(nowStationName).getDistance()+1);//臨近站的距離為本站距離加1 queue.offer(station1.getStationName()); } } } } public static void path(String start,String end){//輸出路徑 if (start.equals(end)){ System.out.print("起點站與終點站相同 本站為:"+start); return; } List<String> path = new ArrayList<>(); Stack<String> printline = new Stack<>(); int numStation = 1;//存放站數 String str = end; while(!str.equals(start)){ path.add(str); printline.push(str); str = Map.get(str).getPreStation(); } path.add(str);//把start放入path printline.push(str); for (int i=1;i<path.size()-1;i++){ if (Map.get(path.get(i)).getLine().size()==1){ continue; } String temp1=""; String temp2=""; for (String str1 : Map.get(path.get(i)).getLine()){//本站與前一站的共同擁有的線路存在temp1中 int flag=0; for (String str2 :Map.get(path.get(i-1)).getLine()){ if (str1.equals(str2)){ temp1 = temp1+str1; flag=1; break; } } if (flag==1) break; } for (String str1 : Map.get(path.get(i)).getLine()){//後一站與本站的共同擁有的線路存在temp2中 int flag=0; for (String str2 :Map.get(path.get(i+1)).getLine()){ if (str1.equals(str2)){ temp2 = temp2+str1; flag=1; break; } } if (flag==1) break; } if (!temp1.equals(temp2))//若temp1和temp2兩線路不同則本站為轉乘站 Map.get(path.get(i)).setIfchange(true); } //判斷path中的換乘站 while(!printline.empty()){ String printStation = printline.pop(); if(numStation==1){ for (String strnow : Map.get(printStation).getLine()){ for (String nextStation : Map.get(path.get(path.size()-numStation-1)).getLine()){ if (strnow.equals(nextStation)) { System.out.println("從"+strnow+"出發"); } } } } if (Map.get(printStation).isIfchange()){ String nowline =""; for (String strnow : Map.get(printStation).getLine()){ for (String nextStation : Map.get(path.get(path.size()-numStation-1)).getLine()){ if (strnow.equals(nextStation)) nowline= nowline + strnow; } } System.out.println(printStation); System.out.println("轉 "+nowline); } System.out.print(printStation+" "); numStation++; } numStation =numStation-1; System.out.println(); System.out.println("一共"+numStation+"站");//輸出最後一共乘坐的站數 } public static void main(String[] ards){ readSubway("E:\\原桌面\\大三上\\軟體工程\\地鐵.txt"); System.out.println("1.查詢某條線路的所有站點"); System.out.println("2.查詢某站到某站的最短線路"); System.out.print("請輸入序號(1或者2):"); Scanner Scanner = new Scanner(System.in); int input = Scanner.nextInt(); if (input==1){ System.out.print("請輸入地鐵線路名稱:"); Scanner Scanner1 = new Scanner(System.in); String linename = Scanner1.nextLine(); searchline(linename); } else if (input==2){ System.out.print("start:"); Scanner Scanner2 = new Scanner(System.in); String start =Scanner2.nextLine(); System.out.print("end:"); String end = Scanner2.nextLine(); BFS(start,end); path(start,end); } }
package test; import java.util.*; public class line { private String LineName; //線名 private List<String> stations= new ArrayList<String>(); //該線路中所有站 public List<String> getStations() { return stations; } public void setStations(List<String> stations) { this.stations = stations; } public String getLineName() { return LineName; } public void setLineName(String lineName) { LineName = lineName; } public void stationAdd(String name){ stations.add(name); } }
package test;
import java.util.*;
public class station {
private String Name; //站點名
private List<String> Line = new ArrayList<String>(); //所線上路(如果是換乘點的話可以有多個)
private List<station> LinkStations= new ArrayList<station>(); //與之相鄰的站點
private boolean visited;//是否訪問過該站點
private String beforeStation;//本站之前訪問的站點
private int distance=0;//本站距離起點站的站數
private boolean ifchange;//是否換乘 預設為false 用於結果
public boolean isIfchange() {
return ifchange;
}
public void setIfchange(boolean ifchange) {
this.ifchange = ifchange;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
public void AddStationLine(String name){
Line.add(name);
}
public void AddLinkStation(station sta){
LinkStations.add(sta);
}
public String getStationName() {
return Name;
}
public void setStationName(String stationName) {
Name = stationName;
}
public List<String> getLine() {
return Line;
}
public void setLine(List<String> line) {
Line = line;
}
public List<station> getLinkStations() {
return LinkStations;
}
public void setLinkStations(List<station> linkStations) {
LinkStations = linkStations;
}
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
public String getPreStation() {
return beforeStation;
}
public void setPreStation(String preStation) {
this.beforeStation = preStation;
}
}
6.測試用例
1查詢某條路線的所有站點:
不存在時:
2查詢某站到某站的最短線路
起點和終點在一條線上時:
起點和終點在不同線上時:
輸入不存在的起點:
輸入不存在的終點:
全部程式碼詳情請移步github:https://github.com/YuKeeMM/subway.git
7.總結
這是第一次使用部落格園的方式發表,使用起來很不錯。本次的作業有所難度,演算法等其他方面都還有待改進,自己的程式碼能力還是不足,需要不斷地練習。