地铁线路最短路径(完整)


项目介绍:

 

 

 

提供一副地铁线路图,计算指定两站之间最短(最少经过站数)乘车路线;输出指定地铁线路的所有站点。以北京地铁为例,地铁线路信息保存在data.txt中,格式如下:

地铁线路总数

线路名1 站名1 站名2 站名3 ...

线路名2 站名1 站名2 站名3 ...

线路名3 站名1 站名2 站名3 ......

需求分析:

1、主要功能

  (1)能实现地铁信息的导入

  (2)能够保存各个站点的信息

  (3)输入起始站点和目标站点后计算出指定两站之间最短乘车路线

  (4)能输出乘车线路经过的所有站点的信息

  (5)能够给出站点的换乘信息

  (6)若有多个最短路线时优先选择换乘少的线路

  (7)若有多个最优解则全部输出

2、实现语言

  java

3、实现算法

  Dijkstra算法

 

  ①基本思想:设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,对vi∈V-S,假设从源点v到vi的有向边为最短路径。以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。重复上述过程,直到集合V中全部顶点加入到集合S中。

 

4、类职责划分(相关类的功能进行描述)

  • Line类

用于保存线路信息

 List<Station> line 保存线路信息

 

 

  • Station类

用于保存站点信息,线路名称,测试站点到某一个目标站点所经过的所有站集合

 

String name 站点名称
String Linename 线路名称
Station prevsation 在当前线路时,所在站点的前一个站
Station nextsation 在当前线路时,所在站点的后一个站
Map<Station,LinkedHashSet<Station>> ordermap 测试站点到某一个目标站点(key)所经过的所有站集合

 

 

 

 

 

 

 

  • ReadFile类

基本功能时读取文件“地铁线路信息.txt”内容,储存到Line,Station中,保存所有线路及该线路的站点信息,站点总数

Set<List<Station>> lineSet    保存所有线路信息
totalStation 保存站点总数
readText() 函数用于读取文件

 

 

 

 

 

  • dijkstra类

 用于计算最短路径得出结果输出

List<Station> getAllNearStations(Station station) 函数用于得到与传入参数所有相邻的站点
Station getShortPath(Station station) 函数用于得到参数到各个站的最短距离站
void result(Station s1,Station s2) 函数用于得出最终结果并输出
void main(String[] args) 主函数用于输入起始站点

 

 

 

 

 

 

5、核心代码

Line类

public class Line {
    //集合保存线路信息
    public static List<Station> line = new ArrayList<Station>();

    public static List<Station> getLine() {
        return line;
    }

    public static void setLine(List<Station> line) {
        Line.line = line;
    }

}

 

Station类

public class Station {
//地铁站名称
private String name; 
//地铁线路名
private String Linename; 

//在当前线路时,所在站点的前一个站
public Station prevsation; 

//在当前线路时,所在站点的后一个站
public Station nextsation; 

//测试站点到某一个目标站点(key)所经过的所有站集合
private Map<Station,LinkedHashSet<Station>> ordermap = new HashMap<Station,LinkedHashSet<Station>>();

        public String getLinename() {
            return Linename;
        }

        public void setLinename(String linename) {
            Linename = linename;
        }

    public Station (String name){
        this.name = name;
    }
 

    public Station() {
        // TODO Auto-generated constructor stub
    }

    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
    //记录当前测试站点到目标站点所经过的所有站点,并储存
    public LinkedHashSet<Station> getAllPassedStations(Station station) {
        if(ordermap.get(station) == null){     
            LinkedHashSet<Station> set = new LinkedHashSet<Station>(); 
            set.add(this);//this为当前类的实例
            ordermap.put(station, set);
        }
        return ordermap.get(station);
    }
 
