数据结构-堆

一、什么是堆

先了解两种特别的二叉树

满二叉树

除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树

完全二叉树

完全二叉树相对于满二叉树来说,最后一层叶子节点从左到右中间没有空缺的,像这样:

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

  • 大顶堆中,任意节点 C 与它的父节点 P 符合 p.value >= c.value
  • 小顶堆中,任意节点 C 与它的父节点 P 符合 p.value <= c.value
  • 最顶层的节点(没有父亲)称之为 root 根节点

完全二叉树可以使用数组来表示,像下图这样

如果从索引 0 开始存储节点数据,它的特征如下:

  • 节点i的父节点为 floor((i-1)/2)
  • 当 i>0 时,节点i的左子节点为2i+1,右子节点为2i+2,当然它们得小于size

二、堆插入元素

以小堆为例,在插入元素的时候,先把元素放到数组的最后,然后与父节点比较,如果比父节点大,就插入成功了,如果比父节点小就跟父节点交换位置,直到它比父节点大或到达跟节点为止。

下面是代码实现

    /**
     *
     * @param e 添加的元素
     * @return 是否成功
     */
    public boolean offer (Integer e) {
        int i = size;
        size = i + 1;
        if (i == 0) {
            queue[i] = e;
        } else {
            siftUp(i, e);
        }
        return true;
    }

    /**
     * 1. 获取父节点
     * 2. 让元素与父节点比较,如果小于就交换位置,大于就结束
     * @param i 被添加元素的索引
     * @param e 被添加元素的值
     */
    public void siftUp(int i, Integer e) {
        queue[i] = e;
        while (i > 0) {
            int parent = (i - 1) / 2;
            if (e > queue[parent]) {
                break;
            }
            swap(i, parent);
            i = parent;
        }

    }

三、出堆实现

  1. 弹出数组第一个元素返回
  2. 把数组最后一个元素放到第一位,然后对它元素进行下潜操作,下潜操作分为这3个步骤
  • 计算左子结点和右子节点
  • 左子节点和右子节点中较小的一个和父节点比较(子节点的index不能大于size)
  • 如果有比父节点小的就交换位置,直到到达叶子节点或者左子节点或右子节点没有小于父节点的就结束

代码实现:

    /**
     *  1.返回第一个元素
     *  2.第一个元素与最后一个元素交换
     *  3.size--,最后一个元素置为null
     *  4.对第一个元素执行下潜操作
     */
    public Integer poll() {
        if (size == 0) {
            throw new RuntimeException("Null");
        }
        Integer result = queue[0];
        swap(0, size - 1);
        queue[--size] = null;
        siftDown(0);
        return result;
    }

    /**
     * 1. 计算左子结点和右子节点
     * 2. 左子节点和右子节点中较小的一个和父节点比较(子节点的index不能大于size)
     * 3. 如果有比父节点小的就交换位置,直到到达叶子节点或者左子节点或右子节点没有小于父节点的就结束
     * @param index 要下潜元素的索引
     */
    public void siftDown(int index) {
        int parent = index;
        int left = index * 2 + 1;
        int right = left + 1;
        if (left < size && queue[left] < queue[parent]) {
            parent = left;
        }
        if (right < size && queue[right] < queue[parent]) {
            parent = right;
        }
        // 说明找到更小的了
        if (parent != index) {
            swap(parent, index);
            siftDown(parent);
        }
    }

四、完整代码

public class Heap {

    private static final int DEFAULT_INITIAL_CAPACITY = 11;

    transient Integer[] queue;

    private int size = 0;

    public Heap() {
        queue = new Integer[DEFAULT_INITIAL_CAPACITY];
    }

    public static void main(String[] args) {
        Heap heap = new Heap();
        heap.offer(1);
        heap.offer(5);
        heap.offer(2);
        heap.offer(4);
        heap.offer(3);

        heap.poll();
        heap.poll();
    }

    /**
     *
     * @param e 添加的元素
     * @return 是否成功
     */
    public boolean offer (Integer e) {
        int i = size;
        size = i + 1;
        if (i == 0) {
            queue[i] = e;
        } else {
            siftUp(i, e);
        }
        return true;
    }

