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

数据结构——lesson7二叉树 堆的介绍与实现

前言💞💞

啦啦啦~这里是土土数据结构学习笔记🥳🥳

在这里插入图片描述
💥个人主页:大耳朵土土垚的博客
💥 所属专栏:数据结构学习笔记
💥对于数据结构顺序表链表有疑问的都可以在上面数据结构的专栏进行学习哦~ 欢迎大家🥳🥳点赞✨收藏💖评论哦~🌹🌹🌹 有问题可以写在评论区或者私信我哦~

一、 堆的概念及结构

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

堆的性质

  1. 堆中某个节点的值总是不大于或不小于其父节点的值;
  2. 堆总是一棵完全二叉树。
    在这里插入图片描述

✨✨简单来说大堆指的是父节点都大于子节点的完全二叉树;
小堆指的是父节点都小于子节点的完全二叉树;
大堆的根节点是最大的,小堆是最小的。

二、堆的实现

1.堆的创建

我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

下面是堆创建以及实现堆所需的函数,后文将一一介绍

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int HPDataType;
//构建一个结构体封装堆
typedef struct Heap
{HPDataType* a;//数组顺序表int size;//堆元素个数int capacity;//数组空间
}Heap;
//以下是实现堆的函数
// 堆的初始化
void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

2.堆的初始化

void HeapInit(Heap* hp)

//堆的初始化
void HeapInit(Heap* hp)
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

3.堆的删除(删除堆顶元素)

void HeapPop(Heap* hp)

在介绍堆的删除之前我们先介绍堆向下调整算法;
显而易见堆的删除不可能像顺序表那样删除尾部元素size–就行,我们需要玩点高深的,删除顶部元素,但删除顶部元素就没办法保证它删除后还是一个堆了,这就要利用我们下面介绍的向下调整算法。

int a[] = {1,8,3,5,7,6}; 

该数组逻辑结构可以看成一个完全二叉树如下图所示:
在这里插入图片描述

我们可以从图中看出它是一颗完全二叉树,但并不是所有的父节点都大于或小于其子节点,所以不是一个堆,接下来我们就可以通过下面介绍的堆向下调整算法将它调整为一个堆。

堆向下调整算法
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述

🥳🥳 ①下面介绍第一种向下调整为小堆
前提条件——左右子树都是小堆

//堆向下调整算法(小堆)
void AdjustDown(HPDataType* a, int n,int parent)
{int child = parent * 2 + 1;//向下调整while (parent < n){//找到较小的孩子节点if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

因为要调整为小堆,所以要找到孩子中较小的一个进行比较;
如果父节点小于较小的孩子节点则直接break不需要调整,因为向下调整的前提条件是——左右子树都是小堆
调整前:
在这里插入图片描述
调整后:在这里插入图片描述

💞💞Swap函数在这里

//交换函数
void Swap(HPDataType* a,HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}

🥳🥳②第二种向下调整为大堆;前提条件——左右子树都是大堆

//堆向下调整算法(大堆)
void AdjustDown(HPDataType* a, int n,int parent)
{int child = parent * 2 + 1;//向下调整while (child < n){//找到较大的孩子节点if (child + 1 < n && a[child] < a[child + 1]){child++;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

因为要调整为大堆,所以要找到孩子中较大的一个进行比较; 如果父节点大于于较大的孩子节点则直接break不需要调整,因为向下调整的前提条件是——左右子树都是大堆

🎉🎉我们这里使用小堆向下调整,大家可以根据自己的需求选择哦~

学习完堆向下调整我们知道只要左右子树是一个堆,那么我们就可以从根节点开始向下调整直到整个二叉树成为一个堆;💫💫
所以删除堆顶元素我们就可以将堆顶元素与最后一个元素交换一下位置,这样除了根节点,其余父子关系都没变,左右子树还是堆,删除交换后的最后一个元素(也就是原来的根节点);🎉🎉
我们再利用堆向下调整算法,将整个二叉树再次复原为堆。🥳🥳

堆顶元素删除

// 堆的删除,删除堆顶元素
void HeapPop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));//判空函数将在后文介绍//交换首尾元素Swap(&hp->a[0], &hp->a[hp->size - 1]);//size要记得--,表示删除元素hp->size--;//向下调整算法AdjustDown(hp->a, hp->size, 0);}

