【数据结构】二叉堆一文详解,附demo

news2024/12/28 3:11:02

有时候也挺迷惑的,技术那么多,感觉学什么都来不及,又什么都得学,经常一看别人,哇,比你年轻比你厉害,然后自己emo一下又要鸡血模式,就挺无语的,但愿我们的坚持与努力都不白费吧,虽然开发可能不是一辈子的事,但但是干一天优秀一天,也是很有价值感的,加油共勉

二叉堆(Binary Heap)是一种特殊的完全二叉树数据结构,用于高效地实现优先队列。二叉堆可以分为两种类型:最小堆(Min Heap)和最大堆(Max Heap)。

在最小堆中,每个父节点的值都不大于其子节点的值;

而在最大堆中,每个父节点的值都不小于其子节点的值

二叉堆的关键特性是它提供了对堆中元素的快速访问、插入和删除操作,所有这些操作的时间复杂度都是 O(log n),其中 n 是堆中的元素数量。

完全二叉树与二叉堆的关系

完全二叉树是一种二叉树,除了最后一层外,每一层都是满的,并且最后一层的所有节点都尽可能地向左靠拢。二叉堆就是基于这种结构的,也就是说,二叉堆满足完全二叉树的定义,同时还要满足堆的性质。

物理存储与逻辑结构

虽然二叉堆在逻辑上表现为一棵树,但在计算机内存中通常使用数组来存储。数组的索引被用来表示树中的节点位置。具体来说有如下特性:

  • 数组的第 0 个位置通常不使用,从第 1 个位置开始存储第一个元素(即根节点)。

  • 对于任意节点 i:

  • 其左子节点的位置是 2i。

  • 其右子节点的位置是 2i + 1。

  • 其父节点的位置是 i / 2(向下取整)。

  • 任何索引大于或等于堆大小一半(size / 2)的节点都不可能有右孩子(因为这些节点处于树的最后一层或倒数第二层,都是叶子节点,它们最多只有一个孩子或没有孩子),这句话啥意思呢
    在这里插入图片描述

可以看p001这个图,上图节点数是8/2=4,大于等于4的有5,6,7,8,都是叶子节点,这四个8在最底层,5,6,7在倒数第二层

这种存储方式使得二叉堆的操作非常高效,因为可以通过简单的数学运算来计算出父节点和子节点的数组位置。

基本操作

插入元素

当插入新元素时,首先将元素添加到数组的末尾,然后执行上浮操作(Bubble Up),即比较该元素与其父节点,如果违反了堆的性质,则交换它们的位置,继续向上比较直到找到合适的位置。

删除元素

删除元素通常是删除堆顶元素(最小堆中最小的元素,最大堆中最大的元素)。首先,将堆顶元素与最后一个元素交换,然后删除原数组末尾的元素,最后执行下沉操作(Sink Down),即比较当前堆顶元素与其子节点,如果违反了堆的性质,则与较小(最小堆)或较大(最大堆)的子节点交换位置,继续向下比较直到找到合适的位置(后面会用代码讲解,别着急)。

应用场景

二叉堆常用于实现优先队列(PriorityQueue的原理就是二叉堆),如在任务调度、事件驱动的模拟程序、Dijkstra 算法(最短路径算法)、Huffman 编码(数据压缩)等领域。

示例代码

下面是一个简单的最小堆实现示例,使用数组存储,注释都已经写清楚了,大家可以揣摩下

import java.util.Arrays;
/**
 * 二叉堆
 * 最小堆在上,最大在下
 */
public class MinHeap {
    //容量
    private int capacity = 10;
    //当前堆中元素个数
    private int size = 0;
    //堆数据
    private int[] data;

    public MinHeap(int capacity) {
        data = new int[capacity];
        this.capacity = capacity;
    }

    public static void main(String[] args) {
        MinHeap heap = new MinHeap(10);
        heap.put(4);
        heap.put(9);
        heap.put(3);
        heap.put(7);
        heap.put(2);
        heap.put(12);
        heap.put(6);
        heap.put(1);
        heap.put(5);
        heap.put(8);
        heap.print();

        heap.remove();
        heap.print();
 
    }

    /**
     * 插入节点
     *
     * @param value 键值
     * @return 成功或失败
     */
    public boolean put(int value) {
        //数组已满
        if (size > capacity) {
            System.out.println("数组已满");
            return false;
        }
        //直接将新节点插入到数据尾部
        data[size] = value;
        //插入节点后不满足二叉堆特性,需要重新堆化 先传后加
        shiftUp(size++);
        return true;
    }

    private void print(){
        System.out.println(Arrays.toString(data));
        System.out.println(data[0]);
    }

    /**
     * 自下而上堆化
     * @param pos 堆化的位置
     */
    private void shiftUp(int pos) {
        // parent 堆化位置的父节点;计算公式:父节点=子节点*2
        // 向上堆化过程
        System.out.println("开始堆化" + pos);
        if (pos == 0) {
            return;
        }
        while (true){
            int parent = (pos - 1) >>> 1;
            System.out.println("父-" + data[parent] + " 子-" + data[pos]);
            if (data[parent] > data[pos]){
                System.out.println("交换" + parent + "和" + pos);
                swap(parent, pos);
                System.out.println("交换后-父-" + data[parent] + " 子-" + data[pos]);
                if (parent == 0) {
                    break;
                }
                pos = parent;
            }else {
                break;
            }
        }
    }

    /**
     * 数组数据交换
     *
     * @param i 下标
     * @param j 下标
     */
    private void swap(int i, int j) {
        int tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    }


    /**
     * 删除最小值 并返回该值
     * @return
     */
    public int remove() {
        if (size < 1) {
            return -1;
        }
        int min = data[0];
        //将最后一个元素放到顶部 这个策略有可能需要堆化多次
        data[0] = data[--size];
        data[size] = 0;
        //重新堆化
        shiftDown(0);
        return min;
    }

    /**
     * 自上而下重新调整二叉堆
     *
     * @param pos 开始调整位置
     */
    private void shiftDown(int pos) {
        while (true) {
            //左子树
            int child = pos << 1 + 1;
            if (child >= size) {
                //没有子节点了
                break;
            }
            // 如果有右子树,并且右子树小于左子树,则转而考虑右子树 谁更小考虑谁,减少循环次数
            if (child + 1 < size && data[child + 1] < data[child]) {
                child++;
            }
            // 如果父节点小于任何一个子节点,则已经满足最小堆性质,退出循环
            if (data[pos] <= data[child]) {
                break;
            }
            // 否则交换父节点与较小的子节点
            swap(pos, child);
            pos = child;
        }
    }
}

这个类展示了如何使用数组实现二叉堆的基本插入和上浮操作,实际应用中还需要实现其他操作如删除、调整等。

二叉堆堆化后输出为
[1, 2, 4, 3, 7, 12, 6, 9, 5, 8]
在这里插入图片描述

二叉堆就到这了,有啥问题评论留言

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

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

相关文章

“炫我”受邀出席虚拟现实及元宇宙产业创新论坛!

当前&#xff0c;新一轮科技革命和产业变革向纵深演进&#xff0c;虚拟现实及元宇宙等相关产业加速发展&#xff0c;催生了新产业新业态新模式&#xff0c;发展潜力巨大、应用前景广阔。 9月27日&#xff0c;由北京市科学技术委员会、中关村科技园区管理委员会&#xff0c;北京…

攻防世界1

pwnstack 发现是64位文件 发现vuln双击进入 看到read知道这里是要将B1&#xff08;177&#xff09;的数据输入buf&#xff0c;这里涉及了栈溢出 发现system和binsh 后门 A8十进制是168 exp&#xff1a; from pwn import * context(oslinux,archamd64,log_leveldebug) io rem…

生产及质量BI应用场景方案(可编辑37页PPT)

荐言分享&#xff1a;随着全球化的深入发展&#xff0c;制造业面临的竞争日益激烈。为了在市场中脱颖而出&#xff0c;企业需要不断提升自身的生产效率、降低成本&#xff0c;同时保证产品质量。现代消费者的需求日益多样化&#xff0c;对产品的个性化、定制化和品质要求越来越…

【unity踩坑】打开vs2022没有文字联想/杂项文件

unity打开vs2022没有文字联想 修改外置编辑器安装unity开发插件vs编辑器显示杂项文件 修改外置编辑器安装unity开发插件 参考 在unity项目里选择Edit-> Preferences->External Tools然后更换编辑器 在vs工具界面添加unity游戏开发选项。 重新打开还是有问题&#xff…

记录搜罗到的Matlab 对散点进行椭圆拟合

需要基于一些散点拟合椭圆估计并计算出椭圆的参数和周长&#xff0c;搜罗到直接上代码 &#xff08;1&#xff09;有用的椭圆拟合及参数计算函数 function W fitellipse(x,y) % 构造矩阵 D [x.*x, x.*y, y.*y, x, y,ones(size(x))]; S D*D; G zeros(6); G(1,3) 2; G(3,1)…

深入探讨B+树索引的基本概念、工作原理以及在MySQL中的应用

文章目录 1. B树的基本概念2. B树在MySQL中的实现3. 示例代码4. 结论 在数据库管理系统中&#xff0c;索引是一种特殊的文件&#xff0c;它能够提高数据检索的速度。MySQL作为最流行的开源关系型数据库之一&#xff0c;提供了多种索引类型来满足不同的性能需求。其中&#xff0…

windows端口被占用但是查不到进程的问题排查

在开发环境上经常遇到端口被占用&#xff0c;但是 netstat -ano|findstr 3306 查不到进程号&#xff0c;没法强杀解决。 这种情况&#xff0c;很有可能端口被排除了&#xff0c;可用命令&#xff1a; netsh interface ipv4 show excludedportrange protocoltcp 可以看到mysql的…

web-前置技能(HTTP协议)-CTFHub

前言 在众多的ctf平台当中&#xff0c;作者认为ctfhub对于初学者来说&#xff0c;是入门平台的不二之选。ctfhub通过自己独特的技能树模块&#xff0c;可以帮助初学者来快速入门。具体请看官方介绍&#xff1a;CTFHub。 作者正在更新ctfhub系列&#xff0c;希望小伙伴们多多支…

