《堆》的模拟实现

目录

前言:

模拟实现《堆》:

1.自定义数据类型

2.初始化“堆”

3.销毁“堆”

4.进“堆”

关于AdjustUp()

5.删除堆顶元素

关于AdjustDown()

6.判断“堆”是否为空

7.求“堆”中的数据个数 

8.求“堆”顶元素

总结:


前言:

我们在上一篇的blog中对于《树》有了初步的认识,树的包含多种数据结构,其中我们现阶段最适合引入“堆”的概念,我们同时也在上一篇的blog中的最后引入并介绍了“堆”的相关概念,了解到了小堆以及大堆。具体内容可以参考上一篇blog:

初识《树》-CSDN博客

本次blog就以小堆为例,动手模拟开辟出一个“小堆”!

模拟实现《堆》:

1.自定义数据类型

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

是的,本次堆的实现我们利用到了顺序表的存储概念,我们在后面会讲到为什么要使用顺序表。

2.初始化“堆”

void HeapInit(HP* php)
{php->a = NULL;php->capacity = php->size = 0;
}

3.销毁“堆”

void HeapDestory(HP* php)
{assert(php);php->size = php->capacity = 0;free(php->a);
}

 初始化和销毁这两个函数在我们之前的blog中有讲解,而且内容相差不大所以我们在这里不给予讲解,我也不再进行过多赘述。

4.进“堆”

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

这里的开头也是与之前的顺序表一致,不同的地方在于我们创建了一个AdjustUp函数。

接下来我们就来讲解此函数:

关于AdjustUp()

void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void AdjustUp(HPDataType* a, int child)
{while (child > 0){int parent = (child - 1) / 2;if (a[parent] > a[child]){swap(&a[parent], &a[child]);}child = parent;}
}

 我们先假设有一个数组,数组元素2,4,5,1,3

现在想要建小堆并让这些数据进“堆”,

还明显,该树并不是堆,既不满足小堆,更不满足堆!

所以我们需要进行调整,所以就有了向上调整法即AdjustUp()

具体的思路:

1.每插入一个数据,就于父亲节点相比较

2.如果父亲节点>孩子节点 那么数据进行交换,由于这是顺序表所以就是数组下标进行交换,同时注意我们在实现交换函数时,传递的是地址

在此我用图来展示:

此时遍历到1这个小标,因为随着数据的添加,size也会++,所以数据1的下标就为size-1

那么我们就让size-1下标即数据1的位置座位child。

而我们想要找到数据1的父亲节点,不难得出公式

parent = (child - 1)/2

 则可找到数据4作为父亲节点,然后进行交换,即:

虽然交换完了数据1和数据4的节点,但是这还不是一个合格的堆,因此我们还要继续进行操作,这个时候我们的child就可以挪动到parent的位置即:

 

 

我们先要将数据1和数据2进行交换,交换完后才是一个小堆,所以这就是while循环在此的作用,而限制条件显而易见就是child不在首元素时状态。

所以parent = (child - 1) / 2

 

进行交换则有:

 

如此就是一个小堆了

 

5.删除堆顶元素

void HeapPop(HP* php)
{assert(php);//交换头尾元素swap(&php->a[0], &php->a[php->size - 1]);php->size--;//向下调整AdjustDown(php->a, php->size, 0);
}

在我们熟悉进“堆”操作后,我们不妨来实现实现删除堆顶数据,具体的操作思路如下:

1.将首元素数据和最后一个数据交换。

2.再调整堆使其完善成小堆。

第一个步骤好理解,接下来我们就来介绍我们的第二个函数,AdjustDown()

关于AdjustDown()

void AdjustDown(HPDataType* a, int sz, int parent)
{int child = 2 * parent + 1;while (child < sz){if (child + 1 < sz && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){swap(&a[child], &a[parent]);parent = child;}else{break;}}
}

就拿刚刚的堆来举例,如图:

 先进行首尾互换,则有:

此时我们先让size-- 

目的是为了不管最后一个元素一,即:

可此时并不是一个合格的小堆,但是我们此时不能使用 向上调整法了,因为如果我们首元素一旦是一个很大的数,拿8举例,执行交换就是8和2进项交换,但是8仍然大于4,所以向上调整法不适用这里,因此我们可以得知向上调整法是适用于建堆!

那我们就要利用一种新的思路:

1.从首元素开始向下调整。

