17.6:迪瑞克斯啦算法

news2024/11/24 21:02:05

迪瑞克斯啦算法

这个算法研究的是:有向的,没有负权重,可以有环的图。

在这里插入图片描述

这个算法主要研究的是:给出的节点到这张图的其他节点的最短路径是多少。用一个表表示出来。

在这里插入图片描述

思路:

如下图所示,我们想要求出a节点到其他节点的最小路径分别是多少。

刚开始a可以直接到b,c,d点,不能到e点,所以表里记录着:(d,2) ,(c,6) ,(b,1) ,(e,无穷)

从里面选一个最小的,选出b来,现在,a到c的距离可以是3,a到e的距离可以是7,表里的数据刷新一下。

注意此时**(b,1)就被锁定了,a到b的最短距离就是1**,往后循环此操作,直至剩下所有节点都被锁定。

锁定这个地方是最精妙的。解释 —> : 在刚开始的时候,a到b的距离是1,a到c的距离是6,a到d的距离是2,a到e的距离是正无穷。最小的就是a到b的距离。此时就把a到b的最小距离定为1.,原因是:我之所以从表中每次都挑选最小的距离节点是因为我想找找到其他节点的还有没有最短的路径。而之所以选出最小的距离节点之后,就将这个键值对锁定是因为从a到这个节点一定是最小的,因为其他的距离都比他大,加之没有负权重,所以不可能有比他更小的了。

使用到的容器:

map:存放表中数据。

堆:筛选最小距离节点。//发现堆结构还不行,因为表中的数据是会刷新的,而堆结构不会自动更改结构,所以必须是加强堆才可以。

在这里插入图片描述

package algorithmbasic.class17;

import java.util.HashMap;


public class Dijkstra {
    //从head出发,所有head能到达的节点,生成到达每个节点的最小路径记录并返回
    public static HashMap<Node, Integer> dijkstra(Node head, int size) {
        //result记录最终要返回的结果。
        HashMap<Node, Integer> result = new HashMap<>();
        //创建好我的加强堆
        HeapGreater heapGreater = new HeapGreater(size);
        //遍历head节点的直接连接节点。
        for (Edge edge : head.edges) {
            heapGreater.addOrUpdateOrIgnore(edge.to, edge.weight);
        }
        while (!heapGreater.isEmpty()) {
            Record record = heapGreater.poll();
            result.put(record.node, record.distance);
            for (Edge edge : record.node.edges) {
                heapGreater.addOrUpdateOrIgnore(edge.to, edge.weight + record.distance);
            }
        }
        return result;
    }

    /**
     * Record内部类
     * 之所以创建这个内部类是因为:我想将节点与权重当作一个整体,通过加强堆的排序之后弹出的是一个整体,这样方便
     * 当然使用hashmap也可以。
     */

    public static class Record {
        public Node node;
        public int distance;

        public Record(Node node, int distance) {
            this.node = node;
            this.distance = distance;
        }
    }

    public static class HeapGreater {
        /**
         * 属性
         */
        Node[] nodes;
        //记录node所对应的位置。
        //如果这个node被弹出了,heapIndexMap中这个节点所对应的位置就定为 -1.原因是:便于我们判断这个节点来过。
        //之所以必须判断这个节点来过是因为,如果后面的某个节点的直接连接节点还是这个节点,如果没有这个判断,这个节点还会再一次的进入堆中
        //导致最终返回的map中正确的值被覆盖。
        HashMap<Node, Integer> heapIndexMap;
        //记录剩余节点的a到Node所对应的最小距离
        HashMap<Node, Integer> distanceMap;
        int usedSize;

        /**
         * 构造器
         */
        public HeapGreater(int size) {
            nodes = new Node[size];
            heapIndexMap = new HashMap<>();
            distanceMap = new HashMap<>();
            usedSize = 0;
        }

        /**
         * addOrUpdateOrIgnore方法
         * 传进来的是一个节点,以及a到该节点的距离。
         * 对于这个节点只会出现三种操作,要么这个节点已经被处理过了,那就不用管直接跳过,
         * 要么这个节点从来没有进来过,那就放入堆中,
         * 要么这个节点的a到该节点的距离比堆中记录的要小,那就更新堆中的记录。
         */
        public void addOrUpdateOrIgnore(Node node, int weight) {
            //传进来的节点要不就放入加强堆中,要不就更新加强堆中的值,要么就被忽略。
            //如果这个节点在堆中,看看a到该节点的距离比堆中记录的要小,那就更新堆中的记录。
            if (inHeap(node)) {
                distanceMap.put(node, Math.min(weight, distanceMap.get(node)));
                //因为堆中的记录只会变的更小,所以只会向上调整。
                insertHeapify(heapIndexMap.get(node));
            }
            //这个节点从来没有进来过。
            //那就加入这个节点。
            if (!isEntered(node)) {
                nodes[usedSize] = node;
                distanceMap.put(node, weight);
                heapIndexMap.put(node, usedSize);
                insertHeapify(usedSize++);
            }
        }

