个人项目——地铁线路

个人git

一、项目需求

1.该程序能够准确地读出.txt文件中的数据,文件格式简洁易懂、可灵活扩展

2.在某号线路上,能够查询各个站点的信息,输出该号线路上所有站点信息

3.在出发站与目的站之间输出一个最短路径

二、文件存储

 

 

 

 个人项目——地铁线路_第1张图片

 

 

 三、文件位置

一共三个package:control、main、model

个人项目——地铁线路_第2张图片

 

control包里有Dijkstra.java,distance.java

Dijkstra.java(此代码为最短路径算法,这是最核心最难的地方,dijkstra算法能很好地解决最短路径问题,这段代码是借鉴了网上的代码,但是我还没能理解透彻):

package control;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import model.*;


public class Dijkstra {
    private static HashMap h = new HashMap<>();
    private static List l = new ArrayList<>();
    public static lujing calculate(station star, station end) {
        
        if (!l.contains(star)) {//将开始站点加入到分析过的站点集合。
            l.add(star);
        }
        
        if (star.equals(end)) {//如果开始站点等于终止站点,则设置result,设置距离和station。
            lujing lujing = new lujing();
            
            lujing.setDistance(0.0D);
            lujing.setEnd(star);
            lujing.setStart(star);
            return h.put(star, lujing);
        }
        
        if (h.isEmpty()) {//第一次调用calculate,且起始点和终止点不同,则h为空。
           
            List ls = getLinkStations(star); //第一次调用获取起始点的相邻站点(在所有地铁线中,这里涉及转线交叉的周围站点)
            
            for (station station : ls) {//把相邻站点集合中的所有站点,加入h中。 因为相邻,则可以直接获取Distance。

                lujing lujing = new lujing();
                lujing.setStart(star);
                lujing.setEnd(station);
                String key = star.getSname() + ":" + station.getSname();
                lujing.setDistance(1.0);
                lujing.getPassStations().add(station);
                h.put(station, lujing);
            }
        }
        station parent = getNextStation();
       
        if (parent == null) { //如果h所有点keySet被分析完了,则返回的parent为null。
            lujing lujing = new lujing();
            lujing.setDistance(0.0D);
            lujing.setStart(star);
            lujing.setEnd(end);
            
            return h.put(end, lujing);//put方法的返回值就是value值。
        }
        
        if (parent.equals(end)) {//如果得到的最佳邻点与目标点相同,则直接返回最佳邻点对应的result对象。
            return h.get(parent);
        }


        //在路径经过点中加入parent后,更新h集合,要么起始点经过parent达到parent相邻点是最优的,要么起始点到parent相邻点不可达,而通过parent可达。
        //获取parent对象(最佳点)的相邻点。
        //分析一个parent最佳点后,把它的相邻点都会加入到h中,在下一次调用getNextStation获取h中未被标记且距离(起始点到该station的距离)最短。
        List childLinkStations = getLinkStations(parent);
        //D:B C E
        for (station child : childLinkStations) {
            if (l.contains(child)) {
                continue;
            }
            String key = parent.getSname() + ":" + child.getSname();
            Double distance;

            if (parent.getSname().equals(child.getSname())) {
                distance = 0.0D;
            }

            Double parentDistance = h.get(parent).getDistance();
            distance = parentDistance+1.0;

            List parentPassStations = h.get(parent).getPassStations();
            lujing childResult = h.get(child);
            if (childResult != null) {
                
                if (childResult.getDistance() > distance) {
                   
                    childResult.setDistance(distance); //如果通过最佳点比直接到距离小,则更新h中的对应result对象。
                    childResult.getPassStations().clear();
                    
                    childResult.getPassStations().addAll(parentPassStations);//路径更新为A->最佳点->child点。
                    childResult.getPassStations().add(child);
                }
            } else {
                
                childResult = new lujing();//如果在h中没有最佳点的相邻点,则往h中添加通过最佳点(初始为起始点的最佳邻点)到达该点。
                childResult.setDistance(distance);
                childResult.setStart(star);
                childResult.setEnd(child);
                childResult.getPassStations().addAll(parentPassStations);
                childResult.getPassStations().add(child);
            }
            h.put(child, childResult);
        }
        //初始时,即第一次调用该方法时,在分析点中加入起始点的最佳相邻点,后面嵌套调用时,就为获取某点的最佳邻点,在用最佳邻点更新h后,往l中加入最佳邻点。
        l.add(parent);
        //加入最佳邻点后,更新h,再次调用calculate
        return calculate(star, end);
        //或:
        // calculate(star, end); 继续往下走,选择最佳点,然后更新h。
        // return h.get(end);
    }

   
    public static List getLinkStations(station station) { //传入起始点station对象。
        List linkedStaions = new ArrayList();

       for (List line : distance.lset) {
            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;
    }
    private static station getNextStation() {//获取最短路径距离
        Double min = Double.MAX_VALUE;
        station rets = null;
        
        Set stations = h.keySet();//获取h中的station集合。
        for (station station : stations) {
            
            if (l.contains(station)) {//如果该点被标记为“已被分析”(已被分析表示起始点到该点的最短路径已求出)
                continue;
            }
            
            lujing result = h.get(station);//循环分析h中未被标记的点,求出最短路径的result对象。
            if (result.getDistance() < min) {
                min = result.getDistance();
                //得到终点的station对象
                rets = result.getEnd();
            }
        }
        return rets;
    }

    private static double doubleAdd(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }
    public static void getResultToText(String filePath) throws IOException {
        if (filePath == null) {
            throw new FileNotFoundException("兄弟来个路径保存路径吧");
        }
        BufferedWriter writer = null;
        //追加路径信息...
        writer = new BufferedWriter(new FileWriter(filePath, true));
        Set> lineSet = distance.lset;
        for (List stations : lineSet) {
            for (station station : stations) {
                for (List stations2 : lineSet) {
                    for (station stationTarget : stations2) {
                       Dijkstra d = new Dijkstra();
                        lujing lujing = d.calculate(station, stationTarget);
                        h = new HashMap<>();
                        l = new ArrayList<>();
                        for (station s : lujing.getPassStations()) {
                            if (s.getSname().equals(stationTarget.getSname())) {
                                String text = station.getSname() + "\t" + stationTarget.getSname() + "\t" + lujing.getPassStations().size() + "\t" + lujing.getDistance() + "\t";
                                for (station test : lujing.getPassStations()) {
                                    text = text + test.getSname() + ",";
                                }
                                writer.write(text);
                                writer.newLine();
                            }
                        }
                    }

                }
            }
        }
        writer.flush();
        writer.close();
    }
}

distance.java:

通过站点名称获取线路信息:

public static String getLineName(station station){
        createlineData();
        String startname = station.getSname();
        for (Map.Entry> entry : ldata.entrySet()) {
            List stations =  entry.getValue();
            for (station sta : stations){
                if(sta.getSname().equals(startname)){
                    return entry.getKey();
                }
            }
        }
        return "";
    }

获取线路信息:

public static ArrayList getLine(String l1,String l2){
        ArrayList l =  new ArrayList();
        String[] a = l1.split(",");//每个站点之间用逗号分隔
        for (String s : a) {
            l.add(new station(s,l2));
        }
        return l;
    }

写入线路数据:

