北京地铁查询实现最短路径

在做这个web的时候首先做了线路的线路名称查询和站点查询,在做最短路径的时候遇到了困难,因为在平时做的系统中并没有涉及到太复杂的算法,这次涉及到了算法,我在github上找了一些资料来写

package algorithm;

import java.util.ArrayList;
import java.util.List;

public class Station {
    private String StationName;/*记录站点名*/
    private boolean Visited;/*是否被遍历过*/
    private String PreStation;/*便于搜索是返回和记录*/
    List<String> StationLine = new ArrayList<>();/*该站点存在的所有线路信息*/
    public List<Station> NearStation = new ArrayList<>();/*该站点存在的所有邻近站点信息*/

    public String getStationName() {
        return StationName;
    }

    public void setStationName(String stationName) {
        StationName = stationName;
    }

    public boolean isVisited() {
        return Visited;
    }

    public void setVisited(boolean visited) {
        Visited = visited;
    }

    public String getPreStation() {
        return PreStation;
    }

    public void setPreStation(String preStation) {
        PreStation = preStation;
    }

    public List<String> getStationLine() {
        return StationLine;
    }

    public void setStationLine(List<String> stationLine) {
        StationLine = stationLine;
    }

    public List<Station> getNearStation() {
        return NearStation;
    }

    public void setNearStation(List<Station> nearStation) {
        NearStation = nearStation;
    }
}

 

package algorithm;

import java.util.ArrayList;

//算法,地铁最短路径,数据存储类
public class line {
    public String LineName;/*记录当前线路名*/
    ArrayList<String> Station = new ArrayList<>();/*记录该线路中所有的站点名*/

    public String getLineName() {
        return LineName;
    }

    public void setLineName(String lineName) {
        LineName = lineName;
    }

    public ArrayList<String> getStation() {
        return Station;
    }

    public void setStation(ArrayList<String> station) {
        Station = station;
    }

    @Override
    public String toString() {
        return "Line{" +
                "LineName='" + LineName + '\'' +
                ", Station=" + Station +
                '}';
    }
}

 

package algorithm;

import java.io.*;
import java.util.*;