4.堆的插入

void HeapPush(Heap* hp, HPDataType x)

我们知道堆的父节点必须都大于或小于子节点,那么往一个堆中插入元素是没办法保证大于或小于其父节点的,所以我们插入之后需要调整这个二叉树来保证堆;
这里就要用到堆向上调整算法了;注意下面是小堆的调整

堆向上调整算法

//向上调整
void AdjustUp(HPDataType* a,int child)
{//找到双亲节点int parent = (child - 1) / 2;//向上调整while (child > 0){if (a[parent] > a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}

堆向上调整类似于向下调整也有大堆小堆之分,大家可以依照堆的向下调整自己试试看写一下大堆的向上调整

堆的插入

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{assert(hp);//判断容量if (hp->size == hp->capacity)//容量满了扩容{int newcapacity = hp->capacity == 0 ? 0 : 2 * hp->capacity;HPDataType* new = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);if (new == NULL){perror("realloc fail");return;}hp->a = new;hp->capacity = newcapacity;}//尾插hp->a[hp->size] = x;hp->size++;//向上调整算法AdjustUp(hp->a,hp->size-1);
}

这里要注意插入数据要判断容量,如果满了要用realloc函数扩容,对于realloc函数有疑问的可以看土土的动态内存函数博客🎉🎉——c语言动态内存函数介绍;
如果第一次扩容,就将空间扩为4个HPDataType,其余扩原来的两倍

5. 取堆顶的数据

HPDataType HeapTop(Heap* hp);

// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));//判空return hp->a[0];//顶即下标为0的元素
}

6. 堆的数据个数

int HeapSize(Heap* hp)

// 堆的数据个数
int HeapSize(Heap* hp)
{assert(hp);return hp->size;
}

堆的数据个数即为结构体中的size,直接返回即可

7.堆的销毁

void HeapDestory(Heap* hp)

