狄克斯特拉算法DijKstra Algorithm

廣度優先算法適用於計算有向無權圖計算最短路徑。狄克斯特拉算法是有向加權圖計算最小開銷的算法,不適用於負權邊的情況。

下面是代碼示例,起點是start,經過a點權重是6,b點的權重是2,a點到終點fin的權重是1。b點到a點的權重是3,到fin點的權重是5,現在計算從start到fin的最小權重路徑。

package com.teriste.algorithm;

import org.apache.commons.collections.MapUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DijKstraAlgorithm {

    //節點關係及權重
    public static Map<String,Map<String,Integer>> graph = new HashMap<>();

    //每個節點的開銷,從起點到該節點的開銷
    public static Map<String,Integer> cost = new HashMap<>();

    //每個節點的父節點
    public static Map<String,String> parent = new HashMap<>();

    //記錄處理過的節點避免重複處理
    //public static List<String> processed = new ArrayList<>();
    static {
        //起點
        Map<String,Integer> start = new HashMap<>();
        //起點到a點的權重
        start.put("a",6);
        //起點到b點的權重
        start.put("b",2);
        graph.put("start",start);
        //a點
        Map<String,Integer> a = new HashMap<>();
        //a到fin點的權重
        a.put("fin",1);
        graph.put("a",a);
        //b點
        Map<String,Integer> b = new HashMap<>();
        //b到a點的權重
        b.put("a",3);
        //b到fin點的權重
        b.put("fin",5);
        graph.put("b",b);
        //fin點是終點
        graph.put("fin",null);
        //-------------------------------
        cost.put("a",6);
        cost.put("b",2);
        //------------------------
        parent.put("a","start");
        parent.put("b","start");
        parent.put("fin",null);
    }

    //遍歷輸入節點的所有臨近節點,
    public void dijKstraCalc(String key){
        Map<String,Integer> start = graph.get(key);
        if (MapUtils.isEmpty(start)){
            return;
        }
        if (MapUtils.isNotEmpty(start)){
            //遍歷臨近節點
            for(Map.Entry<String,Integer> entry:start.entrySet()){
                if (entry.getValue()==null){
                    return;
                }
                /**
                 * 取出到該臨近節點的權重和cost記錄的到該臨近節點的權重比較,
                 * 取最小權重存入cost,
                 * 並記錄到該臨近節點的最小權重的節點記錄到parent散列表
                 */
                if (null==cost.get(entry.getKey())||entry.getValue()<cost.get(entry.getKey())){
                    cost.put(entry.getKey(),entry.getValue());
                    parent.put(entry.getKey(),key);
                }
                //遞歸遍歷該該節點的臨近節點的臨近節點直到最後一個節點結束
                dijKstraCalc(entry.getKey());
            }
        }
    }
}

測試:

package com.teriste.algorithm;

import com.alibaba.fastjson.JSON;
import org.junit.Test;

public class DijKstraAlgorithmTest {

    @Test
    public void dijKstraCalcTest(){
        DijKstraAlgorithm algorithm = new DijKstraAlgorithm();
        //輸入起點,開始計算
        algorithm.dijKstraCalc("start");
        //節點的父子關係
        System.out.println("parent:"+JSON.toJSONString(DijKstraAlgorithm.parent));
        //到該節點的權重
        System.out.println("cost"+JSON.toJSONString(DijKstraAlgorithm.cost));
    }
}

參考文獻:《算法圖解》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章