【数据结构和算法14】堆结构(基于数组实现)

news2024/11/25 19:35:30

目录

1、有关二叉树和堆的介绍

2、大根堆的代码实现

3、小根堆的代码实现


1、有关二叉树和堆的介绍

计算机科学中,堆是一种基于树的数据结构,通常用完全二叉树实现。堆的特性如下

  • 在大顶堆(大根堆)中,任意节点 C 与它的父节点 P 符合 P.value >= C.value

  • 而小顶堆(小根堆)中,任意节点 C 与它的父节点 P 符合 P.value <= C.value

  • 最顶层的节点(没有父亲)称之为 root 根节点

例1 - 满二叉树(Full Binary Tree)特点:每一层都是填满的

 

例2 - 完全二叉树(Complete Binary Tree)特点:最后一层可能未填满,靠左对齐

 

例3 - 大根堆

 

例4 - 小根堆

 

完全二叉树可以使用数组来表示

 

  • 如果从索引 0 开始存储节点数据

    • 节点 i 的父节点为 floor((i-1)/2),当 i>0 时

    • 节点 i 的左子节点为 2i+1,右子节点为 2i+2,当然它们得 < size

  • 如果从索引 1 开始存储节点数据

    • 节点 i 的父节点为 floor(i/2),当 i > 1 时

    • 节点 i 的左子节点为 2i,右子节点为 2i+1,同样得 < size

2、大根堆的代码实现


​
/**
 * 使用数组实现堆数据结构
 * 定义一个用于存储整形数据的大根堆
 *
 * @author zjj_admin
 */
