算法-狄克斯特拉算法

狄克斯特拉算法

注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!

一、简介

狄克斯特拉算法(Dijkstra )用于计算出不存在非负权重的情况下,起点到各个节点的最短距离

二、场景

  • 从A出发是否存在到达B的路径;
  • 从A出发到达B的最短路径(时间最少、或者路径最少等),事实上最后计算完成后,已经得到了A到各个节点的最短路径了;

三、实现思路

  1. 找出“最便宜”的节点,即可在最短时间内到达的节点。
  2. 更新该节点对应的邻居节点的开销。
  3. 重复这个过程,直到每个节点都这样做了。
  4. 计算最终路径。

四、java实现

在这里插入图片描述

public class Dijkstra {


    public static void main(String[] args){
        final HashMap<String,Integer> 广州 = new HashMap<String,Integer>(){
            {
                put("上海",1);
                put("北京",5);
                put("武汉",3);
            }
        };

        final HashMap<String,Integer> 上海 = new HashMap<String,Integer>(){
            {
                put("北京",4);
            }
        };
        final HashMap<String,Integer> 武汉 = new HashMap<String,Integer>(){
            {
                put("北京",1);
                put("南京",2);
            }
        };
        final HashMap<String,Integer> 成都 = new HashMap<String,Integer>(){
            {
                put("上海",7);
                put("北京",10);
            }
        };
        final HashMap<String,Integer> 深圳 = new HashMap<String,Integer>(){
            {
                put("上海",8);
            }
        };
        final HashMap<String,Integer> 南京 = new HashMap<String,Integer>(){
            {
                put("北京",3);
            }
        };
        HashMap<String,HashMap<String,Integer>> allMap = new HashMap<String,HashMap<String,Integer>>() {
            {
                put("广州",广州);
                put("上海",上海);
                put("武汉",武汉);
                put("成都",成都);
                put("深圳",深圳);
                put("南京",南京);
            }
        };


        Dijkstra dijkstra = new Dijkstra();
        dijkstra.handle("广州","北京",allMap);
    }

    /**
     * 计算起点到终点最优方式
     * 思路:先计算起点到相邻节点的最小,然后根据最小节点再计算其子节点,依次循环,最后得到最优的路线
     * @param startKey 起点节点
     * @param target 终点节点
     * @param all 所有数据
     */
    private void handle(String startKey,String target,HashMap<String,HashMap<String,Integer>> all) {
        //存放到各个节点所需要消耗的时间
        HashMap<String,Integer> costMap = new HashMap<String,Integer>();
        //到各个节点对应的父节点
        HashMap<String,String> parentMap = new HashMap<String,String>();
        //存放已处理过的节点key,已处理过的不重复处理
        HashSet<String> processed = new HashSet<String>();

        //首先获取开始节点相邻节点信息
        HashMap<String,Integer> start = all.get(startKey);

        //添加起点到各个相邻节点所需耗费的时间等信息
        for(String key:start.keySet()) {
            int cost = start.get(key);
            costMap.put(key, cost);
            parentMap.put(key,startKey);
        }


        //选择最"便宜"的节点,这边即耗费时间最低的
        String minCostKey = getMiniCostKey(costMap,processed);
        while( minCostKey!=null ) {
            System.out.println("处理节点:"+minCostKey);
            HashMap<String,Integer> nodeMap = all.get(minCostKey);
            if (nodeMap!=null) {
                //该节点没有子节点可以处理了,末端节点
                handleNode(minCostKey,nodeMap,costMap,parentMap);
            }
            //添加该节点到已处理结束的列表中
            processed.add(minCostKey);
            //再次获取下一个最便宜的节点
            minCostKey = getMiniCostKey(costMap,processed);
        }


        if(parentMap.containsKey(target)) {
            System.out.println("到目标节点:"+target+"  最低耗费:"+costMap.get(target));
            List<String> pathList = new ArrayList<String>();
            String parentKey = parentMap.get(target);
            while (parentKey!=null) {
                pathList.add(0, parentKey);
                parentKey = parentMap.get(parentKey);
            }
            pathList.add(target);
            String path="";
            for(String key:pathList) {
                path = path + key + " --> ";
            }
            System.out.println("路线为"+path);
        } else {
            System.out.println("不存在到达"+target+"的路径");
        }
    }



    /**
     * 计算耗费最小的节点信息
     * @param costs 需要计算的内容
     * @param processed 处理过节点的集合
     * @return
     */
    private String  getMiniCostKey(HashMap<String,Integer> costs, HashSet<String> processed) {
        int mini = Integer.MAX_VALUE;
        String miniKey = null;
        for(String key : costs.keySet()) {
            if(!processed.contains(key)) {
                int cost = costs.get(key);
                if(mini > cost) {
                    mini = cost;
                    miniKey = key;
                }
            }
        }
        return miniKey;
    }


    /**
     * 计算子节点的耗费
     * @param startKey 当前节点
     * @param nodeMap 当前节点子节点数据
     * @param costMap 起点节点下的数据
     * @param parentMap 起点到该节点的内容
     */
    private void handleNode(String startKey,HashMap<String,Integer> nodeMap,HashMap<String,Integer> costMap,HashMap<String,String> parentMap) {

        for (String key : nodeMap.keySet()) {
            //获取原本到父节点所需要花费的时间
            int hasCost = costMap.get(startKey);
            //获取父节点到子节点所需要花费的时间
            int cost = nodeMap.get(key);
            //计算从最初的起点到该节点所需花费的总时间
            cost = hasCost + cost;

            if (!costMap.containsKey(key)) {
                //如果原本并没有计算过其它节点到该节点的花费
                costMap.put(key, cost);
                parentMap.put(key, startKey);
            } else {
                //获取原本耗费的时间
                int oldCost = costMap.get(key);
                if (cost < oldCost) {
                    //新方案到该节点耗费的时间更少
                    //更新到达该节点的父节点和消费时间对应的散列表
                    costMap.put(key, cost);
                    parentMap.put(key, startKey);
                    System.out.println("更新节点:" + key + ",cost:" + oldCost + " --> " + cost);
                }
            }
        }
    }
}

五、小结

1、狄克斯特拉算法Dijkstra主要用于有权重的方向图中搜索出最短路径,但不适合于有负权重的情况,标志好已处理的节点避免进入死循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值