多元线性回归:机器学习中的经典模型探讨

引言 多元线性回归是统计学和机器学习中广泛应用的一种回归分析方法。它通过分析多个自变量与因变量之间的关系&#xff0c;帮助我们理解和预测数据的行为。本文将深入探讨多元线性回归的理论背景、数学原理、模型构建、技术细节及其实际应用。 一、多元线性回归的背景与发展…

小米开放式耳机好不好用?小米、南卡、倍思、飞利浦热门开放式耳机一周测评!

​开放式耳机正成为潮流&#xff0c;它们不仅佩戴舒适&#xff0c;音质也出色&#xff0c;特别受到音乐发烧友和运动爱好者的追捧。作为一名多年的数码测评博主&#xff0c;我也早就对开放式耳机感兴趣了&#xff0c;只是最近一直没时间来好好测评下&#xff0c;今天一下子买了…

计算机网络实验二:FTP服务器配置

ftp服务器配置 要求&#xff1a; 1. 学会配置FTP服务器、能在FTP客户端进行下载和上传文件 2. 进一步熟悉ipconfig和ping命令 3. 进一步理解FTP工作原理和流程 1、FTP服务器配置&#xff08;FileZilla Server&#xff09; 第一步安装FileZilla Server&#xff0c;直接下一步…

二、安装vmtools

1、 介绍 vmtools 安装后&#xff0c;可以让我们在 windows 下更好的管理 vm 虚拟机。可以设置 windows 和 centos 的共享文件夹 当时当我们发现安装虚拟机工具位置是灰色的 右击打开终端 在终端输入命令 yum list installed | grep open-vm-*yum list installed 命令会列出…

TikTok代理IP哪里找?

对于那些希望通过社交媒体打造个人品牌的人来说&#xff0c;TikTok是现在热门的平台&#xff0c;他的流量与曝光不可小觑&#xff0c;相信很多跨境营销会选择他进行多账号营销。问题是&#xff0c;TikTok多账号很容易遇到封禁问题&#xff0c;那么如何解决&#xff1f; 一、什么…

如何查看1688阿里巴巴热销选品数据?

✅路径&#xff1a;店雷达选品中心—1688选品库—选择类目 选品前先选类目&#xff0c;初步定位符合自己产品方向后再去分析市场&#xff0c;想看全市场的品类就选择一级类目&#xff0c;也有二三级类目细分选择&#xff0c;根据商家经营目标而定 接着选择想看的市场统计周期&…

吸毛效果好的宠物空气净化器分享,希喂、霍尼韦尔、米家实测

说起宠物空气净化器&#xff0c;几年前我可能会一脸鄙夷&#xff1a;为啥要花这种智商税冤枉钱&#xff1f; 直到之前养了一只猫&#xff0c;被家中乱飞的浮毛和滂臭的异味搞到头晕&#xff0c;于是作为i一个养宠的家电测评博主&#xff0c;索性对宠物空气净化器这玩意做了超级…

教你批量在文件名后面加文字,5个方法超简单

教你批量在文件名后面加文字~在日常办公与项目管理中&#xff0c;文件的规范性与统一性至关重要。它们不仅是信息传递的载体&#xff0c;更是团队协作效率的基石。面对海量的文件资料&#xff0c;如何确保每个文件都能迅速被识别并归类&#xff0c;成为了一个不容忽视的问题。为…

基于QT(C+++Mysql)实现的带GUI的图书管理系统

图书管理系统总体设计报告 图书管理系统概述 本次项目设计并实现了一个精简的多用户图书管路系统。应用后端通过与 MySQL 进行连接实现对数据的管理。用户可以通过界面实现登陆、注册、借书、还书等操作。管理员可以通过登陆界面实现对用户和书籍的管理&#xff0c;具有添加/…

微机原理与接口技术--绪论

1.早期硬件系统组成 1.微处理器&#xff08;中央处理器&#xff09;&#xff08;CPU&#xff09;&#xff1a; 微型计算机的核心部件&#xff0c;它负责执行指令、进行算术逻辑运算和控制计算机的各个部件协同工作。CPU 的性能直接决定了计算机的运行速度和处理能力。例如&…

SSTI模板注入+CTF实例

参考文章&#xff1a; 一文了解SSTI和所有常见payload 以flask模板为例-腾讯云开发者社区-腾讯云 (tencent.com) python-flask模块注入(SSTI) - ctrl_TT豆 - 博客园 (cnblogs.com) ssti详解与例题以及绕过payload大全_ssti绕过空格-CSDN博客 1. SSTI&#xff08;模板注入&…

C语言基础语法——数值表示

进制 进制也就是进位制&#xff0c;是人们规定的一种进位方法对于任何一种进制—X进制&#xff0c;就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一&#xff0c;十六进制是逢十六进一&#xff0c;二进制就是逢二进一&#xff0c;以此类推&#xff0c;x进制就是逢x进位…