【数据结构】二叉树之堆的实现

news2024/10/7 12:25:44

🔥博客主页:小王又困了

📚系列专栏:数据结构

🌟人之为学,不日近则日退

❤️感谢大家点赞👍收藏⭐评论✍️


目录

一、二叉树的顺序结构

📒1.1顺序存储

📒1.2堆的性质

📒1.3堆的分类

二、堆的实现

📒2.1堆的创建

📒2.2堆的初始化

📒2.3堆的插入

📒2.4向上调整数据

📒2.5堆的删除

📒2.6向下调整数据

📒2.7堆的销毁


🗒️前言:

在上一期的文章中我们学习了一些二叉树的知识,也了解了堆的概念。堆是一颗完全二叉树,分为大堆和小堆,今天我们将实现堆的各种功能。

一、二叉树的顺序结构

📒1.1顺序存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

📒1.2堆的性质

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

📒1.3堆的分类

  • 小堆:树中任意一个父亲都小于等于孩子
  • 大堆:树中任意一个父亲都大于等于孩子

二、堆的实现

📒2.1堆的创建

堆的逻辑结构是树形结构,是我们想象出来的,实际上我们操作的数组,所以堆的创建和顺序表的结构相同。

typedef int HPDateType;
typedef struct Heap
{
    HPDateType* a;
    int size;
    int capacity;
}HP;

📒2.2堆的初始化

我们有两种初始化的方式,一种是在初始化阶段不开辟空间,在插入过程中进行扩容;另一种是在初始化阶段就开辟空间。

void HeapInit(HP* php)
{
    assert(php);
    php->a = NULL;
    php->size = 0;
    php->capacity = 0;
}
void HeapInit(HP* php)
{
    assert(php); 
    php->size = 0;
    php->capacity = 5;
    php->a = (HPDateType*)malloc(sizeof(HPDateType) * capacity);
    if (tmp == NULL)
    {
        perror("malloc");
        exit(-1);
    }
}

📒2.3堆的插入

堆是使用顺序结构的数组来存储的,我们使用尾插插入数据更方便,然后将数据调整到合适的位置。

4143c6b8ae344af89a1c07f578efa8b6.jpeg

void HeapPush(HP* php, HPDataType x)
{
    assert(php);

    // 扩容
    if (php->size == php->capacity)
    {
        int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(-1);
        }

        php->a = tmp;
        php->capacity = newCapacity;
    }

    php->a[php->size] = x;
    php->size++;

    AdjustUp(php->a, php->size - 1);
}

如图:在小堆中插入50,50比它的父亲小,所以要交换两数的位置。我们知道孩子的下标通过 parent=(child-1)/2 就可以得到父亲的下标,然后交换两数。

📒2.4向上调整数据

如果是小堆存储我们通过孩子的下标找到父亲,比较两数如果孩子小于父亲就交换,然后在向上比较,如果孩子不小于父亲就跳出循环。

