1. 程式人生 > 實用技巧 >地鐵最短路徑(程式碼部分)

地鐵最短路徑(程式碼部分)


地鐵線路的資訊儲存在一份文字文件中,格式為:

地鐵線路總數
線路名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 LineSet= new ArrayList<>();//查詢路線
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.總結
這是第一次使用部落格園的方式發表,使用起來很不錯。本次的作業有所難度,演算法等其他方面都還有待改進,自己的程式碼能力還是不足,需要不斷地練習。