堆的基本操作(c语言实现)

 1.堆的基本操作

1.1定义堆

typedef int HPDataType;//堆中存储数据的类型typedef struct Heap
{HPDataType* a;//用于存储数据的数组int size;//记录堆中已有元素个数int capacity;//记录堆的容量
}HP;

1.2初始化堆

然后我们需要一个初始化函数,对刚创建的堆进行初始化,注意在初始化期间要将传入数据建堆。

//初始化堆
void HeapInit(HP* php, HPDataType* a, int n)
{assert(php);HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType)*n);//申请一个堆结构if (tmp == NULL){printf("malloc fail\n");exit(-1);}php->a = tmp;memcpy(php->a, a, sizeof(HPDataType)*n);//拷贝数据到堆中php->size = n;php->capacity = n;int i = 0;//建堆for (i = (php->size - 1 - 1) / 2; i >= 0; i--){AdjustDown(php->a, php->size, i);}
}

1.3 销毁堆

 为了避免内存泄漏,使用完动态开辟的内存空间后都要及时释放该空间,所以,一个用于释放内存空间的函数是必不可少的。

//销毁堆
void HeapDestroy(HP* php)
{assert(php);free(php->a);//释放动态开辟的数组php->a = NULL;//及时置空php->size = 0;//元素个数置0php->capacity = 0;//容量置0
}

1.4打印堆

 打印堆中的数据,这里用的打印格式是按照堆的物理结构进行打印,即打印为一排连续的数字。

//打印堆
void HeapPrint(HP* php)
{assert(php);//按照物理结构进行打印int i = 0;for (i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}

1.5堆的插入

数据插入时是插入到数组的末尾,即树形结构的最后一层的最后一个结点,所以插入数据后我们需要运用堆的向上调整算法对堆进行调整,使其在插入数据后仍然保持堆的结构。

void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType) * php->capacity*2);if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity *= 2;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

 这个插入的效果完全取决于AdjustUp函数是给大堆设计的还是小堆!!

1.6堆的删除

堆的删除操作通常指的是从堆中移除最大值或最小值的操作。

在最大堆中,根节点是最大的元素,而在最小堆中,根节点是最小的元素。

以下是堆的删除操作的基本思路:

  1. 首先,将堆顶元素(即根节点)与最后一个元素交换位置,即将最大值或最小值移动到数组的末尾。
  2.  然后,将堆的大小减1,即删除了原来堆顶的元素。
  3. 最后,对新的堆顶元素进行向下调整,以保持堆的性质。在最大堆中,需要将新堆顶元素与其子节点中的较大者交换,直到满足最大堆的性质;在最小堆中,需要将新堆顶元素与其子节点中的较小者交换,直到满足最小堆的性质。

通过以上步骤,可以实现堆的删除操作,并保持堆的性质不变。

//堆的删除
void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));Swap(&php->a[0], &php->a[php->size - 1]);//交换堆顶和最后一个结点的位置php->size--;//删除最后一个结点(也就是删除原来堆顶的元素)AdjustDown(php->a, php->size, 0);//向下调整
}

这段代码是堆的删除操作,基本思路如下:

1. 首先,通过断言(assert)确保传入的堆指针(php)不为空,并且堆不为空。
2. 然后,将堆顶元素(索引为0的元素)与最后一个元素进行交换,即将堆顶元素移动到数组的末尾。
3. 接着,将堆的大小减1,即删除了原来堆顶的元素。
4. 最后,调用AdjustDown函数对新的堆顶元素进行向下调整,以保持堆的性质。

1.7.获取堆的数据个数

获取堆的数据个数,即返回堆结构体中的size变量。

//获取堆中数据个数
int HeapSize(HP* php)
{assert(php);return php->size;//返回堆中数据个数
}

1.8堆的判空

堆的判空,即判断堆结构体中的size变量是否为0。

//堆的判空
bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;//判断堆中数据是否为0
}