void Swap(HPDataType* p1, HPDataType* p2)
{
    HPDataType tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (a[child] < a[parent])
        {
            Swap(&a[child], &a[parent]);
            child = parent;
            parent = (parent - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

📒2.5堆的删除

我们使用挪动覆盖的方法删除根,会使关系混乱,剩下的值不一定是堆,而且效率很低。这里提供一种更好的方法,将根和最后一个值交换,然后删除,最后调整数据。

void HeapPop(HP* php)
{
    assert(php);
    assert(php->size > 0);

    Swap(&php->a[0], &php->a[php->size - 1]);
    --php->size;

    AdjustDown(php->a, php->size, 0);
}

这里要注意有数据的时候才能删除,所以要加入 assert(php->size > 0) 进行判断。

📒2.6向下调整数据

如果是小堆存储我们要找到左右孩子中较小的数,然后与父亲交换,再找到下一层重复步骤,直到找到叶节点结束。

void AdjustDown(HPDataType* a, int n, int parent)
{
    //默认左孩子是较小的
    int child = parent * 2 + 1;
    while (child < n)
    {
        // 找出小的那个孩子
        if (child + 1 < n && a[child + 1] < a[child])
        {
            ++child;
        }

        if (a[child] < a[parent])
        {
            Swap(&a[child], &a[parent]);
            // 继续往下调整
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

📒2.7堆的销毁

我们使用动态开辟内存,要及时释放空间并置为空指针,不然会造成数据泄露。

void HeapDestroy(HP* php)
{
    assert(php);

    free(php->a);
    php->a = NULL;
    php->size = php->capacity = 0;
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。

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

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

相关文章

【力扣每日一题】2023.9.23 树上的操作

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这是一道程序设计类的题目&#xff0c;题目比较长&#xff0c;我稍微概括一下。 构造函数中给我们一个数组&#xff0c;第i个元素表示第…

进程的状态和转换

一、进程的状态 1.创建态&#xff1a;进程正在被创建的阶段。此阶段&#xff0c;操作系统会为进程分配资源、初始化PCB。 2.就绪态&#xff1a;进程创建完毕即进入就绪态。此阶段&#xff0c;进程具备已经具备所有运行条件&#xff0c;但是此时CPU比较繁忙&#xff0c;没有空闲…

5+非肿瘤+WGCNA+单细胞

今天给同学们分享一篇5非肿瘤WGCNA单细胞的生信文章“Integrative network-based analysis on multiple Gene Expression Omnibus datasets identifies novel immune molecular markers implicated in non-alcoholic steatohepatitis”&#xff0c;这篇文章于2023年3月16日发表…

基于SpringBoot的房产销售系统

目录 前言 一、技术栈 二、系统功能介绍 用户功能模块 管理员功能模块 销售经理功能模块 前台首页功能模块 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手…

Java对比对象修改前与修改后字段发生的变化

开发过程中&#xff0c;我们通常会对系统操作人对系统的操作进行记录&#xff0c;记录操作前后某个字段的变化&#xff0c;如下图 2. 提供一个工具类&#xff0c;可以比较一个对象里面&#xff0c;源对象&#xff0c;与修改后的对象&#xff0c;有哪些字段发生了改变&#…

地球系统模式(CESM)应用及进阶

目前通用地球系统模式&#xff08;Community Earth System Model&#xff0c;CESM&#xff09;在研究地球的过去、现在和未来的气候状况中具有越来越普遍的应用。CESM由美国NCAR于2010年07月推出以来&#xff0c;一直受到气候学界的密切关注。近年升级的CESM2.0在大气、陆地、海…

在pandas中使matplotlib动态画子图的两种方法【推荐gridspec】

先上对比图&#xff0c; 第一种方法&#xff0c;这里仅展示1个大区&#xff0c;多个的话需要加一层循环就可以了&#xff0c;主要是看子图的画法 当大区下面的国家为1个或2个时&#xff0c;会进行报错 # 获取非洲国家列表 african_countries df[df[大区] 南亚大区][进口国…

ARM DAY3

硬件模块与总线连接&#xff1a;各种硬件模块&#xff08;如 GPIO 控制器&#xff09;与 CPU&#xff08;或内核&#xff09;通过总线进行连接。这个总线负责数据和指令的传输。 特殊功能寄存器&#xff08;SFRs&#xff09;的角色&#xff1a;每个硬件模块内部都有一组特殊功…

PowerDesigner 连接 MYSQL

我使用的是powerDesigner16的版本&#xff0c;使用前先保证安装了 mysql odbc 驱动包 选择&#xff1a;文件 -> 反向工程 -> database… 一大波图片正在来袭。。。 点击确认 至此连接成功

解决方案 | 如何构建市政综合管廊安全运行监测系统?

如何构建市政综合管廊安全运行监测系统&#xff1f;WITBEE万宾城市生命线智能监测仪器&#xff0c;5年免维护设计&#xff0c;集成10多项结构与气体健康监测指标&#xff0c;毫秒级快速响应&#xff0c;时刻感知综合管廊运行态势

make: /bin/nvcc: Command not found 解决找不到nvcc

首先输入nvcc -V查看nvcc路径&#xff0c;发现报错Command nvcc not found&#xff0c;接下来我们就要解决这个问题。 1&#xff09;进入cuda的bin目录cd /usr/local/cuda/bin&#xff0c;ls查看是否有nvcc 说明存在nvcc但cuda路径没有添加系统变量 2&#xff09;在bin目录下输…

C++中变量是按值访问的, Python 中变量的值是按引用访问的示例说明

C中变量是按值访问的&#xff0c; Python 中变量的值是按引用访问的示例说明 C、C、Python如何获取变量的地址 C语言 在C语言中&#xff0c;可以使用取地址运算符&#xff08;&&#xff09;来获取变量的地址。 例如&#xff1a; #include <stdio.h>int main() {…

基于SSM+Vue的网上超市系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

苏宁滑块验证

网址&#xff1a;https://passport.suning.com/ids/login总结一下&#xff0c;别被他的表面现象给骗了&#xff0c;这玩意儿&#xff0c;个人认为&#xff0c;腾讯的都没法跟他比&#xff01;&#xff01;&#xff01; 难点&#xff1a;动态混淆&#xff0c;vmp&#xff0c;图片…

PID学习

文章目录 1、 简介2、P 比例调节3、I 积分控制4、D 微分控制5、简单的模拟PID输出代码6、改进6.1 采样时间6.1.1 问题所在6.1.2 解决方案6.1.3 代码6.1.4 结果6.1.5 关于中断的旁注6.1.6 个人总结 6.2 微分项出现尖峰6.2.1 问题所在6.2.2 解决方案6.2.3 代码6.2.4 结果6.2.5 个…

执行上下文,js、React、HTML中的this

目录 执行上下文属性&#xff1a;变量对象、this&#xff0c;作用域链 变量对象是与执行上下文相关的数据作用域&#xff0c;存储&#xff1a;变量、函数声明 执行上下文生命周期 创建&#xff1a;生成变量对象、创建函数作用域&#xff0c;建立作用域链、确定this的指向 …

jdk 21发布的意义

jdk 21 最大的功能是虚拟线程&#xff0c;是一种绿色线程&#xff08;具体可以看周志明老师的书籍《深入理解java虚拟机》&#xff09;&#xff0c;目前 jvm 与操作系统的线程是一一对应的关系。 使用了虚拟线程可以减少资源消耗&#xff0c;减少操作系统上下文切换&#xff0…

AIGC绘本——海马搬家来喽

随着ChatGPT的快速发展&#xff0c;人工智能领域也发生了翻天覆地的变化。今天&#xff0c;我们迎合科技潮流&#xff0c;利用AIGC的强大能力&#xff0c;可以创作很多精彩的作品&#xff0c;比如这样一本名为《海马搬家》的绘本&#xff08;注&#xff1a;此绘本根据同名儿童故…

strtok()函数的使用方法

strtok() 函数用于将字符串分割成子字符串&#xff08;标记&#xff09;。它在 C 语言中非常常用&#xff0c;可以通过指定分隔符来拆分原始字符串&#xff0c;并依次返回每个子字符串。 以下是 strtok() 函数的使用方法&#xff1a; #include <stdio.h> #include <…

RK3568平台开发系列讲解(驱动篇)RK3568 I2C总线介绍

🚀返回专栏总目录 文章目录 一、I2C 简介1.1、起始位1.2、停止位1.3、数据传输1.4、应答信号1.5、I2C 写时序1.6、I2C 读时序1.7、I2C 多字节读写时序二、RK3568 I2C 总线介绍沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将讲解RK3568 I2C总线特性。 一、…