当前位置: 首页 > news >正文

【DS】6.堆知识总结!!!

堆(Heap)和栈(Stack)是我们面试过程中很重要的两个概念。不同场景下,含义不同.

一般有两种含义。

程序内存布局场景下:两种内存管理方式;

数据结构场景下:两种常用的数据结构。

本文就是我对堆这种数据结构的理解。

文章目录

    • 一、堆的基本概念、性质及存储方式
      • 定义
      • 定义关键点提取
      • 堆的性质
      • 堆的存储方式
      • 图示
    • 二、堆的创建【两种方式,but都是向下调整】
      • 关于向上向下调整
      • 大根堆的创建
        • 思路分析
        • 图示分析
        • 代码实现
      • 小根堆的创建
        • 思路分析
        • 图示分析
        • 代码实现
      • 建堆时间复杂度求解
    • 三、堆的插入与删除
      • 堆的插入
        • 思路分析
        • 图示分析
        • 代码实现
      • 堆的删除
        • 思路分析
        • 图示分析
        • 代码实现

一、堆的基本概念、性质及存储方式

定义

定义:有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一 个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大
堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

定义关键点提取

  1. 堆是一棵完全二叉树
  2. 二叉树中的key值按照二叉树层序遍历的结果存放到一维数组中
  3. 根节点的值总是大于/小于左孩子节点和右孩子节点的,但是左孩子和右孩子值大小关系并不确定

堆的性质

  • 堆中某个节点的值总是不大于或不小于其父节点的值
  • 堆总是一棵完全二叉树

堆的存储方式

顺序存储:二叉树中的key值按照二叉树层序遍历的结果存放到一维数组中【高效存储】

链式存储:操作较麻烦,应用较少。

特别注意

假设i为节点在数组中的下标

  • 如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
  • 如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子
  • 如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子

图示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r8mtHDoq-1665900642821)(F:\typora插图\image-20221016084031230.png)]

二、堆的创建【两种方式,but都是向下调整】

关于向上向下调整

向上:子过程从下往上,一般是插入操作

向下:子过程从根节点到孩子节点,一般是建堆操作和删除操作

大根堆的创建

思路分析

  1. 每棵子树都应该是大根堆
  2. 从下往上调整
  3. ①从最后一颗子树的根节点开始调整②然后 减减调整其他的根节点③之后,为确保调整根节点的孩子节点作为根节点的堆是大根堆,设置shitDown子函数
  4. 怎么找到最后一棵子树的根节点

【说明:虽然我们说堆是一棵二叉树,但是实际堆创建时给的是数组,我们根据数组创建即可】

图示分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sbzbYCyA-1665900619347)(F:\typora插图\image-20221016132650135.png)]

代码实现

public void createHeap(){
    for (int parent = (usedSize-1-1)/2; parent >= 0; parent--) {
        shitDown(parent,usedSize);
    }
}
private void shitDown(int parent,int len){
    int child=2*parent+1;
    while(child<len){
        if((child+1<len)&&(elem[child]<elem[child+1])){
            child++;
        }
        if(elem[child]>elem[parent]){
            int tmp=elem[child];
            elem[child]=elem[parent];
            elem[parent]=tmp;
            parent=child;
            child=2*parent+1;
        }else{
            break;
        }
    }
}

小根堆的创建

思路分析

  1. 思路与大根堆类似
  2. 只需要将函数中逻辑比较部分的大于换成小于即可

图示分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JkyW2Scr-1665900619348)(F:\typora插图\image-20221016133502589.png)]

代码实现

public void createHeap(){
    for (int parent = (usedSize-1-1)/2; parent >= 0; parent--) {
        shitDownSmall(parent,usedSize);
    }
}
private void shitDownSmall(int parent, int len){
    int child=2*parent+1;
    while(child<len){
        if((child+1<len)&&(elem[child]>elem[child+1])){
            child++;
        }
        if(elem[child]<elem[parent]){
            int tmp=elem[child];
            elem[child]=elem[parent];
            elem[parent]=tmp;
            parent=child;
            child=2*parent+1;
        }else{
            break;
        }
    }
}

建堆时间复杂度求解

时间复杂度

  • 调整(即shitDown子函数)的时间复杂度是O(logn)【树的高度】
  • 建堆的时间复杂度是O(n)

过程分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDHRujZM-1665900619350)(F:\typora插图\image-20221016140451913.png)]

