当前位置: 首页 > article >正文

两点间最短距离 - Dijkstra

一、汇总

算法场景说明参考
BFS

无权图的搜索

标准BFS默认搜索一条最短路径

改造后可以输出所有最短路径

https://blog.csdn.net/m0_37145844/article/details/144534202
DFS走迷宫主要利用回溯算法思想,不保证最短路径https://blog.csdn.net/m0_37145844/article/details/144534202
Dijkstra
带权图最短路径的经典解法主要利用贪心思想,其中在u打印路径时候包含递归,回溯等思想本篇讲解

二、Dijkstra 原理

借助java工具类:PriorityQueue 默认内部元素强制根据指定规则进行自然排序的的小顶堆,每次选择下层节点到起点开始算的最小权值的节点作为当前节点,进行向外的下一个层级的探索,最终让所有节点都保存了,此节点从开始节点的最小权重值及其最短路径的父节点。

三、Dijkstra 代码实现-Java版本

有必要讲解一下代码结构:

  1. 内部类的使用
    1. 体现更强的封装性,结构体仅供外部类使用,不对外暴露。
    2. 外部类可以直接调用内部类,简化代码。
    3. 内部类也可以直接使用外部类的成员变量,此例子中暂无体现。
  2. 优先级队列的使用
    1. 比较器的构造。
    2. 因为每次向外层探索时候,都会加入下一层到开始节点权重总和最小的节点,此数据结构强制进行排序,序列化为一个小顶堆。这也是提升此算法性能的关键设计。
    3. 默认为小顶堆。
    4. 距离Map和路径反向记录Map,都体现了算法设计的技巧。
    5. 尤其在打印路径时候,最终用递归思想。
package algo.backtrace.Dijkstra.weiwei;

import java.util.*;

public class Dijkstra {

    class Grap {

        // 带权重的无向图表示,邻接矩阵表示
        Map<Integer, List<Edag>> adjList;

        Grap() {
            adjList = new HashMap<>();
        }

        // 添加边
        public void addEdag(int start, int des, int weight) {
            adjList.putIfAbsent(start, new ArrayList<>());
            adjList.putIfAbsent(des, new ArrayList<>());
            adjList.get(start).add(new Edag(des, weight));
            adjList.get(des).add(new Edag(start, weight));
        }

        // 获取一个顶点的所有边
        public List<Edag> getEdags(int node) {
            return adjList.getOrDefault(node, new ArrayList<>());
        }

        // 获取所有顶点
        public Set<Integer> getAllNodes() {
            return adjList.keySet();
        }
    }

    // 描述边
    class Edag{
        int des;
        int weight;
        Edag(int des, int weight) {
            this.des = des;
            this.weight = weight;
        }
    }

    public Map<Integer, Integer> dijkstra(Grap grap, Integer start) {
        // 定义工具
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparing(a -> a[1]));
        Map<Integer, Integer> dist = new HashMap<>();
        Map<Integer, Integer> prev = new HashMap<>();

        // 初始化参数
        for (Integer node : grap.getAllNodes()) {
            dist.put(node, Integer.MAX_VALUE);
            prev.put(node, -1);
        }

        dist.put(start, 0);
        pq.offer(new int[]{start, 0});

        while (!pq.isEmpty()) {
            int[] poll = pq.poll();
            int currNode = poll[0];
            int currWeight = poll[1];

            if (currWeight > dist.get(currNode)) {
                continue;
            }

            for (Edag edag : grap.getEdags(currNode)) {
                int newDist = currWeight + edag.weight;
                if (newDist < dist.get(edag.des)) {
                    dist.put(edag.des, newDist);
                    prev.put(edag.des, currNode);
                    pq.offer(new int[]{edag.des, newDist});
                }
            }
        }

        System.out.println("dist:" + dist);
        System.out.println("prev:" + prev);

        return prev;
    }

    public void printTrace(Map<Integer, Integer> prevMap, int traget, List<Integer> trace) {
        if (prevMap.get(traget) == -1) {
            return;
        }

        traget = prevMap.get(traget);
        printTrace(prevMap, traget, trace);
        trace.add(traget);
    }

    public void main(String[] args) {
        Grap grap = new Grap();
        grap.addEdag(0,1,4);
        grap.addEdag(0,2,1);
        grap.addEdag(1,3,2);
        grap.addEdag(2,3,8);
        grap.addEdag(2,4,3);
        grap.addEdag(4,5,2);
        grap.addEdag(3,5,1);

        Dijkstra dijkstra = new Dijkstra();
        Map<Integer, Integer> prevMap = dijkstra.dijkstra(grap, 0);
        List<Integer> list = new ArrayList<>();
        dijkstra.printTrace(prevMap, 5, list);
        System.out.println(list);
    }
}


// 输出
// dist:{0=0, 1=4, 2=1, 3=6, 4=4, 5=6}
// prev:{0=-1, 1=0, 2=0, 3=1, 4=2, 5=4}
// [0, 2, 4] 瑕疵之处是traget 没有打印出,无伤大雅。


http://www.kler.cn/a/447158.html

相关文章:

  • 常用的缓存技术都有哪些
  • OpenHarmony 3.2 网卡获取ip地址缓慢分析
  • Spring Boot--06--整合Swagger
  • React:闭包陷阱产生和解决
  • Map.put 方法
  • Android Java Ubuntu系统如何编译出 libopencv_java4.so
  • 如何快速搭建K8s
  • es使用knn向量检索中numCandidates和k应该如何配比更合适
  • Intel-ECI之Codesys PLC + Ethercat 远端IO + Codesys IDE编程
  • Spring Cloud Sleuth 分布式链路追踪
  • 基于单片机的太阳能数据采集系统(论文+源码)
  • 深入探讨C++标准输入输出流:iostream
  • IDEA中使用Git
  • JWT令牌与微服务
  • 微服务核心概念介绍
  • 《网络对抗技术》Exp9 Web安全基础
  • 全面解析 Golang Gin 框架
  • 【自动化】Python SeleniumUtil 工具 开启开发者模式 自动安装油猴用户脚本等
  • VSCode:Markdown插件安装使用 -- 最简洁的VSCode中Markdown插件安装使用
  • PCB生产设备日志采集
  • 学习Cookie 基础
  • 24届FPGA秋招经验分享
  • 【批量生成WORD和PDF文件】根据表格内容和模板文件批量创建word文件,一次性生成多个word文档和批量创建PDF文件
  • Mybatis中使用MySql触发器报错:You have an error in your SQL syntax; ‘DELIMITER $$
  • 【DevOps工具篇】PM(Project Management)之Redmine
  • linux zip unzip 命令的使用