深入理解数据结构——堆

 前言:

在前面我们已经学习了数据结构的基础操作:顺序表和链表及其相关内容,今天我们来学一点有些难度的知识——数据结构中的二叉树,今天我们先来学习二叉树中堆的知识,这部分内容还是非常有意思的,下面我们就开始慢慢学习

准备工作:本人习惯将文件放在test.c、SeqList.c、SeqList.h三个文件中来实现,其中test.c用来放主函数,SeqList.c用来放调用的函数,SeqList.h用来放头文件和函数声明

一、什么是树

在正式进行二叉树的学习之前,我们要了解一下树是何物,其实我们经常讲到的计算机中的树其实是以数组的形式存在在内存中的,只是它的可以形象化成树的形状,如下:

如图,其中0所在位置被称为树顶或者树根都可以,下面的称为子树,其中1所在分叉称为左子树,2所在分叉成为右子树

还有一些规则如下:

对于学过离散数学的同学来说这部分知识并不难,没有学过的自己再去搜一下了解一下吧,这里只讲了一些大概内容

二、什么是堆

树里面有几个特殊的概念,例如完全二叉树和满二叉树,而堆就是完全二叉树的一种,完全二叉树就是除了最后一层外,其他层节点数达到最大

堆与普通的完全二叉树的不同在于它的大小堆的性质

大堆:树任何一个父亲>=孩子

小堆:树任何一个父亲<=孩子

例如:

三、堆的节点结构

堆用的顺序表的结构,所以堆的节点结构与顺序表差异不大

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int sz;int capacity;
}HP;

堆的节点结构很简单,定义一个指针,两个表示容量的整形即可

四、堆的基本操作

//初始化
void HeapInit(HP* php);
//销毁
void HeapDestory(HP* php);
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//找堆顶元素
HPDataType HeapTop(HP* php);
//判断是否为空
bool HeapEmpty(HP* php);
//算个数
int HeapSize(HP* php);

看上面的函数声明部分我们就可以看到我们每一步要实现的内容,接下来,我们就来一步一步进行实现

1、初始化

//初始化
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->capacity = 0;php->sz = 0;
}

2、销毁

//销毁
void HeapDestory(HP* php)
{free(php->a);free(php);
}

3、插入元素

插入元素时要先检查空间是否够用,如果不够用要先进行扩容

//交换
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//删除//向上调整(小堆)
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 AdjustDown(int* 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 HeapPush(HP* php, HPDataType x)
{assert(php);if (php->sz == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);php->a = tmp;php->capacity = newcapacity;}php->a[php->sz] = x;php->sz++;//向上调整AdjustUp(php->a, php->sz - 1);
}

在这一步我们还创建了几个其他的函数分担一些功能,这些函数在后文中也有应用

4、判断栈顶元素是否为空

这一步在下面有用到,例如当删除树根元素时,如果树根元素为空就无法操作,所以需要判断树根元素是否为空

//判断是否为空
bool HeapEmpty(HP* php)
{assert(php);return php->sz == 0;
}

5、删除元素

这里删除元素是删除树根元素

//删除
void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));Swap(&php->a[0], &php->a[php->sz - 1]);php->sz--;//向下调整AdjustDown(php->a, php->sz,0);
}

6、返回树根元素

//找堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);assert(!HeapEmpty(php));return php->a[0];
}

7、算个数

//算个数
int HeapSize(HP* php)
{assert(php);return php->sz;
}

五、完整代码实例

SeqList.h

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int sz;int capacity;
}HP;//初始化
void HeapInit(HP* php);
//销毁
void HeapDestory(HP* php);
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//找堆顶元素
HPDataType HeapTop(HP* php);
//判断是否为空
bool HeapEmpty(HP* php);
//算个数
int HeapSize(HP* php);

test.c

//堆
int main()
{HP hp;HeapInit(&hp);int a[] = { 65,100,70,32,50,60 };for (int i = 0; i < sizeof(a) / sizeof(int); i++){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){int top = HeapTop(&hp);printf("%d ", top);HeapPop(&hp);}return 0;
}

SeqList.c

