最新更新了github。欢迎多评论+讨论,共同努力。
往后准备更新大数据和微服务的BLOG
由于项目需要计算两个地铁站之前最短距离及其线路流程。
引发使用迪杰斯特拉算法计算带权值两点之前最短距离。
网上资料多用的是C++写的算法,在这里用的是Java。实现的方法可以有很多,重要的是把原理理解后用清晰的代码实现。
这里参考了网上的资料:https://blog.csdn.net/wangchsh2008/article/details/46288967
发现类的职责不十分明确并且逻辑稍微混乱进行了改进。并且加入真实距离后会产生BUG
算法原理我相信搜索能搜出一大把,我提出较为重要的点并辅以代码展示
类职责划分
DataBuilder 数据初始化 (相邻点之间距离)(实际中根据情况用TXT或者数据库读取初始化数据)
Result 运行结果
Station 站点信息
private static HashMap<station> resultMap = new HashMap<>();//结果集
private static List<station> analysisList = new ArrayList<>();//分析过的站点
/**
* Station
*
* Description:
*
* Creation Time: 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 +
'}';
}
}
/**
* Result
*
* Description:
*
* Creation Time: 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 +
'}';
}
}
/**
* com.richstonedt.metro.app.DataBuilder
*
* Description:
*
* Creation Time: 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);
}
最短距离算法~~~ 算最短距离的时候用的。
当时项目是计算地铁最优乘坐方式。小项目,就不把拥挤和换线时间加入最优因素了哈。
算法很简单,但是很多时候遇到新东西,大多数是基于巨人的肩膀进行修修改改,所以当时也是看了那位朋友的代码,他把所有的距离都当做1进行距离计算,实际就是最短步数是一样的。思想不难,并且把相邻站点的真实距离算进去后感觉有某些BUG。代码结构有点混乱,因此进行了一些修改。
https://github.com/ithuhui/hui-core-algorithm-dijkstra
作者:HuHui
转载:欢迎一起讨论web和大数据问题,转载请注明作者和原文链接,感谢