堆的基本实现

一、堆的概念

在提出堆的概念之前,首先要了解二叉树的基本概念

一颗二叉树是节点的有限集合,该集合:

1、或者为空;

2、或者由一个根节点加上两颗分别称为左子树和右子树的两颗子树构成;

 堆就是一颗完全二叉树;

堆有两种:小堆和大堆

堆在内存上的存储是数组形式的(物理结构);我们认为想象成链式结构(逻辑结构)

通过数组结构去实际存储,有这样的规律:每个父节点的下标乘以2加1就是左孩子节点,加2就是右孩子节点;无论是左孩子还是右孩子,其下标减去1再 /2 就是父节点的下标,这就是通过数组存储堆(完全二叉树)的优点。


 

 二、堆实现的相关头文件

#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
#include<errno.h>
//堆有两种:大堆、小堆
typedef int HPDataType;typedef struct Heap
{HPDataType* arr;int size;int capacity;
}Heap;//堆的构建
void HeapInit(Heap* php);//堆的销毁
void HeapDestroy(Heap* php);//向上调整
void AdjustUp(Heap* php, int child);
//堆的插入
void HeapPush(Heap* php, HPDataType x);//向下调整
void AdjustDown(Heap* php, int parent, int size);
//堆的删除
void HeapPop(Heap* php);//取出堆顶的数据
HPDataType HeapTop(Heap* php);//堆的数据个数
int HeapSize(Heap* php);//堆的判空
bool HeapEmpty(Heap* php);

堆是完全二叉树,所以用数组存储可以方便访问子节点和父节点;


三、堆基本接口的实现(大堆)

1、堆的构建(初始化)

void HeapInit(Heap* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}

2、堆的销毁

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

3、堆的插入

void HeapPush(Heap* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->arr,sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("realloc failed");exit(1);}php->arr = tmp;php->capacity = newcapacity;}php->arr[php->size++] = x;//向上调整AdjustUp(php->arr,php->size-1);
}

堆只有大堆和小堆之分,插入数据和顺序表一样,关键是插入数据之后要对数组里面的数据进行调整;

插入数据用到向上调整

