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

6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)

目录

一.堆(Heap)的基本介绍

二.堆的常用操作(以小根堆为例)

三.实现代码

3.1 堆结构定义

3.2 向下调整算法*

3.3 初始化堆*

3.4 销毁堆

3.4 向上调整算法*

 3.5 插入数据

3.6 删除数据

3.7 返回堆顶数据

四.下篇内容

1.堆排序

2.TopK问题


一.堆(Heap)的基本介绍

        了解堆之前我们要简单了解完全二叉树:        

        在二叉树中,我们使用指针来连接每一个结点,最后构成一颗二叉树。而堆是一种使用数组来表示完全二叉树。其满足以下两条规则。

        1.堆中结点值总是大于或者小于其父结点的值。

        2.堆总是一颗完全二叉树。

由此可以推出有两种堆:大根堆和小根堆。

大根堆:根节点的值最大。

小根堆:根节点的值最小。

在堆(二叉树)中,如果一个结点的下标为i

其父亲的结点的下标为 (i-1)/ 2

其左孩子结点的下标为 (i+1)*2 -1  即  i*2 +1

其右孩子结点的下标为 (i+1)*2      即  i*2 + 2

数组的下标由0开始,读者可根据下图进行理解

二.堆的常用操作(以小根堆为例)

//初始化堆
void HeapInit(Heap* php, DataType* arr, int n);//数组建堆主要依赖的算法(这个算法要求数组的左右子树都是小堆)
//小堆,使用向下调整算法
void Adjustdown(DataType* arr, int n, int root);//向上调整算法
void Adjustup(DataType* arr, int n, int root);//销毁堆
void HeapDestory(Heap* php);//插入数据
void HeapPush(Heap* php, DataType x);//删除数据
void HeapPop(Heap* php, DataType x);//求堆顶(根)数据
DataType HeadTop(Heap* php);//交换两个数据
void swap(DataType* p1, DataType* p2);

三.实现代码

3.1 堆结构定义

//以小根堆为例
typedef int DataType;
typedef struct Heap
{DataType* arr;    //数组int capacity;     //容量int size;         //元素大小
}Heap;

3.2 向下调整算法*

        小根堆使用该算法的前提是左右子树都为小根堆,大根堆的前提是左右子树都为大根堆

该算法是从根结点依次向下找到比自己小(或者大)的结点,然后进行交换。

最后就能将新插入的根节点放到相应的位置

调整规则:

小根堆:根节点每一次与孩子结点中较小的一个交换

大根堆:根节点每一次与孩子结点中较大的一个交换

如下图

代码如下(以小根堆为例)

//向下调整算法
void Adjustdown(DataType* arr, int n, int root)
{//1.小根堆,找出左右孩子中较小的结点int parent = root;int child = root * 2 + 1;	//表示左孩子while (child < n){//找到右孩子,如果右孩子比左孩子小,让child++。注意必须存在右孩子才能这么做if (child + 1 < n && arr[child + 1] < arr[child]){child++;}//如果该孩子比父亲小,就要交换if (arr[child] < arr[parent]){swap(arr[child], arr[parent]);//向下继续调整parent = child;child = parent * 2 + 1;}else{//如果孩子比父亲大,交换结束break;}}
}

3.3 初始化堆*

        初始化堆:将一个随机的数组(数组大小随机,元素大小也随机)转换为堆。

思路:

1.将一个数组拷贝到一个堆结构中

2.利用向下调整算法对整个数组进行调整,由于整个数组不能直接进行向下调整(左右子树不符合堆结构),所以我们使用向下调整算法堆 最后一个结点的父亲结点开始调整,然后依次对这个结点之前的结点开始调整。

3.最后得出完整的堆结构

流程图:

代码

//初始化堆
void HeapInit(Heap* hp, DataType* arr, int n)
{//开辟空间,大小为 DataType*nhp->arr = (DataType*)malloc(sizeof(DataType) * n);assert(hp->arr != nullptr);memcpy(hp->arr, arr, sizeof(DataType) * n);hp->size = n;hp->capacity = n;//拷贝好数据后,由于数据是随机的,所以我们使用调整算法建堆//我们从最后一个度为2的结点开始向前依次对每一个结点都进行向下调整//最后一个结点下标为 n-1 则其父亲结点为(n-1-1)/2for (int i = (n - 1 - 1) / 2; i > 0; i--){Adjustdown(hp->arr, hp->size, i);}
}

3.4 销毁堆

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

3.4 向上调整算法*

当我们插入新数据时,这个数据会破坏堆结构(如插入到数组末尾),所以我们需要向上调整

和向下调整算法类似

思路:

        让新增节点依次和自己的父亲比较,然后交换即可

        小根堆:比父亲小,交换。直到比父亲大就结束

        大根堆:比父亲大,交换。直到比父亲小就结束

流程图:

代码

//向上调整算法,以小根堆为例
void Adjustup(DataType* arr, int n, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr[child] < arr[parent]){swap(arr[child], arr[parent]);//继续向上调整child = parent;parent = (child - 1) / 2;}else{break;}}
}

 3.5 插入数据

//插入数据
void HeapPush(Heap* hp, DataType x)
{assert(hp);//1.增容if (hp->size == hp->capacity){hp->capacity *= 2;DataType* tmp = (DataType*)realloc(hp->arr, sizeof(DataType) * hp->capacity);assert(tmp != NULL);hp->arr = tmp;}//2.在数组的插入数据hp->arr[hp->size] = x;hp->size++;//对数组进行向上调整,将小的数据向上调整Adjustup(hp->arr, hp->size, hp->size - 1);
}

3.6 删除数据

删除堆顶的数据

我们交换第一个数据和最后一个数据,然后删除最后一个数据。再对堆顶进行向下调整

这样就能满足删除后,整个堆还是满足规则的

//删除数据(删掉堆顶的数据)
//类似于堆排序,交换第一个和最后一个数据。保证根节点的左右子树都是小根堆
void HeapPop(Heap* hp)
{assert(hp);assert(hp->arr);swap(hp->arr[0], hp->arr[hp->size - 1]);hp->size--;Adjustdown(hp->arr, hp->size, 0);
}

3.7 返回堆顶数据

直接返回0下标处的数据即可

//求堆顶(根)数据
DataType HeadTop(Heap* hp)
{assert(hp);assert(hp->size > 0);return hp->arr[0];
}

四.下篇内容

1.堆排序

2.TopK问题

相关文章:

6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)

目录 一.堆(Heap)的基本介绍 二.堆的常用操作&#xff08;以小根堆为例&#xff09; 三.实现代码 3.1 堆结构定义 3.2 向下调整算法* 3.3 初始化堆* 3.4 销毁堆 3.4 向上调整算法* 3.5 插入数据 3.6 删除数据 3.7 返回堆顶数据 四.下篇内容 1.堆排序 2.TopK问题 一…...

【智能终端】HBuilder X 与微信开发者工具集成与调试实战

目录 1. 需求和理解库、框架、平台 1.1 需求 1.2 理解 2.3 库、框架、平台 2.3.1 库&#xff08;Library&#xff09; 2.3.2 框架&#xff08;Framework&#xff09; 2.3.3 平台&#xff08;Platform&#xff09; 2.3.4 总结 2. 使用 HBuilder X 创建第一个 uni-app 应…...

结构体的字节对齐方式(__attribute_pack(packed))#pragma pack())

结构体的字节对齐方式&#xff08;__attribute_pack(packed))&#pragma pack()) 1、编译器的字节对齐方式 当前编译器都有默认的字节对齐方式&#xff0c; struct PackedStruct {char a;int b;short c; };如上代码段中的结构体&#xff0c;在编译运行后发现他的大小并不…...

若依Ruoyi之智能售货机运营管理系统(新增运营运维工单管理)

idea抽取独立方法快捷键&#xff1a;ctrlaltm TaskDto.java package com.dkd.manage.service.impl;import java.time.Duration; import java.util.List; import java.util.stream.Collectors;import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUti…...

ModuleNotFoundError: No module named ‘keras.layers.core‘怎么解决

问题 ModuleNotFoundError: No module named keras.layers.core&#xff0c;如图所示&#xff1a; 如何解决 将from keras.layers.core import Dense,Activation改为from tensorflow.keras.layers import Dense,Activation&#xff0c;如图所示&#xff1a; 顺利运行&#xf…...

C++(三)----内存管理

1.C/C内存分布 看下面这个问题&#xff08;考考你们之前学的咋样&#xff09;&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pCh…...

使用 ShuffleNet 模型在 CIFAR-100 数据集上的图像分类

简介 在深度学习领域&#xff0c;图像分类任务是衡量算法性能的重要基准。本文将介绍我们如何使用一种高效的卷积神经网络架构——ShuffleNet&#xff0c;来处理 CIFAR-100 数据集上的图像分类问题。 CIFAR-100 数据集简介 CIFAR-100 数据集是一个广泛使用的图像分类数据集&…...

怎么利用短信接口发送文字短信

在当今这个快节奏的数字时代&#xff0c;即时通讯已成为人们日常生活和工作中不可或缺的一部分。而短信接口&#xff08;SMS Interface&#xff09;&#xff0c;作为传统与现代通讯技术结合的典范&#xff0c;凭借其高效、稳定、广泛覆盖的特性&#xff0c;在众多领域发挥着不可…...