  public static String writeLineData(String lname){
        createlineData();
        lname = lname.substring(0,1);
        List a = ldata.get(lname);
        String lstr = a.stream().map(x->x.getSname()).collect(Collectors.joining(","));
        try {
            Files.write(Paths.get(writedis), lstr.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  lstr;
    }

输出最短线路:

public static void shortline(lujing l){
    	FileWriter a= null;
    	BufferedWriter b = null;
    	try {
    		a = new FileWriter(new File(writedis),true);
    	    b = new BufferedWriter(a);
    	    b.write((l.getPassStations().size()+1) + "\t\n");//写入总站数
    	    b.write(l.getStart().getSname() + "\t\n");//写入起点站
    	    String startlname = getLineName(l.getStart());//通过起点站名称得到线路名
    	    String c = startlname;
    	    for (station station : l.getPassStations()){
    	    	if(!c.equals(station.getLname())){
    	    		b.write(station.getLname()+"号线" + "\t\n");//写入转乘站名
    	            b.write(station.getSname()+ "\t\n");
    	            c = station.getLname();
    	            }else{
    	            	b.write(station.getSname() + "\t\n");
    	            	}
    	            }
    	            a.close();
    	            b.close();
    	            } catch (IOException e) {
    	        	e.printStackTrace();
    	            }
    	}

读取文件:

public static void readinformation() {
		File file = new File(readdis);
		BufferedReader reader = null;
		try {
			InputStreamReader i = new InputStreamReader(new FileInputStream(file), "UTF-8");
			reader = new BufferedReader(i);
			String l = null;
			String lname = "1";
			while ((l = reader.readLine()) != null) {
				if (l.trim().startsWith("*")) {
					String[] a = l.substring(1).split("-");
					lset.add(getLine(a[1].trim(), a[0].trim()));
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
		}
	}

输出线路信息:

public void readwj(){
		try {
			FileReader f = new FileReader("station.txt");
			BufferedReader b = new BufferedReader(f);
			String str=b.readLine();
			while(str!=null) {
				System.out.println(str);
				str=b.readLine();
			}
			f.close();
			b.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("文件不存在");
		}
		
    }

输出最短路径:

public void readshort(){
		try {
			FileReader f = new FileReader("routine.txt");
			BufferedReader b = new BufferedReader(f);
			String str=b.readLine();
			while(str!=null) {
				System.out.println(str);
				str=b.readLine();
			}
			f.close();
			b.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("文件不存在");
		}
		
    }
}

model包里有lujing.java,station.java

lujing.java(是对于路径上站点变量函数的存储结构):

package model;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


public class lujing {
	private station start;//起点
    private station end;//终点
    private Double distance = 0.0D;//站点距离
    private List passStations = new ArrayList<>();//经过的站点
	public station getStart() {
		return start;
	}
	public void setStart(station start) {
		this.start = start;
	}
	public station getEnd() {
		return end;
	}
	public void setEnd(station end) {
		this.end = end;
	}
	public Double getDistance() {
		return distance;
	}
	public void setDistance(Double distance) {
		this.distance = distance;
	}
	public List getPassStations() {
		return passStations;
	}
	public void setPassStations(List passStations) {
		this.passStations = passStations;
	}
	
}

station.java(是对于线路上变量函数的存储结构):

package model;

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

public class station {
	private String sname; // 站点名称
	private String lname; // 所属线路名称
	private List lstation = new ArrayList<>(); //相邻连接的站点
	

    public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public String getLname() {
		return lname;
	}

	public void setLname(String lname) {
		this.lname = lname;
	}

	public List getLstation() {
		return lstation;
	}

	public void setLstation(List lstation) {
		this.lstation = lstation;
	}

	public station(String sname, String lname) {
        this.sname = sname;
        this.lname = lname;
    }

    public station(String sname) {
        this.sname = sname;
    }
}

main包里有subway.java

subway.java:

package main;

import java.io.File;
import java.io.IOException;

import control.Dijkstra;
import control.distance;
import model.lujing;
import model.station;


public class subway {
	public static void main(String[] args) throws IOException {
		distance d=new distance();
	       switch (args[0]){
	           case "-map":
	               if(args.length==2){
	                   distance.readdis=System.getProperty("user.dir") + File.separator + "\\" + args[1];
	                   distance.readinformation();
	                   System.out.println("成功读取subway.txt文件");
	               }else{
	                   System.out.println("读取错误");
	               }
	               break;

	           case "-a":
	               if(args.length==6){
	            	   distance.readdis = System.getProperty("user.dir") + File.separator + "\\" + args[3];
	            	   distance.writedis = System.getProperty("user.dir") + File.separator + "\\" + args[5];
	                   distance.readinformation();
	                   distance.writeLineData(args[1]);
	                   System.out.println("线路站点:");
	                   d.readwj();
	               }else{

	                   System.out.println("读取错误");
	               }
	               break;
	           case "-b":

	               if(args.length==7){
	            	   distance.readdis = System.getProperty("user.dir") + File.separator + "\\" + args[4];
	                   distance.writedis = System.getProperty("user.dir") + File.separator + "\\" + args[6];
	                   distance.readinformation();
	                   lujing l = Dijkstra.calculate(new station(args[1]), new station(args[2]));
	                   d.shortline(l);
	                   System.out.println("最短线路:");
	                   d.readshort();
	               }else{
	                   System.out.println("读取错误");
	               }
	               break;
	       }
	    }
}

四、运行方法

需求1:读取subway.txt文件的语句:

java subway -map subway.txt

 个人项目——地铁线路_第3张图片

 

 

需求2:输出指定线路的所有站点

java subway -a 1号线 -map subway.txt -o station.txt

 

需求3:输出两站点之间的最短路径

subway.exe -b 洪湖里 复兴路 -map subway.txt -o routine.txt

 

五、体会

由于是首次做一个感到如此艰难的个人项目,相比于暑期的短学期项目,这个明显难了很多,对于个人能力要求上了不止一个大档次。其次,刚开始写代码,一直卡在最短路径算法这个方向,后来想到了dijkstra算法,但是对这个算法又并没有那么熟悉,所以在这个个人项目中,借鉴了网上的算法代码,但是,在参考了代码之后,一直看的糊糊涂涂,了解了之后也并没有能学以致用,这是对于自己一个失望的地方。

你可能感兴趣的:(个人项目——地铁线路)