数据结构---二叉堆

news2024/11/27 14:34:36

二叉堆

  • 二叉堆自我调整
    • 插入节点(上浮)
    • 删除节点(下沉)
    • 构建二叉堆(所有非叶子节点依次“下沉”)

二叉堆本质上是一种完全二叉树,它分为两个类型。

  1. 最大堆
  2. 最小堆
    最大堆的任何一个父节点的值,都大于或等于它左、右孩子\节点的值
    在这里插入图片描述
    最小堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值。
    在这里插入图片描述

二叉堆的根节点叫作堆顶
最大堆和最小堆的特点决定了:最大堆的堆顶是整个堆中的最大元素;最小堆的堆顶是整个堆中的最小元素。

二叉堆自我调整

堆的自我调整,就是把一个不符合堆性质的完全二叉树,调整成一个堆。

  1. 插入节点
  2. 删除节点
  3. 构建二叉堆

插入节点(上浮)

当二叉堆插入节点时,插入位置是完全二叉树的最后一个位置。
这时,新节点的父节点5比0大,显然不符合最小堆的性质。于是让新节点“上浮”,和父节点交换位置。
继续用节点0和父节点3做比较,因为0小于3,则让新节点继续“上浮”。
继续比较,最终新节点0“上浮”到了堆顶位置。

    /**
     * 插入元素的位置是数组的最后一个位置。
     * 插入(上浮)
     * @param array
     */
    public static void upAdjust(int[] array){
        //插入位置都是在数组的末尾,所以array.length-1就是当前插入位置的数组下标.
        int childIndex = array.length-1;
        //左孩子的父节点下标
        int parentIndex = (childIndex-1)/2;
        //temp 保存插入的叶子节点值,用于最后的赋值
        int temp = array[childIndex];
        while (childIndex>0&&temp<array[parentIndex]){
            //无须真正交换,单向赋值即可
            array[childIndex] = array[parentIndex];
            //在和上一个父节点比较。。。
            childIndex = parentIndex;
            //不管上一个节点是左孩子还是右孩子,通过(parentIndex-1)/2都可找到父节点的父节点。。
            parentIndex = (parentIndex-1)/2;
        }
        //找到childIndex,把值temp插入
        array[childIndex] = temp;
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

删除节点(下沉)

所删除的是处于堆顶的节点。
把堆的最后一个节点10临时补到原本堆顶的位置。

 /**
     * 删除(下沉)
     * @param array    待调整的堆
     * @param parentIndex   要“下沉”的父节点
     * @param length   堆的有效大小
     */
    public static void downAdjust(int[] array,int parentIndex,int length){
        //temp 保存需要下沉的父节点值,用于最后的赋值
        int temp = array[parentIndex];
        //找到父节点的左孩子
        int childIndex = 2*parentIndex+1;
        while (childIndex<length){
            // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子(需要和左右孩子中最小的交换)
            if(childIndex+1<length&&array[childIndex+1]<array[childIndex]){
                    //定位右孩子
                    childIndex++;
            }
            // 如果父节点小于的任何一个孩子的值,则直接跳出(没有交换的必要了)
            if(temp<=array[childIndex]){
                break;
            }
            无须真正交换,单向赋值即可
            array[parentIndex] = array[childIndex];
            //在基于现在往下找。。
            parentIndex = childIndex;
            childIndex = 2*childIndex+1;
        }
        //最后在将下沉的父节点赋值进去
        array[parentIndex] = temp;
    }

在这里插入图片描述
在这里插入图片描述
让暂处堆顶位置的节点10和它的左、右孩子进行比较,如果左、右孩子节点中最小的一个(显然是节点2)比节点10小,那么让节点10“下沉”。
在这里插入图片描述
在这里插入图片描述

构建二叉堆(所有非叶子节点依次“下沉”)

构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质就是让所有非叶子节点依次“下沉”

    public static void buildHeap(int[] array){
        // 从最后一个非叶子节点(array.length-2)/2)开始,依次做“下沉”调整
        for (int i = (array.length-2)/2;i>=0;i--){
            downAdjust(array,i,array.length);
        }
    }

其中:

/**
     * 删除(下沉)
     * @param array    待调整的堆
     * @param parentIndex   要“下沉”的父节点
     * @param length   堆的有效大小
     */
    public static void downAdjust(int[] array,int parentIndex,int length){
        //temp 保存需要下沉的父节点值,用于最后的赋值
        int temp = array[parentIndex];
        //找到父节点的左孩子
        int childIndex = 2*parentIndex+1;
        while (childIndex<length){
            // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子(需要和左右孩子中最小的交换)
            if(childIndex+1<length&&array[childIndex+1]<array[childIndex]){
                    //定位右孩子
                    childIndex++;
            }
            // 如果父节点小于的任何一个孩子的值,则直接跳出(没有交换的必要了)
            if(temp<=array[childIndex]){
                break;
            }
            无须真正交换,单向赋值即可
            array[parentIndex] = array[childIndex];
            //在基于现在往下找。。
            parentIndex = childIndex;
            childIndex = 2*childIndex+1;
        }
        //最后在将下沉的父节点赋值进去
        array[parentIndex] = temp;
    }

在这里插入图片描述
在这里插入图片描述
从最后一个非叶子节点开始,也就是从节点10开始。
接下来轮到节点3,
在这里插入图片描述

然后轮到节点1,
接下来轮到节点7,
在这里插入图片描述
在这里插入图片描述
经过上述几轮比较和“下沉”操作,最终每一节点都小于它的左、右孩子节点,一个无序的完全二叉树就被构建成了一个最小堆。

总结:

堆的插入操作是单一节点的“上浮”,堆的删除操作是单一节点的“下沉”,这两个操作的平均交换次数都是堆高度的一半,所以时间复杂度是O(logn)。
至于堆的构建,需要所有非叶子节点依次“下沉”,所以我觉得时间复杂度是O(n)。

二叉堆虽然是一个完全二叉树,但它的存储方式并不是链式存储,而是顺序存储。换句话说,二叉堆的所有节点都存储在数组中。

在这里插入图片描述

类似于层序遍历。。。。。

父节点的下标是parent,那么它的左孩子下标就是 2×parent+1;右孩子下标就是2×parent+2。

在父节点和孩子节点做连续交换时,并不一定要
真的交换,只需要先把交换一方的值存入temp变量,做单向覆盖,循环结束后,再
把temp的值存入交换后的最终位置即可。

二叉堆是实现堆排序及优先队列的基础

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

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

相关文章

【实测】windows安装部署go实录(超详细)

之前我的课程中&#xff0c;关于go语言的安装是主要展示了mac的&#xff0c;windows的就一笔带过了。 结果被我说着了&#xff08;可能在第一步直接被劝退&#xff09;&#xff0c;好多用windows的小伙伴部署go语言环境各种问题各种坑&#xff0c;网上教程看了个一知半解。没办…

网络工程毕业设计 SSM药品管理系统(源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.2.1 添加信息流程3.2.2 操作流程3.2.3删除信息流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成…

域0day-(CVE-2022-33679)容易利用吗

前言 最近twitter上关于CVE应该CVE-2022-33679比较火了&#xff0c;但是资料也是比较少&#xff0c;下面来唠唠吧。 kerberos认证原理 先了解几个概念 认证服务(Authentication server&#xff09;:简称AS,认证客户端身份提供认证服务。 域控服务器(Domain Control&#x…

ubuntu 安装 MySql 【亲测有效】

目录 一&#xff1a;ubuntu安装mysql 二&#xff1a;mysql 中文乱码 解决 三&#xff1a;Mysql数据库 远程连接授权 四&#xff1a;卸载Mysql并重新安装 五&#xff1a;Mysql 远程连接测试 一&#xff1a;ubuntu安装mysql 首先来到opt(安装)目录下&#xff0c;开启终端&am…

压缩包密码如何解除?

压缩包设置了加密&#xff0c;需要输入压缩包密码才能够顺利解压文件出来。但是有些时候&#xff0c;一些文件只需要一段时间内要加密&#xff0c;之后文件不需要加密了&#xff0c;每次解压文件的时候还是需要输入压缩包密码才行&#xff0c;就很麻烦&#xff0c;那么RAR压缩包…

分布式状态机共识协议 Copilot

目录 前言 定义 slowdown 为什么现有的共识协议无法容忍 slowdown Copilot 如何处理 slowdown 设计 模型 排序 Client 同时发送指令至 pilot 与 copilot Pilot 提议指令与其初始依赖 节点回复 FastAccept Pilot 尝试通过 fast path 来 commit 该指令 Pilot 在 Acc…

C++11标准模板(STL)- 算法(std::min)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 返回各给定值中的较小者 …

基于Java实现(PC)职员工作量管理系统【100010042】

工作量统计系统 一、概述 ​ 在本次专业课实践中我选取到的题目为员工工作量统计系统。该系统分为三个模块&#xff0c;一是实现员工的登录&#xff0c;二是进入到员工的个人界面&#xff0c;并显示&#xff0c;输出员工的个人信息&#xff0c;同时还可以进行输入。第三个模块…

div对角线来回浮动显示

animation-timing-function linear 动画从头到尾的速度是相同的。 ease 默认。动画以低速开始&#xff0c;然后加快&#xff0c;在结束前变慢 ease-in 动画以低速开始 ease-out 动画以低速结束 ease-in-out 动画以低速开始和结束 steps(int,start|end) 指定了时间函数中的间隔…

公司对外投资和担保

一、公司对外投资和担保规范 公司对外投资和外他人提供担保&#xff0c;需承担相应的责任 公司可以对外投资和提供担保 二、公司提供担保的方式 保证 抵押 质押 三、公司提供担保的规定 公司对外承担的规定 公司向其他企业投资或者为他人提供担保&#xff0c;依照公司章程的规…

seata-server-1.4.2的环境搭建

修改seata-server-1.4.2/conf目录下的file.conf和registry.conf file.conf 将store下mode修改为db&#xff0c;找到db模块修改 driverClassName、url、user、password mysql 5.使用 driverClassName "com.mysql.jdbc.Driver" mysql 8 使用 driverClassName "…

Docker入门之docker-compose

一&#xff0c;Docker-compose简介 1&#xff0c;Docker-compose简介 Docker-Compose项目是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。 Docker-Compose将所管理的容器分为三层&#xff0c;分别是工程&#xff08;project&#xff09;&#xff0c…

【MATLAB教程案例62】使用matlab实现基于PointNet++网络的点云数据分类仿真分析

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 1.软件版本 2.PointNet++网络理论概述

通过java代码实现ES中的常用搜索

目录 测试环境准备 在指定索引下搜索全部&#xff08;可以指定字段&#xff09; 通过ids进行搜索 对搜索结果进行分页 match分词搜索 不分词模糊搜索&#xff1a;wildcardQuery与matchPhraseQuery term 搜索&#xff08;精确匹配&#xff09; multi_match搜索 bool搜索…

23年如何准备考PMP?这4点建议你得看

23年的PMP考试还有3个多月&#xff0c;现在开始备考&#xff0c;再合适不过&#xff0c;我这里提出四点备考建议&#xff0c;希望能帮到备考的大家&#xff1a; 【《PMBOK指南》】 PMP的教材仍是第六版&#xff0c;如果有第七版就看第七版&#xff0c;纸质或者电子版都可以&am…

【基础强训】day1

一、选择题&#xff1a; 1. 以下for循环的执行次数是&#xff08;&#xff09; for(int x 0, y 0; (y 123) && (x < 4); x); A 是无限循环 B 循环次数不定 C 4次 D 3次 C y123为真&#xff0c;所以就循环四次。 2. 以下程序的运行结果是&#xff08;&#xff…

jsp+ssm计算机毕业设计ssm酒店综合管理平台【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

2D激光雷达:使用MindStudio进行MindX SDK任务开发

任务介绍 该项目基于DROW3和DR-SPAAM模型&#xff0c;实现了实时的2D激光雷达行人检测。 主要处理流程为&#xff1a;输入预处理后的激光雷达点云序列&#xff08;帧&#xff09;->行人检测模型推理->行人检测模型后处理->检测结果输出及可视化。 由于二维距离数据信…

Unity Gradient Lerp 颜色渐变

最近改插件&#xff0c;本来如果有Gradient的lerp方法&#xff0c;改起来会非常方便。因为插件的更改入口是这个Gradient。运行时候手动调节inspector面板可以直接更改效果。那么此时只要在代码中更改Gradient即可。 但是找了几遍Color&#xff0c;ColorUtility&#xff0c;Gr…

怎么去图片水印?三招让你快速学会图片去水印

上大学的时候&#xff0c;老师让我们每人写一个关于“阅读”的主题报告。写这个主题报告的时候&#xff0c;我发现在网上找的图片素材大多带有水印&#xff0c;十分影响报告的展示效果。于是&#xff0c;我就上网找了一些怎么去图片水印的方法&#xff0c;对这些方法进行试验后…