2.判断左孩子和右孩子的数哪个更小

3.取小的开始不断交换

我们在这里用图来说明:

我们在此是传递首元素,即父亲进来,那么我们可以通过公式

child = 2*parent + 1

找出左孩子的节点,然后进行判断:

此时很明显左孩子小于右孩子所以进行判断

此时2<3所以进行交换

 

然后继续往下判断,parent = child;

 

继续通过公式有:

 

最后就有:

 

此时child还会继续找下一个数据,可是后续的数据就不是我们的数组内容了,因此交换的条件应当是child< size才能进行交换。

以上这两个函数就是本文的核心精华内容!

 

6.判断“堆”是否为空

bool HeapEmpty(HP* php)
{assert(php);if (php->size == php->capacity){return true;}return false;
}

7.求“堆”中的数据个数 

int HeapSize(HP* php)
{assert(php);return php->size;
}

8.求“堆”顶元素

int HeapTop(HP* php)
{assert(php);if (!HeapEmpty(php)){return php->a[0];}exit(-1);
}

总结:

以上就是《堆》的模拟实现的全部内容,我们在实现AdjustUp函数和AdjustDown函数时不难发现,我们要经常找到上一个父亲节点的数据,所以我们才采取顺序表的结构来帮助我们查找。

下一篇的blog我们利用堆这一结构解决问题,包括《堆排序》,《Top-K》。

记住“坐而言不如起而行”

Action speak louder than words!

本文的代码在我的Gitee仓库:

Data structures amd algorithms: 关于数据结构和算法的代码 - Gitee.com

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

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

相关文章

DOM 事件的传播机制

前端面试大全DOM 事件的传播机制 &#x1f31f;经典真题 &#x1f31f;事件与事件流 事件流 事件冒泡流 事件捕获流 标准 DOM 事件流 &#x1f31f;事件委托 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 谈一谈事件委托以及冒泡原理 &#x1f3…

SmartSoftHelp8数据库连接字符串强优化,高并发配置

1.设置数据库是否异步连接 2.数据库连接是否复用 3.最大链接数 4.最小连接数 5.等待时间 6.生命周期 下载地址&#xff1a; 百度网盘 请输入提取码

24、蜂鸣器

蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;常用来产生设备的按键音、报警音等提示信号 蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器 有源蜂鸣器&#xff1a;内部自带振荡源&#xff0c;将正负极接上直流电压即可持续发声&#xff0c;频率固定 无源蜂…

【linux】信号——信号保存+信号处理

信号保存信号处理 1.信号保存1.1信号其他相关概念1.2信号在内核中的表示 2.信号处理2.1信号的捕捉流程2.2sigset_t2.3信号集操作函数2.4实操2.5捕捉信号的方法 3.可重入函数4.volatile5.SIGCHLD信号 自我名言&#xff1a;只有努力&#xff0c;才能追逐梦想&#xff0c;只有努力…

计算机毕业设计 基于SpringBoot的敬老院管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

数据结构与算法-静态查找表

&#x1f31e; “清醒 自律 知进退&#xff01;” 查找 &#x1f388;1.查找的相关概念&#x1f388;2.静态查找表&#x1f52d;2.1静态查找表的类定义&#x1f52d;2.2顺序查找&#x1f52d;2.3二分查找&#x1f50e;二分查找例题 &#x1f52d;2.4分块查找&#x1f52d;2.5三…

理解BatchNormalization层的作用

深度学习 文章目录 深度学习前言一、“Internal Covariate Shift”问题二、BatchNorm的本质思想三、训练阶段如何做BatchNorm四、BatchNorm的推理(Inference)过程五、BatchNorm的好处六、机器学习中mini-batch和batch有什么区别 前言 Batch Normalization作为最近一年来DL的重…

logistic回归详解

为什么不直接统计标签数和预测结果数&#xff0c;计算精度&#xff1f; 因为 存在梯度为0的情况梯度不连续 为什么叫logistic回归 logistic是因为加了一个sigmoid函数&#xff0c;将输出预测值映射到【0&#xff0c;1】 有时候使用MSE损失函数&#xff0c;拟合 有时候使用c…

selenium三猛士

selenium包括三个项目&#xff0c;分别是&#xff1a;Selenium WebDriver,Selenium IDE&#xff0c;Selenium Grid。 Selenium WebDriver Selenium WebDriver是客户端API接口&#xff0c;测试人员通过调用这些接口&#xff0c;来访问浏览器驱动&#xff0c;浏览器再访问浏览器…

