先上一张路径图
一共有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->
时间: 2024-10-12 02:27:48