用迪杰斯特拉算法实现地铁的站点搜索

上一篇文章,利用迪杰斯特拉(dijkstra)算法,实现了无向图的最短路径搜索功能。本篇将以南京地铁为例,用迪杰斯特拉算法实现两个站点之间的最短路径搜索。

借用百度百科,南京2015年4月份的地铁运行线路图如下:

创建一个数据构造类,初始化南京地铁的各条线路站点数据(截至2015年4月南京地铁运营公司数据,与上图对应)

/**
 *
 */
package com.test.dijkstra;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * desc:构造数据关系(以南京地铁站1\2\3\10号线为例)
 * @author chaisson
 * @since 2015-5-31 上午10:23:52
 *
 */
public class DataBuilder {

	public static List<Station> line1 = new ArrayList<Station>();//1号线
	public static List<Station> line2 = new ArrayList<Station>();//2号线
	public static List<Station> line3 = new ArrayList<Station>();//3号线
	public static List<Station> line10 = new ArrayList<Station>();//10号线
	public static List<Station> lineS1 = new ArrayList<Station>();//s1号线
	public static List<Station> lineS8 = new ArrayList<Station>();//s8号线
	public static Set<List<Station>> lineSet = new HashSet<List<Station>>();//所有线集合
	public static int totalStaion = 0;//总的站点数量
	static {
		//1号线
		String line1Str = "迈皋桥站、红山动物园站、南京站、新模范马路站、玄武门站、鼓楼站、珠江路站、新街口站、张府园站、三山街站、中华门站、安德门站、天隆寺站、软件大道站、花神庙站、南京南站、双龙大道站、河定桥站、胜太路站、百家湖站、小龙湾站、竹山路站、天印大道站、龙眠大道站、南医大·江苏经贸学院站、南京交院站、中国药科大学站";
		String[] line1Arr = line1Str.split("、");
		for(String s : line1Arr){
			line1.add(new Station(s));
		}
		for(int i =0;i<line1.size();i++){
			if(i<line1.size()-1){
				line1.get(i).next = line1.get(i+1);
				line1.get(i+1).prev = line1.get(i);
			}
		}

		/*******************************************************************************/
		//2号线
		String line2Str = "油坊桥站、雨润大街站、元通站、奥体东站、兴隆大街站、集庆门大街站、云锦路站、莫愁湖站、汉中门站、上海路站、新街口站、大行宫站、西安门站、明故宫站、苜蓿园站、下马坊站、孝陵卫站、钟灵街站、马群站、金马路站、仙鹤门站、学则路站、仙林中心站、羊山公园站、南大仙林校区站、经天路站";
		String[] line2Arr = line2Str.split("、");
		for(String s : line2Arr){
			line2.add(new Station(s));
		}
		for(int i =0;i<line2.size();i++){
			if(i<line2.size()-1){
				line2.get(i).next = line2.get(i+1);
				line2.get(i+1).prev = line2.get(i);
			}
		}

		/*******************************************************************************/
		//3号线
		String line3Str = "林场站、星火路站、东大成贤学院站、泰冯路站、天润城站、柳洲东路站、上元门站、五塘广场站、小市站、南京站、南京林业大学·新庄站、鸡鸣寺站、浮桥站、大行宫站、常府街站、夫子庙站、武定门站、雨花门站、卡子门站、大明路站、明发广场站、南京南站、宏运大道站、胜太西路站、天元西路站、九龙湖站、诚信大道站、东大九龙湖校区站、秣周东路站";
		String[] line3Arr = line3Str.split("、");
		for(String s : line3Arr){
			line3.add(new Station(s));
		}
		for(int i =0;i<line3.size();i++){
			if(i<line3.size()-1){
				line3.get(i).next = line3.get(i+1);
				line3.get(i+1).prev = line3.get(i);
			}
		}

        /*******************************************************************************/
		//10号线
		String line10Str = "雨山路站、文德路站、龙华路站、南京工业大学站、浦口万汇城站、临江站、江心洲站、绿博园站、梦都大街站、奥体中心站、元通站、中胜站、小行站、安德门站";
		String[] line10Arr = line10Str.split("、");
		for(String s : line10Arr){
			line10.add(new Station(s));
		}
		for(int i =0;i<line10.size();i++){
			if(i<line10.size()-1){
				line10.get(i).next = line10.get(i+1);
				line10.get(i+1).prev = line10.get(i);
			}
		}

		/*******************************************************************************/
		//s1号线
		String lineS1Str = "南京南站、翠屏山站、河海大学·佛城西路站、吉印大道站、正方中路站、翔宇路北站、翔宇路南站、禄口机场站";
		String[] lineS1Arr = lineS1Str.split("、");
		for(String s : lineS1Arr){
			lineS1.add(new Station(s));
		}
		for(int i =0;i<lineS1.size();i++){
			if(i<lineS1.size()-1){
				lineS1.get(i).next = lineS1.get(i+1);
				lineS1.get(i+1).prev = lineS1.get(i);
			}
		}

		/*******************************************************************************/
		//s8号线
		String lineS8Str = "泰山新村站、泰冯路站、高新开发区站、信息工程大学站、卸甲甸站、大厂站、葛塘站、长芦站、化工园站、六合开发区站、龙池站、雄州站、凤凰山公园站、方州广场站、沈桥站、八百桥站、金牛湖站";
		String[] lineS8Arr = lineS8Str.split("、");
		for(String s : lineS8Arr){
			lineS8.add(new Station(s));
		}
		for(int i =0;i<lineS8.size();i++){
			if(i<lineS8.size()-1){
				lineS8.get(i).next = lineS8.get(i+1);
				lineS8.get(i+1).prev = lineS8.get(i);
			}
		}

		lineSet.add(line1);
		lineSet.add(line2);
		lineSet.add(line3);
		lineSet.add(line10);
		lineSet.add(lineS1);
		lineSet.add(lineS8);
		totalStaion  = line1.size() + line2.size() + line3.size() + line10.size() + lineS1.size() + lineS8.size();
		System.out.println("总的站点数量:"+totalStaion);
	}
}