//堆
//初始化
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->capacity = 0;php->sz = 0;
}
//销毁
void HeapDestory(HP* php)
{free(php->a);free(php);
}
//交换
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//删除//向上调整(小堆)
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 AdjustDown(int* 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 HeapPush(HP* php, HPDataType x)
{assert(php);if (php->sz == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);php->a = tmp;php->capacity = newcapacity;}php->a[php->sz] = x;php->sz++;//向上调整AdjustUp(php->a, php->sz - 1);
}
//删除
void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));Swap(&php->a[0], &php->a[php->sz - 1]);php->sz--;//向下调整AdjustDown(php->a, php->sz,0);
}
//判断是否为空
bool HeapEmpty(HP* php)
{assert(php);return php->sz == 0;
}
//找堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);assert(!HeapEmpty(php));return php->a[0];
}
//算个数
int HeapSize(HP* php)
{assert(php);return php->sz;
}

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

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

相关文章

前端秘法番外篇----学完Web API,前端才能算真正的入门

目录 一.引言 二.元素的获取和事件 1.获取元素 2.各种事件 2.1点击事件 2.2键盘事件 三.获取&修改操作 1.获取修改元素属性 2.修改表单属性 2.1暂停播放键的转换 2.2计数器的实现 2.3全选的实现 3.样式操作 3.1行内样式操作 3.2类名样式操作 四.节点 1.创…

记录Xshell使用ed25519公钥免密链接SSH

试了半天&#xff0c;Xshell好像没办法导入linux生成的ssh公钥,因此需要以下步骤实现免密登录 结论&#xff0c;在linux公钥文件中&#xff0c;将客户端生成的ed25519公钥加上去即可(一个公钥单独一行) 1.使用Linux生成秘钥文件(不需要输入私钥密码passphrase)或者直接创建一…

【Servlet】继承关系以及service方法

文章目录 一、继承关系二、相关方法 一、继承关系 Servlet接口下有一个GenericServlet抽象类。在GenericServlet下有一个子类HttpServlet&#xff0c;它是基于http协议。 继承关系 javax.servlet.Servlet接口​ javax.GenericServlet抽象类​ javax.servlet.http.HttpServ…

生产制造园区数字孪生3D大屏展示提升运营效益

在智慧园区的建设中&#xff0c;3D可视化管理平台成为必不可少的工具&#xff0c;数字孪生公司深圳华锐视点打造的智慧园区3D可视化综合管理平台&#xff0c;致力于将园区的人口、经济、应急服务等各项业务进行3D数字化、网络化处理&#xff0c;从而实现决策支持的优化和管理的…

C++多线程:Atomic原子类与CAS锁详解(十)

1、原子操作的概念 什么是原子操作&#xff1a; 原子被认为是构成物质最小的单位&#xff0c;是不可分割的一个东西。而在程序中原子操作被认为是不可分割的一个步骤或者指令其实我们很简单的程序&#xff0c;在高级语言中被认为是一个步骤的操作&#xff0c;编译成汇编指令之…

Redis从入门到精通(三)Jedis客户端、SpringDataRedis客户端

文章目录 前言第3章 Redis的Java客户端3.1 Jedis客户端3.1.1 快速使用3.1.2 连接池 3.2 SpringDataRedis客户端3.2.1 快速使用3.2.2 自定义序列化3.2.3 StringRedisTemplate 3.3 小结 前言 在上一章【Redis从入门到精通(二)Redis的数据类型和常见命令介绍】中&#xff0c;学习…

Springboot+MybatisPlus+EasyExcel实现文件导入数据

记录一下写Excel文件导入数据所经历的问题。 springboot提供的文件处理MultipartFile有关方法&#xff0c;我没有具体看文档&#xff0c;但目测比较复杂&#xff0c; 遂了解学习了一下别的文件上传方法&#xff0c;本文第1节记录的是springboot原始的导入文件方法写法&#xf…

docker-compse安装es(包括IK分词器扩展)、kibana、libreoffice

Kibana是一个开源的分析与可视化平台&#xff0c;设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。 Kibana与Elasticsearch的交互方式是各种不同的图表、表格、地图等&#xff0c;直观的展示数据&#xff0c;从而达到高级的数据…

MySQL 优化及故障排查

目录 一、mysql 前置知识点 二、MySQL 单实例常见故障 故障一 故障二 故障三 故障四 故障五 故障六 故障七 故障八 三、MySQL 主从故障排查 故障一 故障二 故障三 四、MySQL 优化 1.硬件方面 &#xff08;1&#xff09;关于 CPU &#xff08;2&#xff09;关…