// 堆的销毁
void HeapDestory(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

,在内存中用realloc函数开辟空间用 free释放即可

💖💖判空函数在这里~
int HeapEmpty(Heap* hp)

// 堆的判空
int HeapEmpty(Heap* hp)
{assert(hp);return hp->size == 0;
}

8.堆实现代码如下

#include"Heap.h"
//堆的初始化
void HeapInit(Heap* hp)
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}
// 堆的销毁
void HeapDestory(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}
//交换函数
void Swap(HPDataType* a,HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}//堆向下调整算法
void AdjustDown(HPDataType* a, int n,int parent)
{//找到较小的孩子节点int child = parent * 2 + 1;//向下调整while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

测试代码如下:

#include"Heap.h"
int main()
{Heap hp;HeapInit(&hp);int a[] = { 65,100,70,32,50,60 };for (int i = 0; i < 6; i++){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){int top = HeapTop(&hp);printf("%d\n", top);HeapPop(&hp);}return 0;}

运行结果如下:
在这里插入图片描述
居然是升序诶~大家知道原因吗
可以根据上面的代码和介绍理解为自己解答哦~

三、结语

以上就是堆的介绍和实现啦~✨✨需要注意的是堆有大堆小堆之分,相应的函数也就有两种,这里简单介绍了小堆的实现,大堆介绍了一点,大家可以通过上面介绍的自己探索大堆的实现,此外堆向上调整与向下调整是一个重难点大家要多花时间去理解与记忆哦 ~完结撒花 ~💖🎉🎉🥳

相关文章:

数据结构——lesson7二叉树 堆的介绍与实现

前言&#x1f49e;&#x1f49e; 啦啦啦~这里是土土数据结构学习笔记&#x1f973;&#x1f973; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5; 所属专栏&#xff1a;数据结构学习笔记 &#x1f4a5;对于数据结构顺序表链表有疑问的都可以在上面数据结…...

阿里云DSW做AI绘画时的显卡选择A10?V100?

V100是Volta架构&#xff0c;A10是Ampere架构&#xff0c;架构上讲A10先进点&#xff0c;其实只是制程区别&#xff0c;用起来没区别。 V100是HBM的内存读取&#xff0c;带宽大&#xff0c;但是DDR5的。 二块卡都是全精度为主的算力卡&#xff0c;半精度优势不明显。 需要用…...

MySQL安装使用(mac)

目录 一、下载MySQL 二、环境变量 三、启动 MySql 四、初始化密码设置 一、下载MySQL 打开 MySql 官方下载页面 我是macOS12&#xff0c;所以选择了8.0.30 下载完成之后&#xff0c;打开安装&#xff0c;一直下一步安装完成&#xff0c;在最后安装完成时&#xff0c;会弹出…...

Qt控制台项目也能使用opencv的imshow来显示摄像头视频

创建一个Qt控制台项目,目的是实现在控制台打开摄像头视频。由于windows平台是支持GUI&#xff08;图形用户界面&#xff09;功能&#xff0c;所以在windows环境下是可以打开的&#xff0c;但是linux环境下&#xff0c;由于不支持GUI功能&#xff0c;而是支持wayland&#xff0c…...

前端缓存使用规范

一、Cookie使用规范 cookie的存储空间非常有限且会携带在请求头中会浪费不必要的流量&#xff0c;如果仅仅是为存储数据&#xff0c;可以采用其他替代方案&#xff0c;例如 webStorage&#xff0c;非必要不使用cookie。 1、使用方法 注意&#xff1a;过期时间时需转换成UTC格…...

Linux rmmod命令教程:如何卸载内核模块(附实例详解和注意事项)

Linux rmmod命令介绍 rmmod&#xff08;全称&#xff1a;remove module&#xff09;用于从Linux内核中卸载已加载的内核模块。它允许您在运行时移除不再需要的模块&#xff0c;以释放系统资源或更改内核配置。 Linux rmmod命令适用的Linux版本 rmmod在大多数Linux发行版中通…...

中国气象要素年度空间插值数据集

摘要 中国气象要素年度空间插值数据集是地理遥感生态网平台基于全国2400多个站点的气象要素站点日观测数据&#xff0c;在计算各气象要素年值的基础上&#xff0c;基于Anuspl插值软件生成1960-2021年各年度蒸发量、地温、降水量、气压、相对湿度、日照时数 、气温、风速8个气象…...

链表习题-力扣oj (附加思路版)

LCR 140. 训练计划 IIhttps://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号&#xff0c;请查找并返回倒数第 cnt 个训练项目编号。 思路&#xff1a;双指针&#xff0c;快指针先走cnt…...

HNU-计算机网络-甘晴void学习感悟

前言 计算机网络其实我没太学懂&#xff0c; 仅从应试来说&#xff0c;考试成绩也不太好。 这也是为什么一直没有更新这一学科的学习感悟。 大三下还是有点闲&#xff0c;一周三天小长假&#xff0c;闲来无事还是给写了。 教材使用这本&#xff1a; 总领 期中考试 30% 期…...

混合输入矩阵乘法的性能优化

作者 | Manish Gupta OneFlow编译 翻译&#xff5c;宛子琳、杨婷 AI驱动的技术正逐渐融入人们日常生活的各个角落&#xff0c;有望提高人们获取知识的能力&#xff0c;并提升整体生产效率。语言大模型&#xff08;LLM&#xff09;正是这些应用的核心。LLM对内存的需求很高&…...

安卓Kotlin面试题 41-50

41、如何在 Kotlin 中实现 Builder 模式?首先,在大多数情况下,您不需要在 Kotlin 中使用构建器,因为我们有默认和命名参数,但如果您需要使用://add private constructor if necessary class Car( val model: String?,val year: Int) { private constructor(build…...

portainer管理远程docker和docker-swarm集群

使用前请先安装docker和docker-compose&#xff0c;同时完成docker-swarm集群初始化 一、portainer-ce部署 部署portainer-ce实时管理本机docker&#xff0c;使用docker-compose一键拉起 docker-compose.yml version: 3 services:portainer:container_name: portainer#imag…...

分销商城微信小程序:用户粘性增强,促进复购率提升

在数字化浪潮的推动下&#xff0c;微信小程序作为一种轻便、高效的移动应用形式&#xff0c;正成为越来越多企业开展电商业务的重要平台。而分销商城微信小程序的出现&#xff0c;更是为企业带来了前所未有的机遇。通过分销商城微信小程序&#xff0c;企业不仅能够拓宽销售渠道…...

深度学习与机器学习:互补共进,共绘人工智能宏伟蓝图

在人工智能的广阔天地中&#xff0c;深度学习与机器学习如同两支强大的队伍&#xff0c;各自闪耀着独特的光芒&#xff0c;却又携手共进&#xff0c;共同书写着智能的辉煌篇章。尽管深度学习是机器学习的一个分支&#xff0c;但它们在模型构建、特征提取以及应用场景等多个方面…...

Vue.js 实用技巧:深入理解 Vue.mixin

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

【Spring Boot 3】读取resource文件

【Spring Boot 3】读取resource文件 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或…...

BUUCTF:[MRCTF2020]ezmisc

题目地址&#xff1a;https://buuoj.cn/challenges#[MRCTF2020]ezmisc 下载附件打开是一张照片&#xff1a; 放到kali中发现crc校验错误&#xff0c;修改照片宽高&#xff1a; 保存即可发现flag flag为&#xff1a; flag{1ts_vEryyyyyy_ez!}...

2024 RubyMine 激活,分享几个RubyMine 激活的方案

文章目录 RubyMine 公司简介我这边使用RubyMine 的理由RubyMine 2023.3 最新变化AI Assistant 正式版对 AI 生成名称建议的支持改进了 Ruby 上下文单元测试生成 RailsRails 应用程序和引擎的自定义路径Rails 路径的自动导入对存储在默认位置之外的模型、控制器和邮件器的代码洞…...

Flutter使用auto_updater实现windows/mac桌面应用版本升级功能

因为windows应用一般大家都是从网上下载的&#xff0c;后期版本肯定会更新&#xff0c;那用flutter开发windows应用&#xff0c;怎么实现应用内版本更新功能了&#xff1f;可以使用auto_updater库&#xff0c; 这个插件允许 Flutter 桌面 应用自动更新自己 (基于 sparkle 和 wi…...

Python编程实验六:面向对象应用

目录 一、实验目的与要求 二、实验内容 三、主要程序清单和程序运行结果 第1题 第2题 四、实验结果分析与体会 一、实验目的与要求 &#xff08;1&#xff09;通过本次实验&#xff0c;学生应掌握类的定义与对象的创建、类的继承与方法的覆盖&#xff1b; &#xff08;2…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...

DAY 26 函数专题1

函数定义与参数知识点回顾&#xff1a;1. 函数的定义2. 变量作用域&#xff1a;局部变量和全局变量3. 函数的参数类型&#xff1a;位置参数、默认参数、不定参数4. 传递参数的手段&#xff1a;关键词参数5 题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...

大数据驱动企业决策智能化的路径与实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;数据驱动的企业竞争力重构 在这个瞬息万变的商业时代&#xff0c;“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...

接口 RESTful 中的超媒体:REST 架构的灵魂驱动

在 RESTful 架构中&#xff0c;** 超媒体&#xff08;Hypermedia&#xff09;** 是一个核心概念&#xff0c;它体现了 REST 的 “表述性状态转移&#xff08;Representational State Transfer&#xff09;” 的本质&#xff0c;也是区分 “真 RESTful API” 与 “伪 RESTful AP…...

Axure Rp 11 安装、汉化、授权

Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接&#xff1a;https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...

【2D与3D SLAM中的扫描匹配算法全面解析】

引言 扫描匹配(Scan Matching)是同步定位与地图构建(SLAM)系统中的核心组件&#xff0c;它通过对齐连续的传感器观测数据来估计机器人的运动。本文将深入探讨2D和3D SLAM中的各种扫描匹配算法&#xff0c;包括数学原理、实现细节以及实际应用中的性能对比&#xff0c;特别关注…...

【AI News | 20250609】每日AI进展

AI Repos 1、OpenHands-Versa OpenHands-Versa 是一个通用型 AI 智能体&#xff0c;通过结合代码编辑与执行、网络搜索、多模态网络浏览和文件访问等通用工具&#xff0c;在软件工程、网络导航和工作流自动化等多个领域展现出卓越性能。它在 SWE-Bench Multimodal、GAIA 和 Th…...