public class Main {
    static ArrayList<line> LineList = new ArrayList<>();//存放所有线路的列表
    static ArrayList<Station> StationList = new ArrayList<>();//存放线路站点的列表
    public static HashMap<String, Station> stationHashMap = new HashMap<>();//存放对应站点的Hash
    /*对文件进行读入和存储操作*/
    public static void SubwayMessage(String pathname){
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(pathname)));
            String NowLine = null;
            while ((NowLine=bufferedReader.readLine()) != null){
                line line = new line();
                String[] StationInformation = NowLine.split(" ");
                line.setLineName(StationInformation[0]);
                for (int i = 1; i < StationInformation.length-1; i++){
                    Station NowStation = new Station();
                    Station NextStation = new Station();
                    if(stationHashMap.containsKey(StationInformation[i])){
                        /*如果hashmap中已经存在该站点信息,因为需要修改所以将它放入NowStation中*/
                        NowStation = stationHashMap.get(StationInformation[i]);
                        stationHashMap.remove(StationInformation[i]);
                    }
                    else{
                        NowStation.setStationName(StationInformation[i]);
                        NowStation.setVisited(false);
                    }
                    if(stationHashMap.containsKey(StationInformation[i+1])){
                        /*如果hashmap中已经存在该站点信息,因为需要修改所以将它放入NowStation中*/
                        NextStation = stationHashMap.get(StationInformation[i+1]);
                        stationHashMap.remove(StationInformation[i+1]);
                    }
                    else{
                        NextStation.setStationName(StationInformation[i+1]);
                        NextStation.setVisited(false);
                    }
                    /*如果站点不包含当前线路,将线路添加至站点*/
                    if(!NowStation.getStationLine().contains(line.LineName)){
                        NowStation.getStationLine().add(line.LineName);
                    }
                    if(!NextStation.getStationLine().contains(line.LineName)){
                        NextStation.getStationLine().add(line.LineName);
                    }
                    /*如果站点不含下一站,将相邻站添加至NextStation*/
                    if(!NowStation.getNearStation().contains(NextStation)){
                        NowStation.getNearStation().add(NextStation);
                    }
                    if(!NextStation.getNearStation().contains(NowStation)){
                        NextStation.getNearStation().add(NowStation);
                    }
                    NowStation.setPreStation(NowStation.getStationName());
                    NextStation.setPreStation(NextStation.getStationName());

                    stationHashMap.put(StationInformation[i], NowStation);
                    stationHashMap.put(StationInformation[i+1], NextStation);
                    /*将当前站点添加至线路中*/
                    if(!line.getStation().contains(NowStation.getStationName())){
                        line.getStation().add(NowStation.getStationName());
                    }
                    if(!line.getStation().contains(NextStation.getStationName())){
                        line.getStation().add(NextStation.getStationName());
                    }
                }
                LineList.add(line);
            }
            /*释放资源*/
            bufferedReader.close();
        } catch (IOException e) {
            System.out.println("Read file error, Please try again!");
        }
    }
    /*输出线路信息*/
    public static void PrintMessage(String StartStation, String EndStation){
        List<String> list = new ArrayList<>();
        String NowStation = EndStation;
        String PreLine = "";
        while (!NowStation.equals(StartStation)){
            list.add(NowStation);
            NowStation = stationHashMap.get(NowStation).getPreStation();
        }
        Collections.reverse(list);
        System.out.println("当前路程共经过:"+(list.size())+"站");
        System.out.print(StartStation);
        for (int i = 0; i < list.size(); i++){
            if(stationHashMap.get(list.get(i)).getStationLine().size()==1){
                /*如果当前站点只存在一条线路,显然不可能在此站换乘*/
                System.out.print("-->"+stationHashMap.get(list.get(i)).getStationName());
                PreLine = stationHashMap.get(list.get(i)).getStationLine().get(0);
            }
            else {
                /*如果该站点存在多条线路,并且下一站只有一条线路*/
                if (stationHashMap.get(list.get(i+1)).getStationLine().size()==1){
                    /*如果该站和前一站线路相同,直接输出
                     * 如果不同,则表明为换乘线,输出该站名,然后显示换乘线路信息*/
                    if(stationHashMap.get(list.get(i+1)).getStationLine().get(0).equals(PreLine)){
                        System.out.print("-->"+stationHashMap.get(list.get(i)).getStationName());
                    }
                    else{
                        System.out.println("-->"+stationHashMap.get(list.get(i)).getStationName());
                        System.out.println("换乘"+stationHashMap.get(list.get(i+1)).getStationLine().get(0));
                        PreLine = stationHashMap.get(list.get(i+1)).getStationLine().get(0);
                    }
                }
                else{
                    /*对于多线路站点,如果包含前一站的线路信息说明不需要换乘
                     * 如果不包含,遍历前后两站的线路信息,换乘线路一定存在于两站都共有的线路节点中*/
                    if (stationHashMap.get(list.get(i+1)).getStationLine().contains(PreLine)){
                        System.out.print("-->"+stationHashMap.get(list.get(i)).getStationName());
                    }
                    else{
                        boolean IsSame = false;
                        for (int t1 = 0; t1 < stationHashMap.get(list.get(i)).getStationLine().size(); t1++){
                            if (stationHashMap.get(list.get(i+1)).getStationLine().contains(stationHashMap.get(list.get(i)).getStationLine().get(t1))){
                                System.out.println("-->"+stationHashMap.get(list.get(i)).getStationName());
                                System.out.println("换乘"+stationHashMap.get(list.get(i)).getStationLine().get(t1));
                                PreLine = stationHashMap.get(list.get(i)).getStationLine().get(t1);
                                IsSame = true;
                                break;
                            }
                        }
                        if(IsSame){
                            System.out.print("-->"+stationHashMap.get(list.get(i)).getStationName());
                        }
                    }
                }
            }
        }
    }
    /*利用BFS算法进行最短路径遍历*/
    public static void SearchShortPath(String StartStation, String EndStation){
        /*初始化所有站点的遍历信息*/
        for (Map.Entry<String, Station> entry: stationHashMap.entrySet()){
            entry.getValue().setVisited(false);
        }
        Queue<String> queue = new LinkedList<>();
        queue.add(StartStation);
        while (!queue.isEmpty()){
            /*如果队列不为空,移除队列头部,将该站设置为遍历过*/
            String NowStation = queue.poll();
            stationHashMap.get(NowStation).setVisited(true);
            if (NowStation.equals(EndStation)){
                break;
            }
            /*对于该站点的所有相邻节点进行遍历,如果未被遍历,则PreStation设置为当前站,将该相邻站添加至队列中*/
            for (Station station:stationHashMap.get(NowStation).NearStation){
                if (stationHashMap.get(station.getStationName()).isVisited()==false){
                    stationHashMap.get(station.getStationName()).setPreStation(NowStation);
                    queue.add(station.getStationName());
                }
            }
        }
    }
    /*查找线路信息*/
    public static void main(String[] args) {
        SubwayMessage("D:\\subway.txt");
        Scanner input = new Scanner(System.in);
        System.out.println("请输入起始站:");
        String start = input.nextLine();
        System.out.println("请输入终点站");
        String end = input.nextLine();
        boolean IsExisted = true;
        if (!stationHashMap.containsKey(start)) {
            IsExisted = false;
            System.out.println("不存在该起始站");

        }
        if (!stationHashMap.containsKey(end)) {
            IsExisted = false;
            System.out.println("不存在该终点站");
        }
        if (IsExisted) {
            SearchShortPath(start, end);
            PrintMessage(start, end);
        }
    }
}

这个只能在控制台输出,我根据这个进行改写。

将方法的返回值改为对象或者集合,然后使用域对象进行存储,在使用el表达式将其结果输出。

package ShortPath.util;

import ShortPath.model.BeanEdge;
import ShortPath.model.BeanShortestPath;
import ShortPath.model.BeanVertex;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class Graph {
    private BeanEdge edges;
    private Map<String, BeanVertex> vertexes;

    /**
     * @param edges
     * @param vertexes
     */
    public Graph(BeanEdge edges, Map<String, BeanVertex> vertexes) {
        super();
        this.edges = edges;
        this.vertexes = vertexes;
    }


    public int[] dijkstra(int startVertexIndex) {
        boolean[] collected = new boolean[edges.getEdgeValues().length];
        int[] dist = new int[edges.getEdgeValues().length];
        int[] path = new int[edges.getEdgeValues().length];

        // 初始化
        for (int i=0; i<edges.getEdgeValues().length; i++) {
            if (i==startVertexIndex) {  // 等于起始点
                collected[i] = true;
                dist[i] = 0;
                path[i] = i;
            } else {  // 不是起始点
                collected[i] = false;
                if (edges.getEdgeValues()[startVertexIndex][i] > 0) {  // 起始点能到
                    dist[i] = edges.getEdgeValues()[startVertexIndex][i];
                    path[i] = startVertexIndex;
                } else {
                    dist[i] = Integer.MAX_VALUE;
                    path[i] = -1;
                }
            }

        }

        while (true) {
            int minDistIndex = getMinVertex(collected, dist);  // 未收录顶点中 collected=false 的dist最小者
            if (minDistIndex == -1) {
                break;
            }
            collected[minDistIndex] = true;

            for (int i=0; i<edges.getEdgeValues().length; i++) {  // minVertex的每个邻接点
                if (edges.getEdgeValues()[minDistIndex][i]>0 && collected[i] == false) {
                    dist[i] = dist[minDistIndex] + edges.getEdgeValues()[minDistIndex][i];
                    path[i] = minDistIndex;
                }
            }
        }

        return path;
    }

    private int getMinVertex(boolean[] collected, int[] dist) {
        int minDist = Integer.MAX_VALUE;
        int minDistIndex = -1;
        for (int i=0; i<edges.getEdgeValues().length; i++) {
            if (collected[i] == false && dist[i]<minDist) {
                minDist = dist[i];
                minDistIndex = i;
            }
        }

        return minDistIndex;
    }

    public BeanShortestPath getShortestPath(String startStationName, String endStationName) {
        int[] path = dijkstra(vertexes.get(startStationName).getId());

        Map<Integer, BeanVertex> id2StationName = new HashMap<>();  // 再搞一个id到结点的映射
        id2StationName = getId2StationName();

        BeanShortestPath shortestPath = new BeanShortestPath();
        int stationId = vertexes.get(endStationName).getId();
        while (stationId != vertexes.get(startStationName).getId()) {
            shortestPath.getStations().add(id2StationName.get(stationId));  // 根据id找名字找站点
            shortestPath.getLineNames().add(edges.getEdgeNames()[stationId][path[stationId]]);  // 当前站到 上一站 的名字
            stationId = path[stationId];
        }
        shortestPath.getStations().add(id2StationName.get(stationId));  // 加入起点
        Collections.reverse(shortestPath.getStations());
        Collections.reverse(shortestPath.getLineNames());
        return shortestPath;
    }

    private Map<Integer, BeanVertex> getId2StationName() {
        Map<Integer, BeanVertex> id2StationName = new HashMap<>();
        for (BeanVertex v: vertexes.values()) {
            id2StationName.put(v.getId(), v);
        }
        return id2StationName;
    }

    public Map<String, BeanVertex> getVertexes() {
        return vertexes;
    }

    public BeanEdge getEdges() {
        return edges;
    }


    public void setEdges(BeanEdge edges) {
        this.edges = edges;
    }


    public void setVertexes(Map<String, BeanVertex> vertexes) {
        this.vertexes = vertexes;
    }
}
package ShortPath.util;

