文章目录
前言
最新更新了github。欢迎多评论+讨论,共同努力。
往后准备更新大数据和微服务的BLOG
由于项目需要计算两个地铁站之前最短距离及其线路流程。
引发使用迪杰斯特拉算法计算带权值两点之前最短距离。
网上资料多用的是C++写的算法,在这里用的是Java。实现的方法可以有很多,重要的是把原理理解后用清晰的代码实现。
这里参考了网上的资料:https://blog.csdn.net/wangchsh2008/article/details/46288967
发现类的职责不十分明确并且逻辑稍微混乱进行了改进。并且加入真实距离后会产生BUG
算法原理
算法原理我相信搜索能搜出一大把,我提出较为重要的点并辅以代码展示
- 寻找分析点的所有相邻点并记录权值
- 选取最短距离的邻点B
- 循环遍历所有
Core – Code
类职责划分
DataBuilder 数据初始化 (相邻点之间距离)(实际中根据情况用TXT或者数据库读取初始化数据)
Result 运行结果
Station 站点信息
注意
private static HashMap<station> resultMap = new HashMap<>();//结果集
private static List<station> analysisList = new ArrayList<>();//分析过的站点
- Class
/** * <b><code>Station</code></b> * <p/> * Description: * <p/> * <b>Creation Time:</b> 2018/7/19 16:40. * * @author huweihui * @since metrodev2 0.1.0 */
public class Station {
private String name;
private String line;
private List<Station> 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<Station> getLinkStations() {
return linkStations;
}
public void setLinkStations(List<Station> 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 (){
}
@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();
}
@Override
public String toString() {
return "Station{" +
"name='" + name + '\'' +
", line='" + line + '\'' +
", linkStations=" + linkStations +
'}';
}
}
/** * <b><code>Result</code></b> * <p/> * Description: * <p/> * <b>Creation Time:</b> 2018/7/24 14:56. * * @author huweihui * @since metrodev2 0.1.0 */
public class Result {
private Station star;
private Station end;
private Double distance = 0.0D;
private List<Station> 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<Station> getPassStations() {
return passStations;
}
public void setPassStations(List<Station> 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 +
'}';
}
}
/** * <b><code>com.richstonedt.metro.app.DataBuilder</code></b> * <p/> * Description: * <p/> * <b>Creation Time:</b> 2018/7/10 12:36. * * @author huweihui * @since metro-dev 0.1.0 */
public class DataBuilder {
public static List<Station> line1 = new ArrayList<Station>();
public static List<Station> line2 = new ArrayList<Station>();
public static List<Station> line3 = new ArrayList<Station>();
public static List<Station> line3N = new ArrayList<Station>();
public static List<Station> line4 = new ArrayList<Station>();
public static List<Station> line5 = new ArrayList<Station>();
public static List<Station> line6 = new ArrayList<Station>();
public static List<Station> line7 = new ArrayList<Station>();
public static List<Station> line8 = new ArrayList<Station>();
public static List<Station> line9 = new ArrayList<Station>();
public static List<Station> line13 = new ArrayList<Station>();
public static List<Station> line14 = new ArrayList<Station>();
public static List<Station> lineAPM = new ArrayList<Station>();//APM
public static List<Station> lineGF = new ArrayList<Station>();//广佛线
public static LinkedHashSet<List<Station>> lineSet = new LinkedHashSet<>();//所有线集合
public static int totalStaion = 0;//总的站点数量
private DataBuilder(){
}
public static void init (String lineStr,List<Station> line,String lineName){
}
private static void getLine(String lineStr,List<Station> line,String lineName){
String[] lineArr = lineStr.split(",");
for (String s : lineArr) {
line.add(new Station(s,lineName));
}
}
static {
String line1Str = "西朗,坑口,花地湾,芳村,黄沙,长寿路,陈家祠,西门口,公园前,农讲所,烈士陵园,东山口,杨箕,体育西路,体育中心,广州东站";
String line2Str = "广州南站,石壁,会江,南浦,洛溪,南洲,东晓南,江泰路,昌岗,江南西,市二宫,海珠广场,公园前,纪念堂,越秀公园,广州火车站,三元里,飞翔公园,白云公园,白云文化广场,萧岗,江夏,黄边,嘉禾望岗";
String line3Str = "番禺广场,市桥,汉溪长隆,大石,厦滘,沥滘,大塘,客村,广州塔,珠江新城,体育西路,石牌桥,岗顶,华师,五山,天河客运站";
String line3NStr = "体育西路,林和西,广州东站,燕塘,梅花园,京溪南方医院,同和,永泰,白云大道北,嘉禾望岗,龙归,人和,高增,机场南,机场北";
String line4Str = "南沙客运港,南横,塘坑,大涌,广隆,飞沙角,金洲,蕉门,黄阁,黄阁汽车城,庆盛,东涌,低涌,海傍,石碁,新造,大学城南,大学城北,官洲,万胜围,车陂南,车陂,黄村";
String line5Str = "滘口,坦尾,中山八,西场,西村,广州火车站,小北,淘金,区庄,动物园,杨箕,五羊邨,珠江新城,猎德,潭村,员村,科韵路,车陂南,东圃,三溪,鱼珠,大沙地,大沙东,文冲";
String line6Str = "浔峰岗,横沙,沙贝,河沙,坦尾,如意坊,黄沙,文化公园,一德路,海珠广场,北京路,团一大广场,团一大广场,东湖,东山口,区庄,黄花岗,沙河顶,天平架,燕塘,天河客运站,长湴,植物园,龙洞,柯木塱,高塘石,黄陂,金峰,暹岗,苏元,萝岗,香雪";
String line7Str = "广州南站,石壁,谢村,钟村,汉溪长隆,南村万博,员岗,板桥,大学城南";
String line8Str = "凤凰新村,沙园,宝岗大道,昌岗,晓港,中大,鹭江,客村,赤岗,磨碟沙,新港东,琶洲,万胜围";
String line9Str = "飞鹅岭,花都汽车城,广州北站,花城路,花果山公园,花都广场,马鞍山公园,莲塘,清布,清塘,高增";
String line13Str = "鱼珠,裕丰围,双岗,南海神庙,夏园,南岗,沙村,白江,新塘,官湖,新沙";
String line14Str = "新和,红卫,新南,枫下,知识城,何棠下,旺村,汤村,镇龙北,镇龙";
String lineAPMStr = "广州塔,海心沙,大剧院,花城大道,妇儿中心,黄埔大道,天河南,体育中心南,林和西";
String lineGFStr = "新城东,东平,世纪莲,澜石,魁奇路,季华园,同济路,祖庙,普君北路,朝安,桂城,南桂路,礌岗,千灯湖,金融高新区,龙溪,菊树,西朗,鹤洞,沙涌,沙园,燕岗";
getLine(line1Str,line1,"line1");
getLine(line2Str,line2,"line2");
getLine(line3Str,line3,"line3");
getLine(line3NStr,line3N,"line3N");
getLine(line4Str,line4,"line4");
getLine(line5Str,line5,"line5");
getLine(line6Str,line6,"line6");
getLine(line7Str,line7,"line7");
getLine(line8Str,line8,"line8");
getLine(line9Str,line9,"line9");
getLine(line13Str,line13,"line13");
getLine(line14Str,line14,"line14");
getLine(lineAPMStr,lineAPM,"lineAPM");
getLine(lineGFStr,lineGF,"lineGF");
lineSet.add(line1);
lineSet.add(line2);
lineSet.add(line3);
lineSet.add(line3N);
lineSet.add(line4);
lineSet.add(line5);
lineSet.add(line6);
lineSet.add(line7);
lineSet.add(line8);
lineSet.add(line9);
lineSet.add(line13);
lineSet.add(line14);
lineSet.add(lineAPM);
lineSet.add(lineGF);
totalStaion = line1.size() + line2.size() + line3.size() + line4.size() + line5.size() + line6.size()
+ line7.size()+line8.size()+line9.size()+line13.size()+line14.size()+lineAPM.size()+lineGF.size();
System.out.println("总的站点数量:" + totalStaion);
}
}
算法
对应上面算法最关键的三点
- 找所有相邻点
private static List<Station> getLinkStations(Station station) { List<Station> linkedStaions = new ArrayList<Station>(); for (List<Station> line : SZDataBuilder.lineSet) { for (int i = 0; i < line.size() ; i++) { 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<Station> 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 Result calculate(Station star, Station end) { if (!analysisList.contains(star)) { analysisList.add(star); } if (star.equals(end)){ Result result = new Result(); result.setDistance(0.0D); result.setEnd(star); result.setStar(star); resultMap.put(star, result); return resultMap.get(star); } if (resultMap.isEmpty()) { List<Station> linkStations = getLinkStations(star); for (Station station : linkStations) { 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){ Result result = new Result(); result.setDistance(0.0D); result.setStar(star); result.setEnd(end); return resultMap.put(end, result); } if (parent.equals(end)) { return resultMap.get(parent); } List<Station> childLinkStations = getLinkStations(parent); for (Station child : childLinkStations) { if (analysisList.contains(child)) { continue; } String key = parent.getName() + ":" + child.getName(); Double distance = DistanceBuilder.getDistance(key); if( parent.getName().equals(child.getName())){ distance = 0.0D; } Double parentDistance = resultMap.get(parent).getDistance(); distance = doubleAdd(distance, parentDistance); List<Station> parentPassStations = resultMap.get(parent).getPassStations(); Result childResult = resultMap.get(child); if (childResult!=null){ if (childResult.getDistance() > distance) { childResult.setDistance(distance); childResult.getPassStations().clear(); childResult.getPassStations().addAll(parentPassStations); childResult.getPassStations().add(child); } }else { 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); }
应用场景
最短距离算法~~~ 算最短距离的时候用的。
当时项目是计算地铁最优乘坐方式。小项目,就不把拥挤和换线时间加入最优因素了哈。
github
https://github.com/ithuhui/hui-core-algorithm-dijkstra
总结
算法很简单,但是很多时候遇到新东西,大多数是基于巨人的肩膀进行修修改改,所以当时也是看了那位朋友的代码,他把所有的距离都当做1进行距离计算,实际就是最短步数是一样的。思想不难,并且把相邻站点的真实距离算进去后感觉有某些BUG。代码结构有点混乱,因此进行了一些修改。
转载请标明出处 感谢~
作者
作者:HuHui
转载:欢迎一起讨论web和大数据问题,转载请注明作者和原文链接,感谢