1. 程式人生 > 其它 >Java實現最短路徑演算法(Dijkstra 演算法)

Java實現最短路徑演算法(Dijkstra 演算法)

參考:

https://zhuanlan.zhihu.com/p/129373740

《資料結構與演算法-python描述》作者:裘宗燕

以上是原圖,求V1到其餘所有節點的最短路徑。參考了裘宗燕教授的資料結構與演算法

並未完全理解其精髓,暫且記錄,後面再慢慢理解

@Data
@AllArgsConstructor
public class WeightGraph {
    private List<String> nodes;
    private List<WeightEdge<String, String, Integer>> edgeList;


    
public static void main(String[] args) { WeightGraph weightGraph = buildGraph(); Map<String, Path<String, Integer>> shortest = findShortest(weightGraph); for (Map.Entry<String, Path<String, Integer>> entry : shortest.entrySet()) { System.out.println(entry.getKey()
+ ":" + entry.getValue().getLen()); } } /** * 初始化圖結構 * * @return */ public static WeightGraph buildGraph() { List<String> node = Lists.newArrayList("v1", "v2", "v3", "v4", "v5", "v6"); List<WeightEdge<String, String, Integer>> edge = Lists.newArrayList(); edge.add(
new WeightEdge<>("v1", "v2", 10)); edge.add(new WeightEdge<>("v2", "v3", 7)); edge.add(new WeightEdge<>("v4", "v3", 4)); edge.add(new WeightEdge<>("v4", "v5", 7)); edge.add(new WeightEdge<>("v6", "v5", 1)); edge.add(new WeightEdge<>("v1", "v6", 3)); edge.add(new WeightEdge<>("v6", "v2", 2)); edge.add(new WeightEdge<>("v4", "v1", 3)); edge.add(new WeightEdge<>("v2", "v4", 5)); edge.add(new WeightEdge<>("v6", "v4", 6)); return new WeightGraph(node, edge); } public static Map<String, Path<String, Integer>> findShortest(WeightGraph weightGraph) { List<WeightEdge<String, String, Integer>> edgeList = weightGraph.getEdgeList(); List<String> nodes = weightGraph.getNodes(); //以路徑邊長做key的優先順序佇列 PriorityQueue<Triple<Integer, String, String>> queue = new PriorityQueue<>(Comparator.comparing(Triple::getLen)); //初始化佇列 //表示原點v1,經中間節點v1,到v1的距離是0 queue.add(new Triple<>(0, "v1", "v1")); //結果map Map<String, Path<String, Integer>> paths = new HashMap<>(); //paths初始為null,用於儲存最終結果 int size = nodes.size(); for (String node : nodes) { paths.put(node, null); } int count = 0; while (count < size && !queue.isEmpty()) { //長度、中介、終點 Triple<Integer, String, String> triple = queue.remove(); String end = triple.getEnd(); //如果end已經找到,則跳過本次迴圈 if (paths.get(end) != null) { continue; } //如果end還為找到最短路徑 Integer len = triple.getLen(); //因為從優先佇列頭部取出,因此<end,len>就是當前已知的最短路徑 //第一次執行("v1",new Path("v1",0)),v1經v1到v1的最短距離是0 paths.put(end, new Path<>(triple.getMiddle(), len)); //遍歷所有以新得到的最短路徑節點做start的邊,擴充套件可達的邊界 for (WeightEdge<String, String, Integer> edge : edgeList) { if (edge.getStart().equals(end)) { String newEnd = edge.getEnd(); Integer w = edge.getWeight(); //如果新目標還未確定最短路徑,則將end做中介,原end的len+weight作為新的len,並加入優先queue //優先佇列保證經過這輪迴圈,得到了最新的最短路徑節點 if (paths.get(newEnd) == null) { queue.add(new Triple<>(len + w, end, newEnd)); } } } count += 1; } return paths; } } /** * 帶權重的邊 * * @param <S> * @param <E> * @param <W> */ @Data @AllArgsConstructor @NoArgsConstructor class WeightEdge<S, E, W> { private S start; private E end; private W weight; } /** * 優先佇列元素三元組,主要用於獲取目標節點的最短路徑 * * @param <L> length * @param <M> 中介點 * @param <E> 目標點 */ @Data @AllArgsConstructor class Triple<L, M, E> { private L len; private M middle; private E end; } /** * paths的元素格式 * * @param <M> 中介點 * @param <L> 最終最短路徑 */ @Data @AllArgsConstructor class Path<M, L> { private M middle; private L len; }

輸出:

v6:3
v1:0
v2:5
v3:12
v4:9
v5:4