        /**
         * 向上调整
         */
        private void insertHeapify(int index) {
            int father = (index - 1) / 2;
            while (distanceMap.get(nodes[father]) < distanceMap.get(nodes[index])) {
                swap(nodes, father, index);
                index = father;
                father = (index - 1) / 2;
            }
        }

        public void swap(Node[] nodes, int fatehr, int index) {
            heapIndexMap.put(nodes[fatehr], index);
            heapIndexMap.put(nodes[index], fatehr);
            Node temp = nodes[fatehr];
            nodes[fatehr] = nodes[index];
            nodes[index] = temp;
        }

        /**
         * 向下调整
         */
        private void heapify(int index, int size) {
            int lc = index * 2 + 1;
            while (lc < size) {
                int smallChild = lc + 1 < size ? (distanceMap.get(nodes[lc]) < distanceMap.get(nodes[lc + 1]) ? lc : lc + 1) : (lc);
                if (distanceMap.get(index) > distanceMap.get(smallChild)) {
                    swap(nodes, index, smallChild);
                    index = smallChild;
                    lc = index * 2 + 1;
                } else {
                    break;
                }
            }
        }

        /**
         * 判断当前节点是否进来过。
         */
        private boolean isEntered(Node node) {
            return heapIndexMap.containsKey(node);
        }

        /**
         * 判断当前节点是否在堆上
         */
        private boolean inHeap(Node node) {
            return isEntered(node) && heapIndexMap.get(node) != -1;
        }

        /**
         * poll()方法
         */
        public Record poll() {
            Record record = new Record(nodes[0], distanceMap.get(nodes[0]));
            distanceMap.remove(nodes[0]);
            heapIndexMap.put(nodes[0], -1);
            swap(nodes, 0, usedSize - 1);
            heapify(0, --usedSize);
            return record;
        }