    public Map<Station, LinkedHashSet<Station>> getOrderMap() {
        return ordermap;
    }
    
    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        } else if(obj instanceof Station){
            Station s = (Station) obj;
            if(s.getName().equals(this.getName())){
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    
    @Override
    public int hashCode() {
        return this.getName().hashCode();
    }

}

 

ReadFile类

public class ReadFile {
    //集合保存所有线路及该线路的站点信息
    public static Set<List<Station>> lineSet = new HashSet<List<Station>>();
    //所有站点数
    public static int totalStation = 0;
     //文件读取函数  
    public static void readText(){
        Station Prevstation = new Station();
        try {
            File file=new File("地铁线路信息.txt");
            //判断文件是否存在
            if(file.isFile() && file.exists()){ 
                InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
                BufferedReader bufferedReader = new BufferedReader(reader);
                String stationline = null;
              
                int flag = 0;
                while((stationline = bufferedReader.readLine()) != null){
                     String[] tmp = stationline.split(" ");//分割符号,将空格置空
                     List<Station> Linestations = new ArrayList<Station>();//设置一个链表保存线路信息
                    for(int j=1;j<tmp.length;j++) {
                        Station station = new Station();
                        station.setLinename(tmp[0]);//将每一行的第一个字符串存入线路名
                        station.setName(tmp[j]);//保存站点名称
                        Linestations.add(station);//保存线路信息
                        totalStation++;//计算总站点数
                        if(flag != 0) {//当flag不为零时,存在前后站点
                            station.prevsation = Prevstation;
                            Prevstation.nextsation = station;
                        }
                        Prevstation = station;//记录从零开始记录的站点
                        flag++;
                    }
                    lineSet.add(Linestations);//添加为线路集
                }
               // 关闭文件
                reader.close();
                bufferedReader.close();
            }
            else
                System.out.println("找不到指定的文件!");
          } catch (Exception e) {
              System.out.println("文件内容出错!");
              e.printStackTrace();
           }        
        }
     
}

 

dijkstra类

public class dijkstra {

private List<Station> List1 = new ArrayList<Station>();//保存已经遍历过的站点

//得到与传入参数所有相邻的站点
    private List<Station> getAllNearStations(Station station){
        List<Station> linkedStaions = new ArrayList<Station>();
        for(List<Station> line : ReadFile.lineSet){//遍历所有线路
            if(line.contains(station)){//当前线路中包含参数站点
                Station s = line.get(line.indexOf(station));//取出当前线路上的该站点的值
                if(s.prevsation != null){
                    linkedStaions.add(s.prevsation);//得到当前线路的该站点的前一个站点
                }
                if(s.nextsation != null){
                    linkedStaions.add(s.nextsation);//得到当前线路的该站点的后一个站点
                }
            }
        }
        return linkedStaions;
    }
    
//得到参数到各个站的最短距离每一站距离为1
        private Station getShortPath(Station station){
            int min = 10000;//定义一个较大的数用做比较
            Station rets = null;
            for(Station s :station.getOrderMap().keySet()){//遍历当前测试站点到所有站点
                if(List1.contains(s)){
                    continue;
                }
                LinkedHashSet<Station> set  = station.getAllPassedStations(s);//当前测试站点到未遍历站点的路径
                if(set.size() < min){
                    min = set.size();//取路径最短的哪一个
                    rets = s;
                }
            }
            return rets;//返回最近的这一个站点
        }
    
    //计算最短经过路径
    public void result(Station s1,Station s2){
        int flag = 0;
        String tempname = "";
        String linename = "";
        int flag1=0;
        //遍历所有站点,判断输入的站名名称是否存在
        for(List<Station> line : ReadFile.lineSet){
            if(line.contains(s1)){
                flag1=1;
            }
        }
        if(flag1==0) {
            System.out.println("输入站点不存在,请重新输入!");
            return ;
        }
        
        int flag2=0;
        
        for(List<Station> line : ReadFile.lineSet){
            if(line.contains(s2)){
                flag2=1;
            }
        }
        if(flag2==0) {
            System.out.println("输入站点不存在,请重新输入!");
            return ;
        }
        //当所有站点都遍历完
        if(List1.size() == ReadFile.totalStation){
            System.out.println("起点:"+s1.getName()+"  终点站:"+s2.getName()+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
            int p=0;
            for(Station station : s1.getAllPassedStations(s2)){//输出遍历s1到s2经过的路径
                p++;
                if(flag == 0) {
                    tempname = station.getName();
                }
                else if(flag == 1) {
                    linename=station.getLinename();
                    System.out.print(station.getLinename()+tempname+"->");
                }
                else {
                    if(!station.getLinename().equals(linename)) {//换乘线路换行输出
                        linename=station.getLinename();
                        System.out.println();
                    }
                    if(p<s1.getAllPassedStations(s2).size()-1) {
                        System.out.print(station.getLinename()+" "+station.getName()+"->");
                    }
                    else {
                        System.out.print(station.getLinename()+" "+station.getName());
                    }
                    
                }
                flag++;
            }
            return;
        }
        if(!List1.contains(s1)){//将当前测试站点储存在已遍历链表
            List1.add(s1);
        }
        //如果起点的测试站点的OrderMap为空,则第一次用该站的相邻站点初始化
        if(s1.getOrderMap().isEmpty()){
            List<Station> Linkedstations = getAllNearStations(s1);
            for(Station s : Linkedstations){
                s1.getAllPassedStations(s).add(s);
            }
        }
        Station psation = getShortPath(s1);//获取距离起点站s1最近的一个站
        if(psation == s2){
            System.out.println("找到目标站点:"+s2+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
            for(Station station : s1.getAllPassedStations(s2)){
                System.out.print(station.getName()+"->");
            }
            return;
        }
        for(Station station1 : getAllNearStations(psation)){
            if(List1.contains(station1)){
                continue;
            }
            int shortestPath = (s1.getAllPassedStations(psation).size()-1) + 1;//计算所需距离
            if(s1.getAllPassedStations(station1).contains(station1)){
                //如果s1已经计算过到此station1的经过距离,那么比较出最小的距离
                if((s1.getAllPassedStations(station1).size()-1) > shortestPath){
                    //重置S1到周围各站的最小路径
                    s1.getAllPassedStations(station1).clear();
                    s1.getAllPassedStations(station1).addAll(s1.getAllPassedStations(psation));
                    s1.getAllPassedStations(station1).add(station1);
                }
            } else {
                //如果s1还没有计算过到此station1的经过距离
                s1.getAllPassedStations(station1).addAll(s1.getAllPassedStations(psation));
                s1.getAllPassedStations(station1).add(station1);
            }
        }
        List1.add(psation);
        result(s1,s2);//重复计算,往外面站点扩展
    }

 
    public static void main(String[] args) {
        dijkstra subway = new dijkstra();
        ReadFile.readText();
        Scanner input =new Scanner(System.in);
        System.out.print("请输入起点:");
        String str1 = input.next();
        System.out.print("请输入终点:");
        String str2 = input.next();
        
        subway.result(new Station(str1), new Station(str2));    
    }
}

 

6、测试用例

测试一:站点输入有误

测试二:不用换乘

测试三:不用换乘

测试四:换乘

测试五:换乘

7、总结

1.没有完成需求分析中的选择换乘少的路线和输出全部最优解,要进一步完善思考。

2.写代码的过程中,意识到自己对于最短路径算法的理解不透彻,完成过程中查找了很多资料。

3.认识到自己的不足要多多锻炼努力。

 

完整代码已上传https://github.com/tongyao063/SubWay2.git


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM