先上一张路径图
一共有8个点,每个点之间的连线数字,表示这两个点之间的距离,如果两个点之间无直接连线,那么只能通过其它点到达。
Dijkstra算法,网上有逼格较高的定义,描述文字不是太通俗,且不管它。
下面就以求A到G的最短路径为例,谈一下具体的算法实现思路:
前提条件:定义一个close集合,分析过的点都放入此集合中,A为起点,首先放入集合。
1.以A为起点,首先寻找离A最近的相连的某个点(上图是C点)
2.找到这个C点后,循环C相连的所有点(其实B和D),重新计算A到B,A到D的临时最短距离(最初A到D不相连,AD之间距离值设为∞,用Integer.MAX_VALUE表示)并保存。注意此最短距离是临时的,后面路径没有完全搜索之前,可能存在更短的距离。分析过C点后,把C点放入close集合。
3.再次寻找离A最近的某个点(不在close集合中的点,即还没有分析过的点,AF=25,AB=13,AD=15,其实就是B点)
4.然后再以B点执行step2的动作,找到A距离B的所有子节点的临时最短距离,如此反复,直到close集合包括了所有点。
具体java代码如下:
/**
*
*/
package com.test.dijkstra;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
/**
* @author chaisson
* @since 2015-5-30 上午11:51:59
*
*/
public class Dijkstra {
List<Node> openList = new ArrayList<Node>();//未访问过
List<Node> closeList = new ArrayList<Node>();//已访问过
Node A = new Node("A");
Node B = new Node("B");
Node C = new Node("C");
Node D = new Node("D");
Node E = new Node("E");
Node F = new Node("F");
Node G = new Node("G");
Node H = new Node("H");
//初始化数据节点之间的关系
private void init(){
A.linkedNode.add(B);
A.linkedNode.add(C);
A.linkedNode.add(F);
A.setValue(B,14);
A.setValue(C,4);
A.setValue(F,25);
B.linkedNode.add(A);
B.linkedNode.add(C);
B.linkedNode.add(E);
B.setValue(A, 14);
B.setValue(C, 9);
B.setValue(E, 7);
C.linkedNode.add(A);
C.linkedNode.add(B);
C.linkedNode.add(D);
C.setValue(A, 4);
C.setValue(B, 9);
C.setValue(D, 11);
D.linkedNode.add(C);
D.linkedNode.add(E);
D.linkedNode.add(H);
D.setValue(C, 11);
D.setValue(E, 12);
D.setValue(H, 5);
E.linkedNode.add(B);
E.linkedNode.add(D);
E.linkedNode.add(F);
E.linkedNode.add(H);
E.setValue(B, 7);
E.setValue(D, 12);
E.setValue(F, 3);
E.setValue(H, 9);
F.linkedNode.add(A);
F.linkedNode.add(E);
F.linkedNode.add(G);
F.setValue(A, 25);
F.setValue(E, 3);
F.setValue(G, 8);
G.linkedNode.add(F);
G.linkedNode.add(H);
G.setValue(F, 8);
G.setValue(H, 17);
H.linkedNode.add(D);
H.linkedNode.add(E);
H.linkedNode.add(G);
H.setValue(D, 5);
H.setValue(E, 9);
H.setValue(G, 17);
openList.add(A);
openList.add(B);
openList.add(C);
openList.add(D);
openList.add(E);
openList.add(F);
openList.add(G);
openList.add(H);
}
//计算从start到end,走过的路径
public void calculate(Node start,Node end){
if(closeList.size() == openList.size()){
System.out.println(start.getName()+"->"+end.getName()+" min.length.length:"+start.getValue(end));
return;
}
Node childNode = getMinValueNode(start);//找到目前除已经分析过的节点之外的距离start节点最近的节点
start.getAllPassNodes(childNode).add(childNode);//记录扩展到当前最近节点所有经过的节点
if(childNode == end){
System.out.println(start.getName()+"->"+end.getName()+" min.length:"+start.getValue(end));
return;
}
//System.out.println("当前距离"+start.getName()+"最近节点为:"+childNode.getName());
for(Node ccNode : childNode.linkedNode){
if(closeList.contains(ccNode)){
continue;
}
/**
* start节点到距离其最近的一个节点的其中一个子节点的距离(假设有1个或多个子节点)
* 即start节点到子子节点的距离
* 重新计算一遍A(假设start就是A,下同)到所有点的距离,与原来的距离相比较
*/
int ccnodeValue = start.getValue(childNode)+childNode.getValue(ccNode);//超过最大值之后,会变成负数
if(Math.abs(ccnodeValue) < start.getValue(ccNode)){
start.setValue(ccNode,ccnodeValue);
System.out.println(start.getName()+"->"+ccNode.getName()+"的目前最短距离是:"+ccnodeValue);//这个最短距离只是暂时的,只要分析没有结束,最短距离可能进一步缩小
start.getAllPassNodes(ccNode).clear();//临时最短距离缩小,所经过路径也清除重新添加
start.getAllPassNodes(ccNode).addAll(start.getAllPassNodes(childNode));
start.getAllPassNodes(ccNode).add(ccNode);
}
}
closeList.add(childNode);
calculate(start,end);//重复计算A到所有点的最短距离之后,再取距离A最短的节点,对其进行子节点分析【往外面节点扩展分析】
}
//取跟入参节点距离最近的节点,如果有多个相同距离的节点,则随便取其中一个
private Node getMinValueNode(Node node){
Node retNode = null;
int minValue = Integer.MAX_VALUE;
for(Node n : node.getValueMap().keySet()){
if(closeList.contains(n)){
continue;
}
if(node.getValue(n) < minValue){
minValue = node.getValue(n);
retNode = n;
}
}
return retNode;
}
public static void main(String[] args) {
Dijkstra d = new Dijkstra();
d.init();
d.closeList.add(d.A);
d.calculate(d.A, d.G);
//打印路径
for(Node node : d.A.getAllPassNodes(d.G)){
System.out.print(node.getName()+"->");
}
}
}
class Node {
private String name;
//记录本Node所有相连的Node
public List<Node> linkedNode = new ArrayList<Node>();
//记录本Node与其它Node的最短距离
private Map<Node,Integer> valueMap = new HashMap<Node,Integer>();
//记录从本Node到其它Node之间最短距离时所有经过的节点,并保持前后顺序,其实与valueMap对应
private Map<Node,LinkedHashSet<Node>> orderSetMap = new HashMap<Node,LinkedHashSet<Node>>();
public Node(String name){
this.name = name;
}
public void setValue(Node node,Integer value){
valueMap.put(node, value);
}
//如果没有本节点到参数节点的取值,则默认最大值
public Integer getValue(Node node){
return valueMap.get(node) == null? Integer.MAX_VALUE : valueMap.get(node);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<Node, Integer> getValueMap() {
return valueMap;
}
//取本节点到参数节点经过的所有节点集合
public LinkedHashSet<Node> getAllPassNodes(Node node) {
if(orderSetMap.get(node) == null){
LinkedHashSet<Node> set = new LinkedHashSet<Node>();
set.add(this);
orderSetMap.put(node, set);
}
return orderSetMap.get(node);
}
}
main方法执行从A到G的计算,执行结果为:
A->B的目前最短距离是:13
A->D的目前最短距离是:15
A->E的目前最短距离是:20
A->H的目前最短距离是:20
A->G的目前最短距离是:37
A->F的目前最短距离是:23
A->G的目前最短距离是:31
A->G min.length:31
A->C->B->E->F->G->