【C#生态园】提升C#开发效率:掌握这六款单元测试利器

从xUnit到SpecFlow&#xff1a;C#测试驱动开发全指南 前言 在C#开发中&#xff0c;单元测试和模拟框架是至关重要的工具&#xff0c;它们可以帮助开发人员确保代码的质量和可靠性。本文将介绍一些常用的C#单元测试框架和相关库&#xff0c;包括xUnit、NUnit、Moq、FluentAsse…...

【QT】自制一个简单的小闹钟,能够实现语音播报功能

做了一个自制的小闹钟&#xff0c;能够自己输入时间&#xff0c;以及对应的闹铃&#xff0c;时间到了自动播放设定的闹铃&#xff0c;可以随时取消重新设定&#xff0c;采用分文件编译 注意&#xff1a;需要在.pro文件中加入&#xff1a;QT core gui texttospeech 代码…...

基于深度学习的图像描述生成

基于深度学习的图像描述生成&#xff08;Image Captioning&#xff09;是一种将计算机视觉与自然语言处理结合的任务&#xff0c;其目标是通过自动生成自然语言来描述输入的图像。该技术能够理解图像中的视觉内容&#xff0c;并生成相应的文本描述&#xff0c;广泛应用于视觉问…...

Linux和C语言(Day11)

一、学习内容 讲解有参函数 形参 和 实参 形参——定义时的参数&#xff0c;形式上的参数&#xff0c;没有实际意义&#xff0c;语法上必须带有数据类型 void fun(int a,int b); void fun(int a[],int n); void fun(char *s); 可以是&#xff1a;变量、数组、指针 实参——调用…...

使用Zlib库进行多文件或者多文件夹的压缩解压缩

zlib库可在git上自己clone下来然后使用cmake工具生成解决方案&#xff0c;编译、生成zlib二进制文件。然后将zlib库引入项目&#xff1a; //zlib库支持 #include "../zlib/include/zlib.h" #ifdef _DEBUG #pragma comment(lib, "../zlib/lib/zlibd.lib") …...

CSGHub携手Nvidia NIM、阿里计算巢打造企业级私有化部署解决方案

强强联合 人工智能与大数据的迅速发展&#xff0c;大模型的推理应用和资产管理已成为企业数字化转型的重要组成部分&#xff0c;企业正寻求高效、安全的AI模型部署解决方案。为应对日益增长的计算需求和复杂的数据管理挑战&#xff0c;CSGHub、Nvidia和阿里云计算巢强强联手&a…...

opencv的球面投影

cv::detail::SphericalProjector 在全景图像拼接任务中&#xff0c;可能需要对多个图像进行球面投影以实现无缝拼接。每个cv::detail::SphericalProjector可以负责一个图像的球面投影操作。通过将多个这样的投影器存储在std::vector中&#xff0c;可以对一组图像依次进行投影处…...

5. 去中心化应用(dApp)

去中心化应用&#xff08;dApp&#xff09; 去中心化应用&#xff08;dApp&#xff09;是基于区块链技术构建的应用程序&#xff0c;其核心特性是去中心化、透明和开放。dApp与传统应用有许多显著的区别&#xff0c;它们在实现和功能上都带来了新的变革。以下是对dApp的详细介…...

k8s服务发布Ingress

Kubernetes暴露服务的方式目前只有三种&#xff1a;LoadBlancer Service、NodePort Service、Ingress&#xff0c;通俗来讲&#xff0c;ingress和之前提到的Service、Deployment&#xff0c;也是一个k8s的资源类型&#xff0c;ingress用于实现用域名的方式访问k8s内部应用。 In…...

区块链学习笔记1--比特币

区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。 从狭义上来说&#xff1a;区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学的方式保证的不可篡改和不可伪造的分布式账本。 意思就是…...

在 Vite 项目中自动为每个 Vue 文件导入 base.less

在 Vue.js 项目中&#xff0c;使用 Less 作为 CSS 预处理器时&#xff0c;我们通常会创建一个全局的样式文件&#xff08;如 base.less&#xff09;&#xff0c;用于存放一些全局变量、混合、通用样式等。为了避免在每个 Vue 组件中手动导入这个文件&#xff0c;我们可以通过配…...

RUST 学习之全局变量

RUST 全局变量 rust 全局变量编译期初始化的全局变量静态常量静态变量原子类型的静态变量 运行期初始化的全局变量lazy_staticBox::leakOnceCell & OnceLock 参考文档 rust 全局变量 编译期初始化的全局变量 静态常量 在编译期初始化&#xff0c;所以其赋值只能是表达式…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...