三、堆的插入与删除

对于一般的数据结构,我们一般讨论它的增删查改操作,那为什么我们这里只讨论堆的插入和删除呢?

查找和更改操作一般基于索引,一般是查找指定下标 的,但是堆并没有索引概念。这样的操作很少用。

但是堆有时也让查堆顶的值。

堆的插入

思路分析

  1. 插入之后,仍然要保证得到的是大根堆
  2. 用的是向上调整shitUp
  3. 原来就是一个大根堆,所以只需要比较新插入的child和parent
  4. 循环截止条件是child<=0/parent>=0

图示分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5pxQRaiC-1665900619352)(F:\typora插图\image-20221016134546939.png)]

代码实现

public void offer(int val){
    if(isFull()){
        elem= Arrays.copyOf(elem,elem.length*2);
    }
    this.elem[usedSize++]=val;
    shitUp(usedSize-1);
}
private void shitUp(int child){
    int parent=(child-1)/2;
    while(child>0){
        if(elem[child]>elem[parent]){
            int tmp=elem[child];
            elem[child]=elem[parent];
            elem[parent]=tmp;
            child=parent;
            parent=(parent-1)/2;
        }else{
            break;
        }
    }
}
public boolean isFull(){
    return usedSize==elem.length;
}

堆的删除

思路分析

  1. 使用的是一个交换
  2. 把想要删除的节点和堆顶元素交换,然后向下调整
  3. 传的结束位置是usedSize-1,因为已经删除一个节点了

图示分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-faZg1C9e-1665900619354)(F:\typora插图\image-20221016140616855.png)]

代码实现

public int pop(){
    if(isEmpty()){
        return -1;
    }
    int tmp=elem[0];
    elem[0]=elem[usedSize-1];
    elem[--usedSize]=tmp;
    shitDown(0,usedSize);
    return tmp;
}
public boolean isEmpty(){
    return usedSize==0;
}
private void shitDown(int parent,int len){
    int child=2*parent+1;
    while(child<len){
        if((child+1<len)&&(elem[child]<elem[child+1])){
            child++;
        }
        if(elem[child]>elem[parent]){
            int tmp=elem[child];
            elem[child]=elem[parent];
            elem[parent]=tmp;
            parent=child;
            child=2*parent+1;
        }else{
            break;
        }
    }
}

相关文章:

  • kali工具熟悉——存活主机识别
  • 剖释C++内存管理底层细节 | 明晰池化技术中内存管理的原理
  • LVGL v8学习笔记 | 10 - Tabview控件的使用方法
  • 【漏洞复现-dedecms-文件上传】vulfocus/dedecms-cve_2019_8933
  • 罗克韦尔AB PLC安装Studio5000提示未安装Microsoft .NET Framework 3.5的解决方法
  • C++类和对象详解(下篇)
  • 李沐论文精读笔记( ResNet、Transformer、GAN、BERT)
  • 机器学习SVM算法原理
  • 神经网络学习小记录72——Parameters参数量、FLOPs浮点运算次数、FPS每秒传输帧数等计算量衡量指标解析
  • 牛客网之SQL刷题练习——一个实用的网站
  • TDesign-starter-React
  • 【云原生】Spark on k8s 讲解与实战操作
  • 使用 Flask 部署 Next.js
  • 如何排查内存溢出问题
  • 2_spring-cloud-ribbon
  • 08.Android之View事件问题
  • codis proxy处理流程
  • css系列之关于字体的事
  • Docker容器管理
  • HTML5新特性总结
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Java多态
  • Python进阶细节
  • Spring声明式事务管理之一:五大属性分析
  • Vue官网教程学习过程中值得记录的一些事情
  • vue--为什么data属性必须是一个函数
  • 浏览器缓存机制分析
  • 每天一个设计模式之命令模式
  • 实战|智能家居行业移动应用性能分析
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 小李飞刀:SQL题目刷起来!
  • 一个完整Java Web项目背后的密码
  • Python 之网络式编程
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • ​学习一下,什么是预包装食品?​
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (¥1011)-(一千零一拾一元整)输出
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (二)PySpark3:SparkSQL编程
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (算法二)滑动窗口
  • *上位机的定义
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .net Application的目录
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET 使用配置文件
  • .NET 中的轻量级线程安全
  • .Net各种迷惑命名解释
  • .pyc文件是什么?
  • .sh
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce