个人项目——北京地铁出行线路规划

个人项目——北京地铁出行线路规划_第1张图片

基本需求
    1.获取所以的站点信息
    2.获取北京地铁单条线路上的所以站点
    3.获取两个站点之间的最短路线

代码简析

数据导入:

public static void read(){
	    	DistanceBuilder.FILE_PATH=System.getProperty("user.dir") + File.separator + "\\" +"subway.txt";
	    	DistanceBuilder.readSubway();
	    }

读取地铁线路信息:

public static void readSubway() {
        File file = new File(FILE_PATH);
        BufferedReader reader = null;

        try {
            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file),"UTF-8");

            reader = new BufferedReader(inputStreamReader);
            String line = null;
            //String如:苹果园:古城   double为距离,如:1
            //默认起始为1号线
            String lineName = "1";
            distanceMap.put("1",new HashMap<>());
            while ((line = reader.readLine()) != null) {
                //长度为1或2,则该行值为地铁线号。
                if(line.trim().length()==1||line.trim().length()==3||line.trim().length()==2){
                    if(line.trim().length()==3||line.trim().length()==2){ 
                        continue;
                    }
                    lineName = line;
                    //判断distanceMap中是否已创建该地铁线号。如果为创建该地铁线则加入distanceMap
                    if(!distanceMap.keySet().contains(line)){
                        distanceMap.put(line.trim(),new HashMap<>());
                    }
                }else{
                    //判断是否以"*"开头,如果*开头则为某条线的所有站点字符串。
                    if(line.trim().startsWith("*")){
                        String[] lineInfo = line.substring(1).split("-");
                        lineSet.add(getLine(lineInfo[1].trim(),lineInfo[0].trim()));
                    }else{
                        //地铁某站点到某站点信息,如:苹果园:古城	1
                        String texts[] = line.split("\t");
                        String key = texts[0].trim();
                        Double value = Double.valueOf(texts[1]);
                        distanceMap.get(lineName).put(key,value);
                        String other = key.split(":")[1].trim()+":"+key.split(":")[0].trim();
                        distanceMap.get(lineName).put(other,value);
                    }
                }
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
        }


    }

迪杰斯特拉算法应用在地铁的实现:

public class DijkstraUtil {
    private static HashMap resultMap = new HashMap<>();   // 分析过的站点集合.     
    private static List analysisList = new ArrayList<>();

    public static Result calculate(Station star, Station end) {   //迪杰斯特拉算法应用在地铁的实现.
        if (!analysisList.contains(star)) {
            analysisList.add(star);
        }
        if (star.equals(end)) {//起始站和终点站相同时返回result=0,终点站就是初始站
            Result result = new Result();
            result.setDistance(0.0D);
            result.setEnd(star);
            result.setStar(star);
            return resultMap.put(star, result);
            
        }
        if (resultMap.isEmpty()) {    //第一次调用calculate,且起始点和终止点不同,则resultMap为空。
            List linkStations = getLinkStations(star);   //第一次调用获取起始点的相邻站点(在所有地铁线中,这里涉及转线交叉的周围站点)
            for (Station station : linkStations) {   //把相邻站点集合中的所有站点,加入resultMap中,可以直接获取Distance。
                Result result = new Result();
                result.setStar(star);
                result.setEnd(station);
                String key = star.getName() + ":" + station.getName();
                Double distance = DistanceBuilder.getDistance(key);
                result.setDistance(distance);
                result.getPassStations().add(station);
                resultMap.put(station, result);
            }
        }
        Station parent = getNextStation();
        if (parent == null) {    //返回的parent为null,说明resultMap所有点keySet被分析完了
            Result result = new Result();
            result.setDistance(0.0D);
            result.setStar(star);
            result.setEnd(end);
            return resultMap.put(end, result);
        }
        if (parent.equals(end)) {   //寻找到终点,直接返回对应的result
            return resultMap.get(parent);
        }
        List childLinkStations = getLinkStations(parent);
        for (Station child : childLinkStations) {
            if (analysisList.contains(child)) {
                continue;
            }
            String key = parent.getName() + ":" + child.getName();
            Double distance;
            distance = DistanceBuilder.getDistance(key);
            DistanceBuilder.getDistance(key);
            if (parent.getName().equals(child.getName())) {
                distance = 0.0D;
            }
            Double parentDistance = resultMap.get(parent).getDistance();
            distance = doubleAdd(distance, parentDistance);
            List parentPassStations = resultMap.get(parent).getPassStations();
            Result childResult = resultMap.get(child);
            if (childResult != null) {
                if (childResult.getDistance() > distance) {     //通过最佳点比直接到距离小,就更新resultMap中的对应result对象。
                    childResult.setDistance(distance);
                    childResult.getPassStations().clear();
                    childResult.getPassStations().addAll(parentPassStations);//路线更新
                    childResult.getPassStations().add(child);
                }
            } else {   //通过最佳点比直接到距离小,直接从原路线到child点
                childResult = new Result();
                childResult.setDistance(distance);
                childResult.setStar(star);
                childResult.setEnd(child);
                childResult.getPassStations().addAll(parentPassStations);
                childResult.getPassStations().add(child);
            }
            resultMap.put(child, childResult);
        }
        analysisList.add(parent);
        calculate(star, end);
        return resultMap.get(end);
        
    }

  地铁线路切换以及相邻节点遍历:

private static List getLinkStations(Station station) {  // 获取所有相邻节点.
        List linkedStaions = new ArrayList();
        for (List line : DistanceBuilder.lineSet) {    //遍历所有地铁线
            for (int i = 0; i < line.size(); i++) {
                if (station.equals(line.get(i))) {
                    if (i == 0) {
                        linkedStaions.add(line.get(i + 1));//地铁站为换乘线的初始站,则继续+1遍历
                    } else if (i == (line.size() - 1)) {
                        linkedStaions.add(line.get(i - 1));//地铁站为换乘线的终点站,则继续-1遍历
                    } else {                               //地铁站为换乘线的中途站,则继续+1,-1遍历
                        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 = resultMap.keySet();
        for (Station station : stations) {
            if (analysisList.contains(station)) {   //跳过已经被分析过的站点
                continue;
            }
            Result result = resultMap.get(station);
            if (result.getDistance() < min) {   //寻找出未经过的最近点
                min = result.getDistance();
                rets = result.getEnd();
            }
        }
        return rets;
    }

  查询该站点所在地铁线:

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

  输出指定线路所有站点:

public static void writeLineData(String lineName){
        createlineData();
        lineName = lineName.substring(0,3);
        List lineInfo = lineData.get(lineName);
        //System.out.println(lineData.get(lineName));
        String lineStr = lineInfo.stream().map(x->x.getName()).collect(Collectors.joining(",","[","]"));
        System.out.print(lineStr);
    }

  输出最佳路线:

public static void getPassStation(Result result){
    	//System.out.print(result.getStar());
        String starLine = getLineNameByStation(result.getStar());
        String converLine = starLine;
        System.out.println("起始地铁线:"+starLine);
        for (Station station : result.getPassStations()) {
            if(!converLine.equals(station.getLine())){
                System.out.print("换乘地铁线:"+station.getLine()+"  ");
                converLine = station.getLine();
                converLine = station.getLine();
            }
            System.out.print(station.getName() + " > ");
        }
    }

  站点存储:

public class Station {
  
    private String name;  
    private String line;
    private List linkStations = new ArrayList<>();
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLine() {
        return line;
    }
    public void setLine(String line) {
        this.line = line;
    }
    public List getLinkStations() {
        return linkStations;
    }
    public void setLinkStations(List linkStations) {
        this.linkStations = linkStations;
    }
    public Station(String name, String line) {
        this.name = name;
        this.line = line;
    }
    public Station(String name) {
        this.name = name;
    }
    public Station (){

    }
    public int hashCode() {
		return this.getName().hashCode();
	}
	public String toString() {
		return "Station{" + "name='" + name +'\'' +",line='" + line + '\'' + ", linkStations=" + linkStations + '}';
	}
    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;
        }
    }
}

  运行结果存储:

public class Result {
    private Station star;
    private Station end;
    private Double distance = 0.0D;
    private List passStations = new ArrayList<>();
    public Station getStar() {
        return star;
    }
    public void setStar(Station star) {
        this.star = star;
    }
    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;
    }
    public Result(Station star, Station end, Double distance) {
        this.star = star;
        this.end = end;
        this.distance = distance;
    }
    public Result() {

    }

    @Override
    public String toString() {
        return "Result{" +
                "star=" + star +
                ", end=" + end +
                ", distance=" + distance +
                ", passStations=" + passStations +
                '}';
    }
}

  主函数:

public class Main {
	 public static void main(String[] args) {
	        read();
	        System.out.println("北京地铁查询");
	      while(true) {
	        write();
	        }
	    }
	    public static void read(){
	    	DistanceBuilder.FILE_PATH=System.getProperty("user.dir") + File.separator + "\\" +"subway.txt";
	    	DistanceBuilder.readSubway();
	    }
	    public static void write() {
	    	Scanner input=new Scanner(System.in);
	    	System.out.print("输入指令:(查询地铁线路信息:-info 八通线),(查询起末站线路:-way star end):");
	         String s=input.nextLine();
	         String[] split =s.split("\\s+");
	         if(split[0].equals("-map")) {
	        	 if(split.length==1){
	        		 DistanceBuilder.readSubway();
	                   System.out.println("成功读取subway.txt文件");
	               }else{
	                   System.out.println("重新输入");
	               }
	         }
	         else if(split[0].equals("-info")) {
	              if(split.length==2){
	            	  DistanceBuilder.readSubway();
	            	  DistanceBuilder.writeLineData(split[1]);
	               }else{

	                   System.out.println("输入错误,请重新输入");
	               }
	         }
	         else if(split[0].equals("-way")) {
	               if(split.length==3){
	            	   if(split[1].equals(split[2]))
	            		   System.out.println("输入站点重复,请重新输入");
	            	   else {
	            	   DistanceBuilder.readSubway();
	            	   System.out.println(split[1]+" -> "+split[2]+":");
	                   Result result = DijkstraUtil.calculate(new Station(split[1]), new Station(split[2]));
	                   //System.out.println(split[2]);
	                   DistanceBuilder.getPassStation(result);
	                   //System.out.println(result);
	                   if(result.getDistance()==0.0)
	                	   System.out.println("输入站点不存在");
	               }
	               }else{
	                   System.out.println("输入错误,请重新输入");
	               }
	               
	         
	         }
		    	System.out.println();
	    }
}

运行结果测试

1、输出指定线路所有站点信息

 

2、路线查询

(1).线路换乘

 

 

 (2).单线路乘车

 

 

 3、输入出错

(1).起点和终点相同

 

 

 

(2).输入站点不存在

 

 

 

(3).输入格式出错

个人项目——北京地铁出行线路规划_第2张图片

 

 

 个人感想

作业进行的比较艰辛,有借鉴了网络上的代码学习修改,对eclipse的Debug不熟悉,需要依靠println来查看代码运行中的参数传递过程。

写完这个作业对Java语言和迪杰斯特拉算法在Java上的使用都有了深入的了解,算是有所收获。

github链接: https://github.com/RealWyr/ZUCCwyr

 

你可能感兴趣的:(个人项目——北京地铁出行线路规划)