public class MaxHeap {
​
    /**
     * 用于存储数据
     */
    private int[] array;
​
​
    /**
     * 堆中的数据个数
     */
    private int size;
​
​
    public MaxHeap(int capacity) {
        this.size = 0;
        this.array = new int[capacity];
        //调整堆的结构
        adjust();
    }
​
    /**
     * 获取堆中的元素个数
     *
     * @return
     */
    public int size() {
        return size;
    }
​
    /**
     * 查看堆顶元素
     *
     * @return
     */
    public int peek() {
        if (size <= 0) {
            throw new NullPointerException("没有数据了");
        }
        return array[0];
    }
​
​
    /**
     * 返回并移除堆顶元素
     *
     * @return
     */
    public int poll() {
        if (size <= 0) {
            throw new NullPointerException("没有数据了");
        }
        int top = array[0];
        //让第一个数据和左后一个数据做交换
        exchange(0, size - 1);
        size--;
        // 重新对第一个元素做下潜操作
        down(0);
        return top;
    }
​
    /**
     * 返回并移除指定索引的数据
     * 1、先将索引 index 和最后一个数据进行交换
     * 2、移除最后一个数据,及删除了开始索引为 index 的数据
     * 3、对索引 index 的数据进行上浮操作,当不发生节点交换时再进行下潜操作
     *
     * @param index
     * @return
     */
    public int poll(int index) {
        if (index < 0) {
            throw new IndexOutOfBoundsException("index 必须不小于 0");
        }
        // 当索引数据
        if (index > size - 1) {
            throw new NullPointerException("没有数据了");
        }
        //先将索引 index 和最后一个数据进行交换
        exchange(index, size - 1);
        //移除最后一个数据,及删除了开始索引为 index 的数据
        int removed = array[size - 1];
        size--;
        //对索引 index 的数据进行上浮操作,当不发生节点交换时再进行下潜操作
        int newParent = up(index);
        down(newParent);
        return removed;
    }
​
    /**
     * 向堆中添加一个元素
     *
     * @param value
     * @return
     */
    public boolean offer(int value) {
        if (size >= array.length) {
            return false;
        }
        array[size] = value;
        size++;
        //上浮最后一个元素
        up(size - 1);
        return true;
    }
​
    /**
     * 调整堆结构,让其满足大根堆
     * 方法:从最后一个非叶子节点开始,依次向前做下潜操作
     * 在数组中,左后一个非叶子节点的索引为:(size/2  - 1)
     */
    private void adjust() {
        for (int i = size / 2 - 1; i >= 0; i--) {
            //依次做下潜操作即可
            down(i);
        }
    }
​
​
    /**
     * 堆节点做下潜操作,让父节点数据不小于子节点数据
     *
     * @param parent
     */
    private void down(int parent) {
        if (2 * parent + 1 < size && array[parent] < array[2 * parent + 1]) {
            // 交换位置
            exchange(parent, 2 * parent + 1);
​
            // 做下潜操作
            down(2 * parent + 1);
        } else if (2 * parent + 2 < size && array[parent] < array[2 * parent + 2]) {
            // 交换位置
            exchange(parent, 2 * parent + 2);
​
            // 做下潜操作
            down(2 * parent + 2);
        }
    }
​
    /**
     * 上浮操作,并返回上浮终点索引
     *
     * @param child
     * @return 上浮终点索引
     */
    private int up(int child) {
        int parent = (child - 1) / 2;
        while (parent >= 0 && array[child] > array[parent]) {
            exchange(parent, child);
            child = parent;
            parent = (child - 1) / 2;
        }
        return Math.max(child, 0);
    }
​
    /**
     * 交换堆中两个位置的数据
     *
     * @param i
     * @param j
     */
    private void exchange(int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
​
    @Override
    public String toString() {
        int[] a = new int[size];
        System.arraycopy(array, 0, a, 0, size);
        return Arrays.toString(a);
    }
}

3、小根堆的代码实现


/**
 * 使用数组实现堆数据结构
 *
 * @author zjj_admin
 */
public class MinHeap {
​
    /**
     * 用于存储数据
     */
    private int[] array;
​
​
    /**
     * 堆中的数据个数
     */
    private int size;
​
​
    public MinHeap(int capacity) {
        this.size = 0;
        this.array = new int[capacity];
        //调整堆的结构
        adjust();
    }
​
    /**
     * 获取堆中的元素个数
     *
     * @return
     */
    public int size() {
        return size;
    }
​
    /**
     * 查看堆顶元素
     *
     * @return
     */
    public int peek() {
        if (size <= 0) {
            throw new NullPointerException("没有数据了");
        }
        return array[0];
    }
​
​
    /**
     * 返回并移除堆顶元素
     *
     * @return
     */
    public int poll() {
        if (size <= 0) {
            throw new NullPointerException("没有数据了");
        }
        int top = array[0];
        //让第一个数据和左后一个数据做交换
        exchange(0, size - 1);
        size--;
        // 重新对第一个元素做下潜操作
        down(0);
        return top;
    }
​
    /**
     * 返回并移除指定索引的数据
     * 1、先将索引 index 和最后一个数据进行交换
     * 2、移除最后一个数据,及删除了开始索引为 index 的数据
     * 3、对索引 index 的数据进行上浮操作,当不发生节点交换时再进行下潜操作
     *
     * @param index
     * @return
     */
    public int poll(int index) {
        if (index < 0) {
            throw new IndexOutOfBoundsException("index 必须不小于 0");
        }
        // 当索引数据
        if (index > size - 1) {
            throw new NullPointerException("没有数据了");
        }
        //先将索引 index 和最后一个数据进行交换
        exchange(index, size - 1);
        //移除最后一个数据,及删除了开始索引为 index 的数据
        int removed = array[size - 1];
        size--;
        //对索引 index 的数据进行上浮操作,当不发生节点交换时再进行下潜操作
        int newParent = up(index);
        down(newParent);
        return removed;
    }
​
    /**
     * 向堆中添加一个元素
     *
     * @param value
     * @return
     */
    public boolean offer(int value) {
        if (size >= array.length) {
            return false;
        }
        array[size] = value;
        size++;
        //上浮最后一个元素
        up(size - 1);
        return true;
    }
​
    /**
     * 调整堆结构,让其满足大根堆
     * 方法:从最后一个非叶子节点开始,依次向前做下潜操作
     * 在数组中,左后一个非叶子节点的索引为:(size/2  - 1)
     */
    private void adjust() {
        for (int i = size / 2 - 1; i >= 0; i--) {
            //依次做下潜操作即可
            down(i);
        }
    }
​
​
    /**
     * 堆节点做下潜操作
     *
     * @param parent
     */
    private void down(int parent) {
        if (2 * parent + 1 < size && array[parent] > array[2 * parent + 1]) {
            // 交换位置
            exchange(parent, 2 * parent + 1);
​
            // 做下潜操作
            down(2 * parent + 1);
        } else if (2 * parent + 2 < size && array[parent] > array[2 * parent + 2]) {
            // 交换位置
            exchange(parent, 2 * parent + 2);
​
            // 做下潜操作
            down(2 * parent + 2);
        }
    }
​
    /**
     * 上浮操作,并返回上浮终点索引
     *
     * @param child
     * @return 上浮终点索引
     */
    private int up(int child) {
        int parent = (child - 1) / 2;
        while (parent >= 0 && array[child] < array[parent]) {
            exchange(parent, child);
            child = parent;
            parent = (child - 1) / 2;
        }
        return Math.max(child, 0);
    }
​
    /**
     * 交换堆中两个位置的数据
     *
     * @param i
     * @param j
     */
    private void exchange(int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
​
    @Override
    public String toString() {
        int[] a = new int[size];
        System.arraycopy(array, 0, a, 0, size);
        return Arrays.toString(a);
    }
}

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

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

相关文章

开源视频监控管理平台国标GB28181视频EasyCVR电子地图功能展示优化

视频监控综合管理平台EasyCVR可提供的视频能力包括&#xff1a;视频监控直播、云端录像、云存储、录像检索与回看、告警上报、平台级联、云台控制、语音对讲、电子地图、H.265自动转码等&#xff0c;也具备接入AI智能分析的能力。 视频汇聚平台EasyCVR可拓展性强、视频能力灵活…

centos7中用shell脚本实现mysql分库分表备份

环境&#xff1a; 脚本&#xff1a; #!/bash/bin back_path/backup/db databases_file/backup/databases.list [ -f $databases_file ] || touch /backup/databases.list if [[ ! -s ${databases_file} ]] thenecho "$databases_file为空,请在该文件中写上需要备份的数据…

C# Modbus TCP上位机测试

前面说了三菱和西门子PLC的上位机通信&#xff0c;实际在生产应用中&#xff0c;设备会有很多不同的厂家生产的PLC&#xff0c;那么&#xff0c;我们就需要一种通用的语言&#xff0c;进行设备之间的通信&#xff0c;工业上较为广泛使用的语言之一就是Modbus。 Modbus有多种连…

filscan api 获取错误扇区个数

获取错误扇区个数 POST 请求 curl -s -X POST -H "Content-Type: application/json" -d {"account_id": "f01889512"} https://api-v2.filscan.io/api/v1/AccountInfoByID | jq -r .result.account_info.account_miner.account_indicator.fault…

JMM内存模型深入详解,探索volatile、synchronized与VarHandle深层次的奥秘

文章目录 一、JMM内存模型1、什么是JMM&#xff08;1&#xff09;参考资料 2、竞态条件&#xff08;Race Condition&#xff09;&#xff08;1&#xff09;实例 3、同步动作&#xff08;Synchronization Order&#xff09;&#xff08;1&#xff09;实例&#xff08;2&#xff…

fSGAT批量候选基因关联分析丨快速单基因关联分析

候选基因如何分析&#xff1f; 通常情况下关联分析会得到一大堆候选基因&#xff0c;总不可能每个都有用&#xff0c;因此需要对候选基因进行深一步分析&#xff0c;本篇笔记分享一下群体遗传学研究中GWAS候选位点与候选基因的筛选思路。主要的方式包括单基因关联分析、连锁程度…

Appium+python自动化(二十三)- Monkeyrunner与Monkey傻傻的分不清楚(超详解)

monkeyrunner简介 1.monkeyrunner工具使用Jython&#xff0c;这是一种使用Java编程语言的Python实现。Jython允许monkeyrunner API与Android框架轻松交互。使用Jython&#xff0c;您可以使用Python语法来访问API的常量&#xff0c;类和方法。MonkeyRunner工具是使用Jython(使用…

【VCS】(7)Fast Gate-level Verification

Fast Gate-level Verification VCS中SDF反标(Back-Annotation)Lab 门级网表的后仿真DC综合RTL级仿真波形后仿真 网表级的仿真可以验证综合后得到的门级网表和RTL代码是否一致。也可以验证&#xff0c;在加速时序信息&#xff08;SDF&#xff09;之后&#xff0c;设计的功能是否…

基于POX、JBX交叉的遗传算法求解车间调度

对于流水车间调度问题&#xff0c;n个工件在m台设备上加工&#xff0c;已知每个工件每个工序使用的机器和每个工件每个工序所用时间&#xff0c;通过决策每个机器上工件的加工顺序和每个工序的开始时间&#xff0c;使完成所有工序所用时间(makespan)最小。具有下列约束&#xf…

58寸透明屏的画质怎么样?

58寸透明屏是一种新型的显示屏技术&#xff0c;它具有透明度高、色彩鲜艳、清晰度高等特点&#xff0c;可以广泛应用于商业展示、户外广告、智能家居等领域。 首先&#xff0c;58寸透明屏的透明度高。 透明屏采用了先进的光学技术&#xff0c;使得屏幕在显示图像的同时&#x…

ubuntu 18.04 磁盘太满无法进入系统

安装了一个压缩包&#xff0c;装了一半提示磁盘空间少导致安装失败。我也没在意&#xff0c;退出虚拟机打算扩展硬盘。等我在虚拟机设置中完成扩展操作&#xff0c;准备进入虚拟机内部进行操作时&#xff0c;发现登录不进去了 shift 登入GUN GRUB设置项的问题 网上都是在开机…

Rust vs Go:常用语法对比(十三)

题图来自 Go vs. Rust: The Ultimate Performance Battle 241. Yield priority to other threads Explicitly decrease the priority of the current process, so that other execution threads have a better chance to execute now. Then resume normal execution and call f…

在centos 7系统docker上构建mysql 5.7

一、VM上已经安装centos 7.9&#xff0c;且已完成docker的构建 二、安装mysql5.7 安装镜像&#xff1a;[rootlocalhost lll]# docker pull mysql:5.7 查看镜像[rootlocalhost lll]# docker images 根据镜像id构建mysql容器&#xff0c;且分配端口号[rootlocalhost lll]# dock…

勘探开发人工智能应用:断层识别

1 断层识别 断层是地下岩层在受到挤压或拉伸力作用下,因脆性变形而形成的地层错断,是一种重要的地质构造特征。断层检测和解释是从地震剖面中认识岩层结构和储层特性的重要步骤。 1.1 数据描述 合成地震数据: 每一个合成地震数据都是由地质模型的反射系数与雷克子波进行褶…

chrome插件推荐

chrome插件推荐 chrome的一些插件, 真的能很大程度上提升我们的工作效率。而且chrome的插件极其丰富, 基本你想要的功能,都能找到对应的插件&#xff0c;接下来给大家推荐几个我自己在用的。 插件 1、Momentum 新标签页 简介: 超漂亮的新标签页面。每日更新精彩背景壁纸图片&…

124.【SpringBoot 源码刨析C】

SpringBoot源码刨析C (三)、SpringBoot核心功能2.Web4.数据响应与内容协商(1).响应JSON&#xff08;1.1&#xff09;jackson.jarResponseBody&#xff08;1.1.1&#xff09;、返回值解析器&#xff08;1.1.2&#xff09;、返回值解析器原理 (1.2).SpringMVC到底支持哪些返回值(…

一遍过JavaSE基础知识

文章目录 前言安装Java Development Kit (JDK)安装jdk配置开发环境验证是否安装配置成功 编写第一个Java程序hello world运行Java程序的流程 数据类型和变量数据类型变量 程序逻辑控制条件语句循环语句跳转语句 数组声明和创建数组访问数组元素数组长度遍历数组多维数组 面向对…

OpenAI大模型生态与ChatGLM ||学习大模型我们需要掌握些什么?

首先我们来看OpenAI系列模型&#xff1a; OpenAI 并不只有一个模型&#xff0c;而是提供了涵盖文本、码、对话、语音、图像领域的一系列模型。 语言类大模型 其中语言类大模型包括: GPT-3、GPT-3.5、GPT-4系列模型。 并且&#xff0c;OpenAI在训练GPT-3的同时训练了参数不同、…

Disulfo ICG Amine,二磺酸吲哚菁绿氨基,应用于多种生物大分子以及药物的检测

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ Disulfo-ICG-Amine试剂 | 基础知识概述&#xff08;部分&#xff09;: 中文名称&#xff1a;二磺酸吲哚菁绿氨基 英文名称&#xff1a;Disulfo-ICG-Amine&#xff0c;Disulfo ICG NH2 CAS号&#xff1a;N/A 分子式&#xf…

【Gray Hat Python】构建自己的windows调试器

环境准备 windows10 64bit python3.7 64bit 打开可执行文件&#xff0c;创建进程 定义变量 以下代码用 ctypes 定义了调用 windows API 需要的结构 my_debugger_define.py import ctypesWORD ctypes.c_ushort DWORD ctypes.c_ulong LPBYTE ctypes.POINTER(ctypes.c_uby…