    /**
     * 1. 获取父节点
     * 2. 让元素与父节点比较,如果小于就交换位置,大于就结束
     * @param i 被添加元素的索引
     * @param e 被添加元素的值
     */
    public void siftUp(int i, Integer e) {
        queue[i] = e;
        while (i > 0) {
            int parent = (i - 1) / 2;
            if (e > queue[parent]) {
                break;
            }
            swap(i, parent);
            i = parent;
        }

    }

    /**
     *  1.返回第一个元素
     *  2.第一个元素与最后一个元素交换
     *  3.size--,最后一个元素置为null
     *  4.对第一个元素执行下潜操作
     */
    public Integer poll() {
        if (size == 0) {
            throw new RuntimeException("Null");
        }
        Integer result = queue[0];
        swap(0, size - 1);
        queue[--size] = null;
        siftDown(0);
        return result;
    }

    public void swap(int i, int j) {
        int temp = queue[i];
        queue[i] = queue[j];
        queue[j] = temp;
    }

    /**
     * 1. 计算左子结点和右子节点
     * 2. 左子节点和右子节点中较小的一个和父节点比较(子节点的index不能大于size)
     * 3. 如果有比父节点小的就交换位置,直到到达叶子节点或者左子节点或右子节点没有小于父节点的就结束
     * @param index 要下潜元素的索引
     */
    public void siftDown(int index) {
        int parent = index;
        int left = index * 2 + 1;
        int right = left + 1;
        if (left < size && queue[left] < queue[parent]) {
            parent = left;
        }
        if (right < size && queue[right] < queue[parent]) {
            parent = right;
        }
        // 说明找到更小的了
        if (parent != index) {
            swap(parent, index);
            siftDown(parent);
        }
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

驾考在线答题系统源码:含PC+手机版驾考宝典多题库

安装说明&#xff1a; 1、上传到网站根目录 2、用 phpMyadmin 导入数据库文件 db.sql 3、修改数据库链接文件 /ThinkPHP/Conf/convention.php# &#xff08;记得不要用记事本修改&#xff0c;否则可能会出现验证码显示不了问题&#xff0c;建议用 Notepad 4、 帐号 admin 密码…

Git 入门使用 —— 建库、代码上下传、常用命令

目录 一、Git 入门 1.1 Git简介 1.2 Git安装 1.3 创建码云仓库 二、Git 使用 2.1 git初始化操作 2.2 代码上传 2.3 代码下载 2.4 代码更新 2.4.1 仓库管理者 2.4.1 仓库使用者 三、Git 常用命令 一、Git 入门 1.1 Git简介 Git是一个开源的分布式版本控制系统&am…

Wireshark分析tcp交互过程

三次握手 客户端发起请求 Tcp段长度为575字节&#xff0c;seq1&#xff0c;ack1&#xff0c;next_seq576 服务器响应&#xff1a; Tcp段长度为175字节&#xff0c;seq1&#xff0c;ack576&#xff0c;next_seq176 客户端响应&#xff1a; Tcp段长度523字节&#xff0c;seq576&…

Lazarus安装和入门资料

azarus-2.2.6-fpc-3.2.2-win64 下载地址 Lazarus 基础教程 - Lazarus Tutorials for Beginners Lazarus Tutorial #1 - Learning programming_哔哩哔哩_bilibili https://www.devstructor.com/index.php?pagetutorials Lazarus是一款开源免费的object pascal语言RAD IDE&…

数据结构: 哈希桶

目录 1.概念 2.模拟实现 2.1框架 2.2哈希桶结构 2.3相关功能 Modify --Insert --Erase --Find 2.4非整型数据入哈希桶 1.仿函数 2.BKDR哈希 1.概念 具有相同地址的key值归于同一集合中,这个集合称为一个桶,各个桶的元素通过单链表链接 2.模拟实现 2.1框架 a.写出…

H5横屏适配方案

横屏模式一般使用场景比较少&#xff0c;特殊情况除外&#xff0c;一般用于游戏、操作性比较大的网页会采用横屏 整体代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" conte…

【第2章 Node.js基础】2.2 Node.js回调函数

学习目标 &#xff08;1&#xff09;理解Node.js的回调函数&#xff1b; &#xff08;2&#xff09;掌握回调函数的使用。 什么是回调函数 回调函数是一种特殊的函数&#xff0c;它作为参数传递给另一个函数&#xff0c;并在特定的事件或条件发生时被调用。回调函数通常用于异…

【Git】深入了解Git及其常用命令

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Git的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Git是什么 二.SVN和Git的区别 三.Git的…

二十、泛型(5)

本章概要 边界通配符 编译器有多聪明逆变无界通配符捕获转换 边界 边界&#xff08;bounds&#xff09;在本章的前面进行了简要介绍。边界允许我们对泛型使用的参数类型施加约束。尽管这可以强制执行有关应用了泛型类型的规则&#xff0c;但潜在的更重要的效果是我们可以在…

【C++】开源:rapidjson数据解析库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍rapidjson数据解析库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

VS Code+DevChat助力非专业开发也能玩转代码编程

一、前言 偶然间网上瞎逛&#xff0c;看到DevChat 发布了一款 VS Code 插件&#xff0c;可提供类似chatgpt一样的“一站式 AI 辅助编程”体验。据说&#xff0c; DevChat 直接对接 GPT-4 还让免费用&#xff0c;目前免费注册收邮件即可获取key&#xff0c;再也不用麻烦的外部手…

web3 从redux中拿出所有已完成订单 并渲染到对应的Table列表中

上文web3 React dapp项目通过事件从区块链中拿到 已取消 已完成 和所有的订单数据 并存入redux中 中 我们已经从 区块中拿到了自己的订单 然后 我们恢复一下上文的环境 ganache ganache -d然后 登一下 MetaMask 然后 用我们的项目 发布一下合约 truffle migrate --reset然后…

使用Streamlit创建AutoGen用户界面

AutoGen作为一个最大化LLM(如GPT-4)能力的框架而脱颖而出。由微软研究院开发的AutoGen通过提供一种自动化、优化和编排工作流的方法&#xff0c;简化了复杂的、基于多代理llm的应用程序的创建。我们在以前的文章中也有过介绍&#xff0c;你可以与许多GPT交谈&#xff0c;并且GP…

STM32独立看门狗(IWDG)溢出时间计算

什么是IWDG&#xff1f; 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动&#xff0c;即使主时钟发生故障它也仍然有效。 IWDG最适合应用于那些需要看门狗作为一个在主程序之外&#xff0c;能够完全独立工作&#xff0c;并且对时间精度要求较低的场合。 从上图我们可以看出IWDG的时…

每日一练 | 华为认证真题练习Day127

1、如图所示&#xff0c;关于OSPF的拓扑和配置&#xff0c;下列说法中正确的是&#xff08;&#xff09;。 A. R1与R2相比&#xff0c;R2更有机会成为DR&#xff0c;因为它的接口DR优先级值较小 B. 只要把R1的接口网络类型恢复为默认的广播类型&#xff0c;R1和R2即可建立稳定…

Netty入门指南之NIO 粘包与半包

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言问题产…

xcode SDK does not contain ‘libarclite‘

SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a; try increasing the minimum deployment target解决方法 iOS13以上

多语言翻译软件 Mate Translate mac中文版特色功能

Mate Translate for Mac是一款多语言翻译软件&#xff0c;Mate Translate mac可以帮你翻译超过100种语言的单词和短语&#xff0c;使用文本到语音转换&#xff0c;并浏览历史上已经完成的翻译。你还可以使用Control S在弹出窗口中快速交换语言。 Mate Translate Mac版特色功能…

由于flutter_app依赖于flutter_swiper>=0.0.2,不支持零安全,版本解决失败。

参考 dart3.0使用flutter_swiper报错记录 flutter_swiper package - All Versions从官网的信息可以看到 Dart3版本不兼容 最小兼容的Dart SDK版本需要2.0 Flutter SDK 版本列表Flutter SDK 版本列表 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 说明&#xff1a;因…

骨传导运动蓝牙耳机推荐,这五款骨传导耳机不要错过!

骨传导耳机在这两年在运动圈中非常火热&#xff0c;相比传统耳机&#xff0c;骨传导耳机使用时开放双耳&#xff0c;不堵塞耳朵&#xff0c;解决了入耳式耳机佩戴的不适感。同时&#xff0c;也避免了戴耳机运动时耳内出汗带来的一系列卫生和健康问题。最关键的是通过耳骨传声&a…