当前位置: 首页 > 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…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...