標籤:
先上一張路徑圖
一共有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所有相連的Nodepublic 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->
Dijkstra演算法java現實