Reversing Linked List

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K3, then you must output 3→2→1→6→5→4; if K4, you must output 4→3→2→1→5→6. Input Specifi…

网络基础——ISIS

名词 ISIS&#xff1a;中间系统到中间系统&#xff0c;优先级是15集成化ISIS&#xff1a;这是在优化后&#xff0c;可以使用在OSI模型上的NET地址&#xff1a;由区域ID、系统ID和SEL组成&#xff0c;一台设备上最多配置3个NET地址&#xff0c;条件是区域号要不一致&#xff0c;…

Intel FPGA (7):adc adc128s102

Intel FPGA (7)&#xff1a;adc adc128s102 前提摘要 个人说明&#xff1a; 限于时间紧迫以及作者水平有限&#xff0c;本文错误、疏漏之处恐不在少数&#xff0c;恳请读者批评指正。意见请留言或者发送邮件至&#xff1a;“Email:noahpanzzzgmail.com”。本博客的工程文件均存…

用Python实现办公自动化(自动化处理PDF文件)

自动化处理 PDF 文件 目录 自动化处理 PDF 文件 谷歌浏览器 Chrome与浏览器驱动ChromeDriver安装 &#xff08;一&#xff09;批量下载 PDF 文件 1.使用Selenium模块爬取多页内容 2.使用Selenium模块下载PDF文件 3.使用urllib模块来进行网页的下载和保存 4.使用urllib…

关于OcenaBase v4.2中,分区转移和负载均衡的技术解读

OceanBase​​​​​​​​​​​​​​作为一款原生分布式数据库&#xff0c;其核心的技术特性之一是高可扩展性&#xff0c;其具体表现在两个方面&#xff1a; 首先&#xff0c;是灵活的扩缩容能力&#xff0c;包括垂直扩缩容和水平扩缩容&#xff1a; 垂直扩缩容&#xff…

神经网络汇聚层

文章目录 最大汇聚层平均汇聚层自适应平均池化层 最大汇聚层 汇聚窗口从输入张量的左上角开始&#xff0c;从左往右、从上往下的在输入张量内滑动。在汇聚窗口到达的每个位置&#xff0c;它计算该窗口中输入子张量的最大值或平均值。计算最大值或平均值是取决于使用了最大汇聚…

RISC-V/ARM mcu OpenOCD 调试架构解析

Risc-v/ARM mcu OpenOCD 调试架构解析 最近有使用到risc-v的单片机&#xff0c;所以了解了下risc-v单片机的编译与调试环境的搭建&#xff0c;面试时问到risc-v的调试可参看以下内容。 risc-v根据官方的推荐&#xff0c;调试器服务是选择OpenOCD&#xff0c;DopenOCD(开放片上…

Python反爬案例——验证码的识别

验证码的识别 使用打码平台识别验证码 利用打码平台可以轻松识别各种各样的验证码&#xff0c;图形验证码、滑动验证码、点选验证码和逻辑推理验证码。打码平台提供了一系列API&#xff0c;只需要向API上传验证码图片&#xff0c;它便会返回对应的识别结果。 使用超级鹰平台…

深入理解指针1:指针变量、指针运算、野指针、const修饰指针

生活中我们把门牌号也叫地址&#xff0c;在计算机中我们把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫&#xff1a;指针。 所以我们可以理解为&#xff1a;内存单元的编号地址指针 1、指针变量 我们知道的是&#xff1a;数组名是数组首元素的地址。也就是说&…

中断服务程序模板

通常定时器初始化过程如下: ①对 TMOD赋值,以确定TO和T1的工作方式。 ②计算初值,并将初值写入THO、TLO或TH1、TL1。 ③中断方式时&#xff0c;则对IE赋值&#xff0c;开放中断。 ④使TRO或TR1置位&#xff0c;启动定时器/计数器定时或计数。 代码 利用定时器0工作方式1&…

轻松设置Facebook自动隐藏评论和删除评论功能

Facebook作为海外营销的最大流量平台之一&#xff0c;是很多跨境卖家争夺的市场&#xff0c;希望可以通过Facebook这个全球性的平台来推广自己的产品或服务。身处这个竞争激烈的市场&#xff0c;任何一条负面评论或不当言论出现在你的品牌页面上都可能影响到品牌形象&#xff0…