利用Python中的Manim进行数学绘画和创作

相信很多同学就算没听过3Blue1Brown&#xff0c;也一定曾看过他们出品的视频&#xff0c;其从独特的视觉角度解说各种数学概念&#xff0c;内容包括线性代数、微积分、神经网络、傅里叶变换以及四元数等晦涩难懂的知识点。例如最火的《线性代数本质》系列视频。 那么这些视频是…

【算法】动态规划中的路径问题

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;如果给算法的难度和复杂度排一个排名&#xff0c;那么动态规划算法一定名列前茅。今天&#xff0c;我们通过由简单到困难的两道题目带大家学会动…

文字、图片免费生成视频和专属数字人,你不来试试吗?

查看生成的效果&#xff1a;AI产生的视频&#xff08;关注公众号&#xff0c;获取精彩内容&#xff09; 您是否想要制作一些令人惊叹的视频&#xff0c;但又没有视频编辑的技能或经验&#xff1f;您是否想要利用人工智能的力量&#xff0c;让您的图片和声音变成动态的视频&…

如何强制任何Android应用程序进入全屏沉浸式模式(无生根)

谷歌在2012年发布了Android版本的Chrome&#xff0c;并且从未费心给它一个全屏模式。如果您厌倦了等待自己喜欢的Android应用程序提供全屏&#xff0c;则可以使用沉浸式模式自行完成。 来吧&#xff0c;谷歌&#xff0c;我真的一直在乞求你多年&#xff01;没有理由不给我们一…

【Go语言反射reflect】

Go语言反射reflect 一、引入 先看官方Doc中Rob Pike给出的关于反射的定义&#xff1a; Reflection in computing is the ability of a program to examine its own structure, particularly through types; it’s a form of metaprogramming. It’s also a great source of …

C语言——深入理解指针(4)

目录 1.回调函数 2. qsort 函数的使用 2.1 排序整型数据 2.2 排序结构体数据 3. qsort 函数的模拟实现 1.回调函数 回调函数就是通过一个函数指针调用的函数。 你把函数的地址作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;被调…

【web安全】ssrf漏洞的原理与使用

前言 菜某对ssrf漏洞的总结。 ssrf的作用 主要作用&#xff1a;访问外界无法访问的内网进行信息收集。 1.进行端口扫描&#xff0c;资源访问 2.指纹信息识别&#xff0c;访问相应的默认文件 3.利用漏洞或者和payload进一步运行其他程序 4.get类型漏洞利用&#xff0c;传参数…

用CHAT 写一份销售人员激励方案

问CHAT &#xff1a;写一份销售人员早会激励方案 CHAT回复&#xff1a; 标题&#xff1a;鼓舞斗志&#xff0c;迎接新的一天 -- 销售人员早会激励方案 一、会议的氛围设定&#xff1a; 深呼吸&#xff0c;准备开始一天的事业&#xff1a;清晨的阳光&#xff0c;温暖而明亮&…

Nat. Rev. Chem. | 一份关于用机器学习研究化学问题的评估指导

今天为大家介绍的是来自Tiago Rodrigues团队的一篇论文。机器学习&#xff08;ML&#xff09;有望解决化学领域的重大挑战。尽管ML工作流程的适用性极广&#xff0c;但人们通常发现评估研究设计多种多样。目前评估技术和指标的异质性导致难以&#xff08;或不可能&#xff09;比…

Android BT HCI分析简介

对于蓝牙开发者来说&#xff0c;通过HCI log可以帮助我们更好地分析问题&#xff0c;理解蓝牙协议&#xff0c;就好像网络开发一定要会使用Wireshark分析网络协议一样。 本篇主要介绍HCI log的作用、如何抓取一份HCI log&#xff0c;并结合一个实际的例子来说明如何分析HCI log…

亚马逊云科技 re:Invent 2023:科技前沿风向标,探索未来云计算之窗

文章目录 一、前言二、什么是亚马逊云科技 re:Invent&#xff1f;三、亚马逊云科技 re:Invent 2023 将于何时何地举行四、亚马逊云科技 re:Invent 2023 有什么内容&#xff1f;4.1 亚马逊云科技 re:Invent 2023 主题演讲4.2 亚马逊云科技行业专家探实战 五、更多亚马逊云科技活…