import ShortPath.model.BeanEdge;
import ShortPath.model.BeanVertex;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class Reader {
    public static Graph readSubwayInfo(String txtPath) {
        Graph graph = null;
        BufferedReader reader;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(txtPath)), "UTF-8"));

            // 先将文件中的数据读入 (因为要重复用到)
            ArrayList<String> txtLines = new ArrayList<String>();
            {  // 使变量名txtLine只在此区域生效  便于下面for each遍历时取同样的变量名
                String txtLine;
                while ((txtLine = reader.readLine()) != null) {
                    txtLines.add(txtLine);
                }
            }

            // 保存所有站点
            Map<String, BeanVertex> stations = new HashMap<>();
            for (String txtLine: txtLines) {
                String[] stationNames = txtLine.split(" ");
                String lineName = stationNames[0];
                for (int i=1; i<stationNames.length; i++) {  // 0是lineName
                    if (!stations.containsKey(stationNames[i])) {  // map中没有 需要创建后加入
                        BeanVertex v = new BeanVertex(stations.size(), stationNames[i]);
                        v.getLine().add(lineName);
                        stations.put(stationNames[i], v);
                    } else {  // map中有 需要加一个lineName
                        stations.get(stationNames[i]).getLine().add(lineName);
                    }
                }

            }


            // 保存边信息 即站点之间的联系  以及边名称(线路名称)
            BeanEdge edge = new BeanEdge(stations.size());
            for (String txtLine: txtLines) {
                String[] stationNames = txtLine.split(" ");
                String lineName = stationNames[0];
                for (int i=1; i<stationNames.length-1; i++) {
                    BeanVertex station1 = stations.get(stationNames[i]);
                    BeanVertex station2 = stations.get(stationNames[i+1]);
                    edge.getEdgeValues()[station1.getId()][station2.getId()] = 1;
                    edge.getEdgeValues()[station2.getId()][station1.getId()] = 1;
                    edge.getEdgeNames()[station1.getId()][station2.getId()] = lineName;
                    edge.getEdgeNames()[station2.getId()][station1.getId()] = lineName;
                }
            }

            // 构建图
            graph = new Graph(edge, stations);
        } catch (UnsupportedEncodingException | FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return graph;
    }
}
package Servlet;

import ShortPath.model.BeanShortestPath;
import ShortPath.util.Graph;
import ShortPath.util.Reader;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "InputStations", value = "/InputStations")
public class InputStations extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");

        Graph graph = Reader.readSubwayInfo("D:\\subway.txt");//进行文件导入,如果需要导入数据库数据需要进行数据查询,再将其存储到集合中
        String start = request.getParameter("startStation");
        String end = request.getParameter("endStation");
        BeanShortestPath shortestPath = graph.getShortestPath(start,end);
        request.setAttribute("result",shortestPath);
        request.getRequestDispatcher("output.jsp").forward(request,response);
    }
}

 

posted on 2022-04-05 17:16  跨越&尘世  阅读(46)  评论(0编辑  收藏  举报