构建地铁站对象(以地铁站名称进行唯一区分,hashcode基于name名称)

/**
 *
 */
package com.test.dijkstra;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;

/**
 * desc:地铁站对象
 * @author chaisson
 * @since 2015-5-31 上午10:22:44
 *
 */
public class Station {

	private String name; //地铁站名称,假设具备唯一性

	public Station prev; //本站在lineNo线上面的前一个站

	public Station next; //本站在lineNo线上面的后一个站

	//本站到某一个目标站(key)所经过的所有站集合(value),保持前后顺序
	private Map<Station,LinkedHashSet<Station>> orderSetMap = new HashMap<Station,LinkedHashSet<Station>>();

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public LinkedHashSet<Station> getAllPassedStations(Station station) {
		if(orderSetMap.get(station) == null){
			LinkedHashSet<Station> set = new LinkedHashSet<Station>();
			set.add(this);
			orderSetMap.put(station, set);
		}
		return orderSetMap.get(station);
	}

	public Map<Station, LinkedHashSet<Station>> getOrderSetMap() {
		return orderSetMap;
	}

	@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();
	}
}

具体的算法实现

/**
 *
 */
package com.test.dijkstra;

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

/**
 * desc:利用Dijkstra算法,计算地铁站经过路径,以南京地铁为例
 * @author chaisson
 * @since 2015-5-31 上午9:43:38
 *
 */
public class Subway {

	private List<Station> outList = new ArrayList<Station>();//记录已经分析过的站点

	//计算从s1站到s2站的最短经过路径
	public void calculate(Station s1,Station s2){
		if(outList.size() == DataBuilder.totalStaion){
			System.out.println("找到目标站点:"+s2.getName()+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
			for(Station station : s1.getAllPassedStations(s2)){
				System.out.print(station.getName()+"->");
			}
			return;
		}
		if(!outList.contains(s1)){
			outList.add(s1);
		}
		//如果起点站的OrderSetMap为空,则第一次用起点站的前后站点初始化之
		if(s1.getOrderSetMap().isEmpty()){
			List<Station> Linkedstations = getAllLinkedStations(s1);
			for(Station s : Linkedstations){
				s1.getAllPassedStations(s).add(s);
			}
		}
		Station parent = getShortestPath(s1);//获取距离起点站s1最近的一个站(有多个的话,随意取一个)
		if(parent == s2){
			System.out.println("找到目标站点:"+s2+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
			for(Station station : s1.getAllPassedStations(s2)){
				System.out.print(station.getName()+"->");
			}
			return;
		}
		for(Station child : getAllLinkedStations(parent)){
			if(outList.contains(child)){
				continue;
			}
			int shortestPath = (s1.getAllPassedStations(parent).size()-1) + 1;//前面这个1表示计算路径需要去除自身站点,后面这个1表示增加了1站距离
			if(s1.getAllPassedStations(child).contains(child)){
				//如果s1已经计算过到此child的经过距离,那么比较出最小的距离
				if((s1.getAllPassedStations(child).size()-1) > shortestPath){
					//重置S1到周围各站的最小路径
					s1.getAllPassedStations(child).clear();
					s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
					s1.getAllPassedStations(child).add(child);
				}
			} else {
				//如果s1还没有计算过到此child的经过距离
				s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
				s1.getAllPassedStations(child).add(child);
			}
		}
		outList.add(parent);
		calculate(s1,s2);//重复计算,往外面站点扩展
	}

	//取参数station到各个站的最短距离,相隔1站,距离为1,依次类推
	private Station getShortestPath(Station station){
		int minPatn = Integer.MAX_VALUE;
		Station rets = null;
		for(Station s :station.getOrderSetMap().keySet()){
			if(outList.contains(s)){
				continue;
			}
			LinkedHashSet<Station> set  = station.getAllPassedStations(s);//参数station到s所经过的所有站点的集合
			if(set.size() < minPatn){
				minPatn = set.size();
				rets = s;
			}
		}
		return rets;
	}

	//获取参数station直接相连的所有站,包括交叉线上面的站
	private List<Station> getAllLinkedStations(Station station){
		List<Station> linkedStaions = new ArrayList<Station>();
		for(List<Station> line : DataBuilder.lineSet){
			if(line.contains(station)){//如果某一条线包含了此站,注意由于重写了hashcode方法,只有name相同,即认为是同一个对象
				Station s = line.get(line.indexOf(station));
				if(s.prev != null){
					linkedStaions.add(s.prev);
				}
				if(s.next != null){
					linkedStaions.add(s.next);
				}
			}
		}
		return linkedStaions;
	}

	/**
	 * desc: How to use the method
	 * author chaisson
	 * since 2015-5-31
	 * version 1.0
	 */
	public static void main(String[] args) {
		long t1 = System.currentTimeMillis();
		Subway sw = new Subway();
		sw.calculate(new Station("南京站"), new Station("奥体东站"));
		long t2 = System.currentTimeMillis();
		System.out.println();
		System.out.println("耗时:"+(t2-t1)+"ms");
	}
}

以南京站到奥体东站为例,运行结果为:

总的站点数量:121

找到目标站点:奥体东站,共经过12站

南京站->新模范马路站->玄武门站->鼓楼站->珠江路站->新街口站->上海路站->汉中门站->莫愁湖站->云锦路站->集庆门大街站->兴隆大街站->奥体东站->

耗时:15ms

以上算法经过多次测试,均能计算出“最短的路径”,并可验证正确行,然后这其实并没有什么卵用,实际操作中,还需要继续优化算法,比如实现最少换乘,实时人流量平衡考虑,或者收费和换乘次数的最佳结合路线等等。

时间: 2024-10-04 06:00:38

用迪杰斯特拉算法实现地铁的站点搜索的相关文章

最短路径算法——迪杰斯特拉算法(Dijkstra)

图结构中应用的最多的就是最短路径的查找了,关于最短路径查找的算法主要有两种:迪杰斯特拉算法(Dijkstra)和Floyd算法. 其中迪杰斯特拉算法(Dijkstra)实现如下: 原理就是不断寻找当前的最优解: void main() { int V[Max][Max]={0,8,32,Infinity,Infinity, 12,0,16,15,Infinity, Infinity,29,0,Infinity,13, Infinity,21,Infinity,0,7, Infinity,Infi

迪杰斯特拉算法——PAT 1003

本文主要是将我对于我对于迪杰斯特拉算法的理解写出来,同时通过例题来希望能够加深对于算法的理解,其中有错误的地方希望大家指正. 迪杰斯特拉算法 我将这个算法理解成一个局部到整体的算法,这个方法确实越研究就会发现越经典. 首先可以将整个图的节点看成两个集合:一个是S,一个是U-S.如果是求v0到图中各点的最短距离的话,那么S就是已经确认到v0距离最短的点,U-S则是对于整体的点集合U,还没有加入S集合的点. 这里提出一个算法总体的思想,将所有的点按照一定的原则加入到S集就是解集.而这个解法就是重点了

数据结构之单源最短路径(迪杰斯特拉算法)-(九)

最开始接触最短路径是在数据结构中图的那个章节中.运用到实际中就是我在大三参加的一次美赛中,解决中国的水资源问题.所谓单源最短路径,就是一个起点到图中其他节点的最短路径,这是一个贪心算法. 迪杰斯特拉算法原理(百科): 按路径长度递增次序产生算法: 把顶点集合V分成两组: (1)S:已求出的顶点的集合(初始时只含有源点V0) (2)V-S=T:尚未确定的顶点集合 将T中顶点按递增的次序加入到S中,保证: (1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度 (2)每个顶

迪杰斯特拉算法介绍

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中顶点的路径是"起点s

图(最短路径算法————迪杰斯特拉算法和弗洛伊德算法).RP

文转:http://blog.csdn.net/zxq2574043697/article/details/9451887 一: 最短路径算法 1. 迪杰斯特拉算法 2. 弗洛伊德算法 二: 1. 迪杰斯特拉算法 求从源点到其余各点的最短路径 依最短路径的长度递增的次序求得各条路径 路径长度最短的最短路径的特点: 在这条路径上,必定只含一条弧,并且这条弧的权值最小. 下一条路径长度次短的最短路径的特点: 它只可能有两种情况:或是直接从源点到该点(只含一条弧):或者是从源点经过顶点v1,再到达该顶

十大基础实用算法之迪杰斯特拉算法、最小生成树和搜索算法

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中顶点的路径是"起点s

普里姆算法,克鲁斯卡尔算法,迪杰斯特拉算法,弗洛里德算法

做数据结构的课程设计顺便总结一下这四大算法,本人小白学生一枚, 如果总结的有什么错误,希望能够告知指正 普里姆算法如图所示prim 找出最短的边,再以这条边构成的整体去寻找与之相邻的边,直至连接所有顶点,生成最小生成树,时间复杂度为O(n2) 克鲁斯卡尔算法如图所示kruskal 克鲁斯卡尔算法,假设连通网N=(N,{E}),则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点 自成一个连通分量.在E中选择代价最小的边,若该边依附的定顶点落在T中不同的连通分量上,

数据结构图之三(最短路径--迪杰斯特拉算法——转载自i=i++

数据结构图之三(最短路径--迪杰斯特拉算法) [1]最短路径 最短路径?别乱想哈,其实就是字面意思,一个带边值的图中从某一个顶点到另外一个顶点的最短路径. 官方定义:对于内网图而言,最短路径是指两顶点之间经过的边上权值之和最小的路径. 并且我们称路径上的第一个顶点为源点,最后一个顶点为终点. 由于非内网图没有边上的权值,所谓的最短路径其实是指两顶点之间经过的边数最少的路径. 别废话了!整点实际的哈,你能很快计算出下图中由源点V0到终点V8的最短路径吗? [2]迪杰斯特拉算法 迪杰斯特拉算法是按路

hdu 2112 HDU Today &lt;迪杰斯特拉算法+map函数&gt;

HDU Today Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19697    Accepted Submission(s): 4635 Problem Description 经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强.这时候