        /**
         * isEmpty()方法
         */
        public boolean isEmpty() {
            return this.usedSize == 0;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

建立时间、保持时间和亚稳态

目录 一、建立时间和保持时间 二、亚稳态 三、避免亚稳态策略 四、多级寄存器阻断亚稳态传播 一、建立时间和保持时间 如图1所示&#xff0c;建立时间&#xff08;set up time&#xff09;是指在触发器的时钟信号上升沿到来以前&#xff0c;数据稳定不变的时间&#xff0c;…

【Apache Pinot】探究 Pinot 中存储模型的设计逻辑和 Segment 详解

背景 上一篇文章中&#xff0c;笔者简单介绍了一下分布式数据库 Pinot 的核心组件&#xff0c;本文主要针对其中的存储模型会做部分讲解。 如果你对读写磁盘有不错的基础的话&#xff0c;看起来会更轻松一些&#xff0c;如果没有也没关系&#xff0c;我会简单讲解一下这么设计…

使用STM32进行串口实验(非中断+中断)

关于串口相关的基本知识可以看这篇文章https://blog.csdn.net/weixin_62599865/article/details/129963991?spm1001.2014.3001.5501 一.使用非中断的方式进行串口通信 串口发送/接收函数&#xff1a; HAL_UART_Transmit(); 串口发送数据&#xff0c;使用超时管理机制 HAL_…

2023最新版本Activiti7系列-Activiti7概述和入门案例

一、Activiti7概述 官网地址&#xff1a;https://www.activiti.org/ Activiti由Alfresco软件开发&#xff0c;目前最高版本Activiti 7。是BPMN的一个基于java的软件实现&#xff0c;不过Activiti 不仅仅包括BPMN&#xff0c;还有DMN决策表和CMMN Case管理引擎&#xff0c;并且有…

【前端 - HTML】第 1 课 - HTML 初体验

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 。 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、HTML 概念 2.1、HTML 定义 2.2、标签语法 3、HTML 基本骨架 4、标签的关系 5、注释 6、总结 1、缘起 最近在学习微信小程…

Apache Doris 冷热分层技术如何实现存储成本降低 70%?

在数据分析的实际场景中&#xff0c;冷热数据往往面临着不同的查询频次及响应速度要求。例如在电商订单场景中&#xff0c;用户经常访问近 6 个月的订单&#xff0c;时间较久远的订单访问次数非常少&#xff1b;在行为分析场景中&#xff0c;需支持近期流量数据的高频查询且时效…

C++ 使用一维数组和二维数组给 std::vector<cv::Point2d> 赋值的方法

文章目录 1. 一维数组给 vector 赋值的方法2. 一维 Point2d 数组给 vector<cv::Point2d> 赋值3. 二维 double 数组给 vector<cv::Point2d> 赋值 1. 一维数组给 vector 赋值的方法 &#xff08;1&#xff09;最简单的赋值方法是for循环遍历赋值&#xff0c;此处略过…

Python展开嵌套列表的五种方法

一、问题的提出 微信群中有人问&#xff0c;如何把以下内容转换成一个列表&#xff1a; 转换后&#xff1a; "[["007674","工银产业升级股票A","GYCYSJGPA","1.3574"],["007675","工银产业升级股票C",&qu…

d2l学习_第二章预备知识

x.1 Data Manipulation 数据操作。在Pytorch中常用的数据操作如下&#xff1a; 对于张量&#xff0c;即torch.Tensor类型的数据&#xff0c;你的任何操作都要把他想象成一个指针&#xff0c;因为等于运算符ab&#xff0c;会将b的张量内存地址赋值给a。 torch.Tensor类型的基…

day02-JavaScript-Vue

1 JavaScript html完成了架子&#xff0c;css做了美化&#xff0c;但是网页是死的&#xff0c;我们需要给他注入灵魂&#xff0c;所以接下来我们需要学习JavaScript&#xff0c;这门语言会让我们的页面能够和用户进行交互。 1.5.1.3 JSON对象 自定义对象 在 JavaScript 中自…

linux(信号发送后)

目录&#xff1a; 1.引入什么是合适的时候 2.内核态和用户态 3.信号的处理 4.sigaction函数 -------------------------------------------------------------------------------------------------------------------------------- 1.引入什么是合适的时候 2.信号什么时候被处…

你真的会PPT配色吗?来看看这篇吧,瞬间让你的PPT高大上起来

本文档使用技巧如下截图 在色彩里使用其它填充颜色 选取这个“吸管” 用于吸别人的颜色 我曾经为了出一个“惊艳”的PPT,光吸管用了不下150次。 好的艺术家复制,伟大的艺术家偷窃!--毕加索 下面就给出几大常用配色 各位在使用时注意看这些“色卡”的规律,那就是反差色…

安卓系统浏览器开发

预置某个浏览器为系统默认的浏览器 描述: 当系统存在多个浏览器时&#xff0c;如何预置某个浏览器为系统默认的浏览器&#xff1f; 方法: 1.在PackageManagerService.java中的构造函数结尾添加&#xff1a;setDefaultBrowser(); 2.setDefaultBrowser()的具体实现&#xff…

TDengine 合作伙伴 +1,这次是「DaoCloud道客」

随着我国数字经济持续快速发展&#xff0c;各行各业都在积极拥抱云技术&#xff0c;上云成为企业加快数字化转型步伐的关键一步。在此过程中&#xff0c;越来越多的企业开始意识到云原生技术的重要性&#xff0c;利用云原生更快地开发和部署应用程序&#xff0c;提高应用程序的…

智慧信访大数据挖掘平台解决方案

TipDM数据挖掘建模平台由泰迪自主研发&#xff0c;面向大数据挖掘项目的工具。平台使用JAVA语言开发&#xff0c;采用B/S结构&#xff0c;用户不需要下载客户端&#xff0c;可通过浏览器进行访问。平台提供了基于Python、R以及Hadoop/Spark分布式引擎的大数据分析功能。平台支持…

人民大学加拿大女王大学金融硕士——为什么这么多人选金融行业呢

又是一年毕业季&#xff0c;越来越多的新人涌入职场&#xff0c;金融行业依然是择业人们的香饽饽。为什么大家会选金融行业呢&#xff1f;金融行业是一个充满挑战但也充满魅力的行业。在这个快节奏的行业中&#xff0c;人们不断地面对着机遇和挑战&#xff0c;而这个行业也为那…

TLD5097EL-ASEMI代理英飞LED驱动TLD5097EL

编辑&#xff1a;ll TLD5097EL-ASEMI代理英飞LED驱动TLD5097EL 型号&#xff1a;TLD5097EL 品牌&#xff1a;Infineon(英飞凌) 封装&#xff1a;SSOP-14-EP-150mil 类型&#xff1a;LED驱动、汽车芯片 TLD5097EL特性 输入电压范围宽&#xff0c;从4.5 V到45 V 极低关断…

【FATE联邦学习】FATE 自定义Trainer

背景 自己定义了模型后&#xff0c;需要自行定义训练方式。 这里文档给了方法&#xff0c;但是大部分还是需要自己看源码摸索。 https://fate.readthedocs.io/en/latest/tutorial/pipeline/nn_tutorial/Homo-NN-Customize-Trainer/https://fate.readthedocs.io/en/latest/tu…

如何按需下载和安装Win10补丁

如何按需下载和安装Win10补丁 一般我们都是通过系统自带的Windows更新来直接安装补丁&#xff0c;这种方式虽然方便&#xff0c;但是耗时久&#xff0c;而且更新体量也大&#xff0c;会占用很多空间&#xff0c;其实我们完全可以按需下载和安装&#xff0c;下面就给大家介绍方法…

FPGA量子类比机制-FPQA,将在量子运算设计中引发一场新的革命

1980年代现场可程式化逻辑门阵列(FPGA)的出现彻底改变了电子设计。大约40年后&#xff0c;现场可程式化量子位元阵列(FPQA)可望在量子运算电路设计中引发一场类似的革命。 1980年代现场可程式化逻辑闸阵列(FPGA)的出现彻底改变了电子设计。FPGA允许设计人员创建适合特定应用的…