//向上调整
void AdjustUp(HPDataType* arr,int child)
{int parent = (child - 1) / 2;while (child>0){if (arr[child] > arr[parent]){//交换数组里面的值Swap(&arr[child], &arr[parent]);//继续比较大小要将child和parent的值向上移动child = parent;parent = (child - 1) / 2;}else{//之前的数据都是一个一个建好的大堆//父节点的值比子节点的大,停止break;}}
}
void Swap(HPDataType* x, HPDataType* y)
{HPDataType tmp = *x;*x = *y;*y = tmp;
}

每次插入进堆的数据都是孩子节点(形参名称),向上调整的原因就是每个子树的父亲节点理论上是要大于孩子节点的,但是插入的数据可能要比父节点大,所以在向上调整函数里面要先通过孩子节点的下标找到对应的父节点,之后再比较看是否要交换,直到父亲节点大于子节点;

循环结束的条件是child>0,当child为0的时候说明已经调整到根节点的位置了。

4、堆的删除

//堆的删除
void HeapPop(Heap* php)
{assert(php && php->size>0);//删除是删除的是堆顶的数据,若是直接让数组整体往前移动 堆被打乱 要重新建堆 时间复杂度高;//方法:交换堆首位的数据,让size--,再从堆顶开始向下调整Swap(&php->arr[0],& php->arr[php->size - 1]);php->size--;AdjustDown(php->arr, 0, php->size - 1);
}

堆的删除删除的是根节点的数据,也就是数组里面下标为0的数据;如果直接移动数组下标删除,那么新数组就不再是一个堆,此时要重新建堆,代价过大;

采用这种方式:每次进行删除之前先交换堆首尾的数据,之后再让size--,就访问不到原来的根节点,此时得到的新数组,除了根节点处的数据,它的子树都是大堆;此时进行向下调整算法,把这个不应该是根节点的数据向下调整,把下面的数据里面最大的调整到根节点处;

向下调整算法

void AdjustDown(HPDataType* arr, int parent, int size)//size指向的是最后一个有效数据
{int child = parent * 2 + 1;//定义为左孩子while (child <= size){if (child+1<=size && arr[child] < arr[child + 1])//当最后一个子树只有左孩子时,child+1越界{child = child + 1;//若是右孩子较大,那么就定义成右孩子}//总是大的调到上面去if (arr[child] > arr[parent]){Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

向下调整是从下标为0处开始调整的,这个0下标位置就是父节点,通过乘以2加上1的办法找到子节点,但是要找到子节点里面较大的那个所以上面代码就有了child处和child+1处数据大小的比较,若是父节点小于子节点就交换;每次调整完都刷新父节点和子节点的下标,以便一直往下面调整直到父节点的数据要大于子节点的数据就停止;

循环结束的条件是child<size,这里的size是数组里面最后一个有效数的下标;

5、堆顶数据、堆的数据个数、堆的判空

//取出堆顶的数据
HPDataType HeapTop(Heap* php)
{assert(php && php->size>0);return php->arr[0];
}//堆的数据个数
int HeapSize(Heap* php)
{assert(php);return php->size;
}//堆的判空
bool HeapEmpty(Heap* php)
{assert(php);return php->size == 0;
}

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

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

相关文章

【Python系列】isin用法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

电脑屏幕录制软件哪个好?推荐3款,满足各种录制需求

大家好&#xff0c;今天和大家来聊一个既实用又有点神秘的话题——电脑屏幕录制软件哪个好&#xff1f;这是个让众多网友头疼的问题&#xff0c;毕竟谁不想拥有一款既好用又好玩的录制神器呢&#xff1f; 首先&#xff0c;我们得明确屏幕录制软件可不是简单地录屏而已&#xf…

VARIAN瓦里安真空Model 979 Leak Detector Instruction Manual使用说明

VARIAN瓦里安真空Model 979 Leak Detector Instruction Manual使用说明

杂项——电阻式角度传感器使用

三个引脚&#xff0c;分别接3.3V&#xff0c;GND&#xff0c;ADC引脚。12位ADC有4096份&#xff0c;将360分成4096份&#xff0c;再乘以单片机返回的模拟量的值&#xff0c;即可得到角度。 M0代码 #include "ti_msp_dl_config.h"volatile bool gCheckADC; volatile …

免费【2024】springboot 毕业生学历证明系统

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

【案例】使用React+redux实现一个Todomvc

About 大家好&#xff0c;我是且陶陶&#xff0c;今天跟大家分享一个redux的todoList案例&#xff0c;通过这个案例能够快速掌握redux的基本知识点&#x1f339; ❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…

微信小程序之计算器

在日常生活中&#xff0c;计算器是人们广泛使用的工具&#xff0c;可以帮助我们快速且方便地计算金额、成本、利润等。下面将会讲解如何开发一个“计算器”微信小程序。 一、开发思路 1、界面和功能 “计算器”微信小程序的页面效果如图所示 在计算器中可以进行整数和小数的…

C++学习笔记——模板

学习视频 文章目录 模板的概念函数模板函数模板语法函数模板注意事项函数模板案例普通函数与函数模板的区别普通函数与函数模板的调用规则模板的局限性 类模板类模板与函数模板区别类模板中成员函数创建时机类模板对象做函数参数类模板与继承类模板成员函数类外实现类模板分文件…

box-shadow属性的复合写法及高级用法,超详细!

前言&#xff1a;最近又叕看到了一个好看的特效&#xff0c;随后整理了一下&#xff0c;发现实现起来主要靠一个css属性就实现了&#xff0c;有一次刷新了我对css强大的认知&#x1f60e;&#xff0c;这个属性就是box-shadow&#xff0c;平常我们用到的比较少&#xff0c;但是针…

oracle中存储过程的写法

存储过程常规语法&#xff1a; 实际业务例子&#xff1a; CREATE OR REPLACE TRIGGER "TRI_B00_02_ONLY_GUID" BEFORE/AFTER INSERT OR UPDATE OR DELETE ON B00_02 FOR EACH ROW declare t_guid varchar2(300) : ; --GUID t_cnt int : 0; BEGIN t_guid : :NEW…

【深度学习】大模型GLM-4-9B Chat ,微调与部署(1)

下载好东西&#xff1a; 启动容器环境: docker run -it --gpus all --net host --shm-size8g -v /ssd/xiedong/glm-4-9b-xd:/ssd/xiedong/glm-4-9b-xd kevinchina/deeplearning:pytorch2.3.0-cuda12.1-cudnn8-devel-yolov8train bashpip install typer tiktoken numpy1.2…

ROS2入门到精通—— 2-11 ROS2实战:实现基于voronoi_planner的全局规划(一)!!!保姆级教程

实现基于voronoi_planner的全局规划将分为两篇博文进行讲解 本文参考该大佬代码: https://github.com/nkuwenjian/voronoi_planner.githttps://github.com/nkuwenjian/voronoi_layer.git将上面的ROS1代码移植到ROS2,移植不易,中间遇到很多坑 0 前言 针对一些狭窄区域,可能…

【机器学习】梯度下降的基本概念和如何使用梯度下降自动化优化w和b

引言 梯度下降是一种用于寻找函数最小值的优化算法&#xff0c;它在机器学习中广泛用于训练模型&#xff0c;如线性回归、神经网络等 一、梯度下降的基本概念 1.1 目标函数 在机器学习中&#xff0c;这通常是损失函数&#xff08;如均方误差、交叉熵等&#xff09;&#xff0…

深度学习趋同性的量化探索:以多模态学习与联合嵌入为例

深度学习趋同性的量化探索&#xff1a;以多模态学习与联合嵌入为例 参考文献 据说是2024年最好的人工智能论文&#xff0c;是否有划时代的意义&#xff1f; [2405.07987] The Platonic Representation Hypothesis (arxiv.org) ​arxiv.org/abs/2405.07987 趋同性的量化表达 …

Pytorch使用教学7-张量的广播

PyTorch中的张量具有和NumPy相同的广播特性&#xff0c;允许不同形状的张量之间进行计算。 广播的实质特性&#xff0c;其实是低维向量映射到高维之后&#xff0c;相同位置再进行相加。我们重点要学会的就是低维向量如何向高维向量进行映射。 相同形状的张量计算 虽然我们觉…

JAW:一款针对客户端JavaScript的图形化安全分析框架

关于JAW JAW是一款针对客户端JavaScript的图形化安全分析框架&#xff0c;该工具基于esprima解析器和EsTree SpiderMonkey Spec实现其功能&#xff0c;广大研究人员可以使用该工具分析Web应用程序和基于JavaScript的客户端程序的安全性。 工具特性 1、动态可扩展的框架&#x…

模拟ADG主库归档文件丢失,备库出现gap(增量备份解决)

文章目录 一、说明二、环境信息2.1.主备库环境信息2.2.检查主备是否同步正常 三、模拟日志断档3.1.模拟主库归档文件丢失3.2 查看主库状态出现GAP 四、RMAN增量备份恢复备库同步4.1 RMAN增量恢复备库4.2 开启备库redo同步4.3 主备库验证同步 一、说明 模拟Oracle主库归档文件丢…

Git基本原理讲解、常见命令、Git版本回退、Git抛弃本地分支拉取仓库最新分支

借此机会写篇博客汇总一下自己去公司实习之后遇到的一些常见关于Git的操作。 Git基本认识 Git把数据看作是对小型文件系统的一组快照&#xff0c;每次提交更新&#xff0c;或在Git中保存项目状态时&#xff0c;Git主要对当时的全部文件制作一个快照并保存这个快照的索引。同时…

【C++】选择结构案例-三只小猪称体重

案例问题 假设有三只小猪A、B、C&#xff0c;在输入三者体重后希望能输出他们各自的体重并测出谁最重 思路 先让A与B相比较&#xff0c;如果A重&#xff0c;则让A和C相比较&#xff0c;如果A重则输出A最重&#xff0c;否则输出C最重 在最开始的条件&#xff08;AB相比较&am…

浅谈Devops

1.什么是Devops DevopsDev&#xff08;Development&#xff09;Ops&#xff08;Operation&#xff09; DevOps&#xff08;Development和Operations的混合词&#xff09;是一种重视“软件开发人员&#xff08;Dev&#xff09;”和“IT运维技术人员&#xff08;Ops&#xff09;”…