2.完整操作加测试代码

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType x = *p1;*p1 = *p2;*p2 = x;
}//堆的向下调整(小堆)—— 左右子树都是小堆
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;}}
}
//初始化堆
void HeapInit(HP* php, HPDataType* a, int n)
{assert(php);HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * n);//申请一个堆结构if (tmp == NULL){printf("malloc fail\n");exit(-1);}php->a = tmp;memcpy(php->a, a, sizeof(HPDataType) * n);//拷贝数据到堆中php->size = n;php->capacity = n;int i = 0;//建堆for (i = (php->size - 1 - 1) / 2; i >= 0; i--){AdjustDown(php->a, php->size, i);}
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}
void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}//堆的向上调整(小堆)
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 = (child - 1) / 2;}else//已成堆{break;}}
}void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity *= 2;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}//打印堆
void HeapPrint(HP* php)
{assert(php);//按照物理结构进行打印int i = 0;for (i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));// 删除数据Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HeapTop(HP* php)
{assert(php);return php->a[0];
}int HeapSize(HP* php)
{assert(php);return php->size;
}
int main()
{HP hp;int a[] = { 4,18,42,12,21,3,5,5,88,5,5,15,5,45,5 };int size = sizeof(a) / sizeof(a[0]);HeapInit(&hp,a,size);HeapPrint(&hp);HeapPop(&hp);HeapPrint(&hp);HeapPush(&hp, 4);HeapPrint(&hp);return 0;
}

我们可以来验证一下是不是堆

  1. 堆的向上调整和向下调整的代码一定要是匹配的,小堆的只能和小堆匹配使用,大堆的只能和大堆匹配使用,要不然就会让你十分抓马 ,我就是因为错误匹配使用就导致了痛苦了两个晚上……
  2. 还有就是大家一定要去画图去验证一下这个是不是堆,不要用眼睛看
  3. 其次就是一定要建好堆后再使用堆的向上调整和向下调整

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

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

相关文章

【C语言】路漫漫其修远兮,深入[指针]正当下

一. 指针初步 1.概念定义 地址&#xff1a;我们在内存中开辟空间时&#xff0c;为了方便后续访问&#xff0c;每个数据有确切的地址。 指针&#xff1a;指向数据的地址&#xff0c;并将其地址储存在指针变量中。 2.基本运算符 • 取地址操作符&#xff08;&&#xff09; …

【强化学习入门】基于DDPG的强化学习控制器设计

最近在看控制领域研究热门–强化学习相关的东西&#xff0c;跟着matlab官方强化学习教程一边看一边学&#xff0c;感觉入门门槛略高&#xff0c;需要补很多机器学习相关的知识&#xff0c;高数概率论那些&#xff0c;摸索了个把月感觉现在只大概会用&#xff0c;原理啥的还没搞…

进口家装水管十大品牌哪家好,弗锐德为您推荐进口家装水管领先十大品牌

水管作为家装隐蔽工程之一&#xff0c;选对一款优质的水管是至关重要的&#xff0c;毕竟好的水管能够保证家庭后续几十年的用水安全和健康。今天&#xff0c;小编就和大家说说进口家装水管十大品牌哪家好&#xff1f; 目前国内进口家装水管具有知名度和消费者认可的品牌有&…

自制一个3D打印的移动终端——T3rminal

T3rminal是我过去几个月一直在努力开发的一个CyberDeck&#xff0c;并希望将其开源。 我从不同设备如Decktility、YARH和其他项目中获得了灵感。 你可以在我的Github上协助并关注该项目&#xff1a;https://github.com/crazycaleb2008/T3rminal/tree/main/3D%20Models 材料 …

Edge的使用心得和深度探索-Sider: ChatGPT 侧边栏

作为一款备受欢迎的网络浏览器&#xff0c;Microsoft Edge在用户体验和功能方面都有着诸多优势。在长期的使用中&#xff0c;我总结出了三条使用心得&#xff0c;同时也发现了三个能够极大提高效率的功能。让我们一起深度探索Edge的潜力吧&#xff01; 使用心得&#xff1a; 界…

Spring 常用的注入方式有什么?

Spring 是一个非常流行的 Java 开发框架&#xff0c;它提供了多种依赖注入&#xff08;Dependency Injection&#xff09;的方式&#xff0c;使得开发者可以轻松地管理应用程序中的组件依赖关系。在 Spring 中&#xff0c;常用的注入方式主要包括构造器注入、Setter 方法注入、…

【测试报告】星光日册

⭐ 作者&#xff1a;Jwenen &#x1f331; 作者主页&#xff1a;Jwenen的个人主页 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 测试报告 1. 项目介绍2. 测试用例框架3. 自动化测试源码 1. 项目介绍 “星光日册”项目实现了用…

继续SQL

主知识点六&#xff1a;having 聚合前的筛选用where&#xff0c;聚合后的筛选用having Having和where的区别是&#xff1a;运行顺序和对象不用 Having是在group by聚合后的基础上进行筛选。 ● 【例题27*】&#xff08;运行原理&#xff09;查询总人口数至少为3亿的大洲和…

vxe-table 区域选取、复制粘贴功能,的基本使用

vxe-table区域选取、复制粘贴功能&#xff0c;的基本使用&#xff08;注&#xff1a;该功能仅支持企业版&#xff0c;这里仅供部分演示&#xff09; 1.鼠标区域选择功能&#xff1a; 参数说明&#xff1a; mouse-config.area 是否开启鼠标单元格区域选取 <template>&l…

详解基于 RAG 的 txt2sql 全过程

前文 本文使用通义千问大模型和 ChromaDB 向量数据库来实现一个完整的 text2sql 的项目&#xff0c;并基于实际的业务进行效果的展示。 准备 在进行项目之前需要准备下面主要的内容&#xff1a; python 环境通义千问 qwen-max 模型的 api-keyChromaDB 向量数据库acge_text_…

Linux-笔记 uboot修改设备树

1. FDT介绍 扁平设备树&#xff08;Flattened Device Tree&#xff0c;FDT&#xff09;&#xff0c;也叫平坦设备树&#xff0c;是设备树的一种二进制表示形式&#xff0c;提高了在嵌入式系统中的传输和解析效率&#xff1b; 2. 在U-Boot中使用FDT 2.1. 进入U-Boot 开发板上…

OpenCV 入门(四)—— 车牌号识别

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

【论文阅读】VMamba: Visual State Space Model

VMamba:视觉状态空间模型 code&#xff1a;https://github.com/MzeroMiko/VMamba Background ​ CNN拥有线性复杂度因而可以处理高分辨率的图像&#xff0c;而ViT在拟合能力方面超过了CNN&#xff0c;但ViT是二次复杂度&#xff0c;在处理高分辨率图像时计算开销较大。ViT通过…

Wappalyzer指纹识别下载安装使用教程,图文教程(超详细)

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Windows平台通过MobaXterm远程登录安装在VMware上的Linux系统(CentOS)

MobaXterm是一个功能强大的远程计算工具&#xff0c;它提供了一个综合的远程终端和图形化的X11服务器。MobaXterm旨在简化远程计算任务&#xff0c;提供了许多有用的功能&#xff0c;使远程访问和管理远程服务器变得更加方便&#xff0c;它提供了一个强大的终端模拟器&#xff…

钉钉开放平台创建企业内部H5微应用或者小程序

前言&#xff1a; 在当今企业数字化转型的浪潮中&#xff0c;创建企业内部H5微应用或小程序已成为提升工作效率和促进内部沟通的重要举措。发话不多说本文将介绍如何利用钉钉平台快速创建这些应用&#xff0c;让企业内部的工作更加便捷高效。 步骤 1.在浏览器打开链接…

【解决】Android APK文件安装时 已包含数字签名相同APP问题

引言 在开发Android程序过程中&#xff0c;编译好的APK文件&#xff0c;安装至Android手机时&#xff0c;有时会报 包含数字签名相同的APP 然后无法安装的问题&#xff0c;这可能是之前安装过同签名的APP&#xff0c;但是如果不知道哪个是&#xff0c;无法有效卸载&#xff0c;…

ESD静电问题 | 更换接口芯片

【转发微信公众号&#xff1a;EMC容冠电磁】

VMare Workstation安装ubuntu虚拟机异常问题处理

安装方法 ubuntu官网下载插件 异常处理 开启时报错"unable to proceed without a log file" 遇到此问题的都有一个共同点&#xff0c;工作目录路径上都带了数字&#xff0c;比如"Ubuntu 64位 01"&#xff0c;解决方法为&#xff1a; 选中"Ubuntu 64位…

用得助全媒体呼叫中心,让AI落到实处帮品牌做营销

怎么让人工智能落到实处的帮助到我们&#xff1f;我们今天来讲讲中关村科金得助全媒体呼叫中心是怎么让AI帮品牌。 这次聊的案例是知名的护肤品牌&#xff0c;该品牌在中国功能性护肤品市场占有率达到20.5%&#xff0c;这么高的市场占有率客户的咨询量也是非常庞大的&#xff0…