【数据结构】堆的模拟实现

news2024/12/23 10:08:31

前言:前面我们学习了顺序表、单链表、栈、队列,今天我们就开始新的学习吧,今天我们将进入堆的学习!(最近博主处于低谷期)一起加油吧各位。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


学前必读:

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。(至于二叉树,博主会在下一篇博客中给大家讲解,各位友友不用心急)

什么是堆

堆(Heap):我们可以通俗的理解成一种二叉树,但最大值或最小值是存在上面的,且堆中某个节点的值总是不大于或不小于其父节点的值。并且堆总是一棵完全二叉树。光看文字我们可能无法很清晰的理解堆,我们来看下图。
在这里插入图片描述


堆的基本功能

  1. 插入数据
  2. 取堆顶的数据
  3. 删除根节点(最顶部)的数据
  4. 堆的数据个数
  5. 堆的判空

堆的功能实现

思路导读:要想实现堆,我们首先得定义一个结构体,里面存放一个指针,和一个size记录堆中数据个数,一个capacity记录空间的容量看是否需要扩容。如果有不懂的友友可以去看我前面的文章。
代码实现

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


堆的初始化

思路导读:堆的初始化还是一样的,我们把指针置为空,元素个数清零,空间容量清零即可。
代码实现

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

堆的销毁

思路导读:堆的销毁方法也不变,只需要将该指针开辟的空间释放掉,然后将指针置为空,元素个数清零,空间容量清零即可。
代码实现

typedef int HPDataType;//定义一个变量

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

堆的插入数据

思路导读:首先我们在插入的数据应该考虑,(假设我们建的堆是小堆)是直接插入在堆的头部还是在尾部,首先我们来看看头部是不是可行的,如果我们插入在头部,当插入的这个数是小于头部这个数的时候,那么我们就需要调整整个堆中的数据,来一一判断,可想而知这种方式是多么的麻烦,并且时间复杂度也相对来说较高。那么我们考虑把这个数据放在堆的尾部的时候看看是什么情况,我们将堆的数据放在尾部如果比它的父亲结点还小那么我们就交换它和父亲结点的位置即可。我们可以通过下图来对比分析。在这里插入图片描述
尾部插入代码实现:当然这个还是比较简单的,不懂的可以看前面的文章

void HeapPush(HP* php, HPDataType x)//插入数据
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;//先存放在尾部
}

我们通过图可知道,我们将数据放在尾部插入,然后将数据和它的父亲结点比较,如果比它的父亲结点还要小,我们就将它们俩俩交换,如果一直没有找到那么什么时候停止呢?就是当走到下标为0的时候停止(如下图)。因此我们要写一个函数将插入的数据向上调整,来保证我们的堆在插入后仍然成立。
在这里插入图片描述
代码实现:

void AdjustUp(HPDataType* a, int child)//向上调整
{
	assert(a);
	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 Swap(int* x, int* y)//交换
{
	int tmp = 0;
	tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustUp(HPDataType* a, int child)//向上调整
{
	assert(a);
	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)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;//先存放在尾部
 	AdjustUp(php->a,php->size);
	php->size++;
}

取堆顶的数据

思路导读:因为我们堆顶的数据在数组中存储的时候就放在了数组的头部,因此我们只需要返回数组下标为0的那个数即可。
代码实现

HPDataType HeapTop(HP* php)// 取堆顶的数据
{
	assert(php);
	return php->a[0];
}

删除根节点(堆顶)的数据

思路导读:1.如何删除根节点我们删除根节点我们首先想到的就是直接删除头部的节点,我们来试想一下直接删除根节点,如果直接删除头部节点,那么我们整个堆的数据都要立刻开始动(即数据都往前诺一位)在不考虑删除堆后是否还是堆,因此直接删除根节点是十分麻烦的。我们换一个思路,我们将根节点,和尾部节点的数据交换位置,然后直接尾删数据,那么我们整个堆在不考虑交换后是否仍然是堆的情况下,即可很快速的完成删除根节点。
2. 向下调整我们在完成删除根部节点之后,我们尾部的数据放在了根部,我们自然而然的就要考虑这个树是否仍然是一个堆了,因此我们要把交换后的这个数与它的孩子节点比较,如果比它们大即交换数据,一直到比它们小为止,或者走到树的尾部。如下图所示
在这里插入图片描述
代码实现

void AdjustDown(HPDataType* a, int size, int parent)//向下调整
{
	assert(a);
	int child = parent * 2 + 1;//找到第一个孩子
	while (child < size)
	{
		//看俩个孩子谁更小,交小的那个与父亲去比较
		if (a[child] > a[child + 1] && (child+1) < size)
		{
			child += 1;
		}
		if (a[parent] > a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;//让父亲和儿子往下走
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapPop(HP* php)//删除根节点(最顶部)的数据
{
	assert(php);
	assert(php->size > 0);
	Swap(&php->a[php->size - 1], &php->a[0]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

堆的数据个数

思路导读:我们在前面记录了一个size负责记录数据的个数,因此我们只需要直接返回size即可。
代码实现:

size_t HeapSize(HP* php) //堆的数据个数
{
	assert(php);
	return php->size;
}

堆的判空

思路导读:我们只需要判断size中的数据是否为0即可。
代码实现:


bool HeapEmpty(HP* php) //堆的判空
{
	assert(php);
	return php->size == 0;

}

整体函数测试

void Test1()
{
	int array[] = { 27,15,19,18,28,34,65,49,25,37 };
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < sizeof(array) / sizeof(int); i++)
	{
		HeapPush(&hp, array[i]);//插入数据
	}
	int k = HeapSize(&hp);
	while (k--)
	{
		printf("%d ",HeapTop(&hp));//获取堆顶数据
		HeapPop(&hp);
	}
	//Print(&hp);
	HeapDestory(&hp);

}

int main()
{
	Test1();
}

运行结果:在这里插入图片描述
自己手动排一下,看看是否建堆成功。
在这里插入图片描述


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🫵🫵🫵 祝各位接下来好运连连 💞

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

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

相关文章

在AWS EC2中部署和使用Apache Superset的方案

大纲 1 Superset部署1.1 启动AWS EC21.2 下载Superset Docker文件1.3 修改Dockerfile1.4 配置管理员1.5 结果展示1.6 检查数据库驱动1.7 常见错误处理 2 Glue&#xff08;可选参考&#xff09;3 IAM与安全组3.1 使用AWS Athena3.2 使用AWS RedShift或AWS RDS3.2.1 查看AWS Reds…

MySQL8.0默认配置详解--持续更新中

binlog日志的默认保留数量和大小 在MySQL 8.0中&#xff0c;您可以使用以下SQL命令来查询binlog日志的默认保留数量和大小&#xff1a; SHOW VARIABLES LIKE binlog_expire_logs_seconds; SHOW VARIABLES LIKE max_binlog_size;binlog_expire_logs_seconds 变量表示binlog日志…

食品进销存系统哪个好?亿发商品信息管理系统,操作简单好用,可定制

元旦将近&#xff0c;年的味道也越来越浓厚。年货置办的人越来越多&#xff0c;食品店也迎来年底的生意旺季。但众所周知&#xff0c;食品行业作为一个商品品类众多、品牌繁多且商品销售价格波动频繁的领域&#xff0c;常常面临商品批次管理的挑战&#xff0c;特别是需要注意避…

智能优化算法应用:基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.群居蜘蛛算法4.实验参数设定5.算法结果6.…

【LuatOS】简单案例网页点灯

材料 硬件&#xff1a;合宙ESP32C3简约版&#xff0c;BH1750光照度模块&#xff0c;0.96寸OLED(4P_IIC)&#xff0c;杜邦线若干 接线&#xff1a; ESP32C3.GND — OLED.GND — BH1750.GND ESP32C3.3.3V — OLED.VCC — BH1750.VCC ESP32C3.GPIO5 — OLED.SCL — BH1750.SCL E…

人工智能导论习题集(1)

第二章&#xff1a;知识表示 题1题2题3题4题5 题1 题2 题3 题4 题5

【从零开始学习JVM | 第六篇】快速了解 直接内存

前言&#xff1a; 当谈及Java虚拟机&#xff08;JVM&#xff09;的内存管理时&#xff0c;我们通常会想到堆内存和栈内存。然而&#xff0c;还有一种被称为"直接内存"的特殊内存区域&#xff0c;它在Java应用程序中起着重要的作用。直接内存提供了一种与Java堆内存和…

DRBD分布式存储实验

DRBD DRBD的全称为&#xff1a;Distributed Replicated Block Device (DRBD) 分布式块设备复制 与心跳连接结合使用&#xff0c;构建高可用性(HA)的集群。 实现方式是通过网络来镜像(mirror)整个设备。它允许用户在远程机器上建立一个本地块设备的实时镜像。DRBD负责接收数据…

[Linux] Tomcat

一、Tomcat相关知识 1.1 Tomcat的简介 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;是 Apache 软件基金会的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。Tomc…

Python从入门到精通九:Python异常、模块与包

了解异常 什么是异常 当检测到一个错误时&#xff0c;Python解释器就无法继续执行了&#xff0c;反而出现了一些错误的提示&#xff0c;这就是所谓的“异常”, 也就是我们常说的BUG bug单词的诞生 早期计算机采用大量继电器工作&#xff0c;马克二型计算机就是这样的。 19…

元素定位,年轻人在 Web UI 自动化成长道路上吃的第一个亏

元素定位&#xff0c;对于 Web UI 自动化而言&#xff0c;绝对是大家成长道路上的一道绊脚石。很多初学者&#xff0c;都“死”在了元素定位上&#xff0c;从而失去了学习的兴趣。导致职业规划不得不半途而废~那么&#xff0c;今天&#xff0c;我们就使用 Katalon Studio&#…

我的创作三周年纪念日

今天收到CSDN官方的来信&#xff0c;创作三周纪念日到了。 Dear: Hann Yang &#xff0c;有幸再次遇见你&#xff1a; 还记得 2020 年 12 月 12 日吗&#xff1f; 你撰写了第 1 篇技术博客&#xff1a; 《vba程序用7重循环来计算24》 在这平凡的一天&#xff0c;你赋予了它…

Python编程技巧 – 使用组合运算符

Python编程技巧 – 使用组合运算符 Python Programming Skills – Using Combined Operators Python通过赋值过程&#xff0c;将声明变量与赋值和而为之&#xff0c;可谓讲求效率。此外&#xff0c;在Python赋值运算符里&#xff0c;也有一个强大高效的功能&#xff0c;即复合…

Python 神奇解码器:pyWhat 库全面指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在当今数字化的世界中&#xff0c;理解和处理文本数据是许多应用程序的关键任务。而PyWhat库作为一个用于处理文本的Python库&#xff0c;提供了强大的功能&#xff0c;帮助开发者在文本中识别和提取有意义的信息…

n-Track Studio Suite,音频录制与编辑的新纪元

在音乐制作领域&#xff0c;n-Track Studio Suite已经成为了音频录制和编辑的新标杆。这款软件将功能强大、操作简便和艺术创新完美融合&#xff0c;为用户提供了前所未有的音乐制作体验。 n-Track Studio Suite以其先进的音频处理技术&#xff0c;提供了精确的音频录制、编辑…

【从零开始学习JVM | 第三篇】类的生命周期(高频面试)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。 在本文中&#xff0c;我们将深入探讨类的生命周期&#xff0c;从类加载到…

VUE3语法--toRefs与toRef用法

1、功能概述 ref和reactive能够定义响应式的数据&#xff0c;当我们通过reactive定义了一个对象或者数组数据的时候&#xff0c;如果我们只希望这个对象或者数组中指定的数据响应&#xff0c;其他的不响应。这个时候我们就可以使用toRefs和toRef实现局部数据的响应。 toRefs是…

【探讨】bp神经网络是前馈还是后馈

目录 一、BP神经网络简介 1.1 什么是BP神经网络 1.2 BP神经网络的结构 二、BP神经网络的前馈与后馈 2.1 什么是BP神经网络的前馈 2.2 什么是BP神经网络的后馈 三、BP神经网络前馈与后馈的关系 3.1 BP神经网络前馈与后馈的区别 3.2 BP神经网络前馈与后馈的意义 四、BP…

论文阅读三——端到端的帧到凝视估计

论文阅读三——端到端的帧到凝视估计 主要内容研究问题文章的解题思路文章的主要结构 论文实验关于端到端凝视估计的数据集3种基线模型与EFE模型的对比在三个数据集中与SOTA进行比较 问题分析重要架构U-Net 基础知识 主要内容 文章从端到端的方法出发&#xff0c;提出了根据he…

Linux---虚拟机软件

1. 虚拟机软件的介绍 它是能够虚拟出来计算机的一个软件。 常用虚拟机软件: VmwareVirtualBox 说明: 只有安装了虚拟机软件才可以创建虚拟机&#xff0c;当然通过虚拟机软件还可以创建多个虚拟机。 2. 虚拟机的介绍 就是模拟一个真实的计算机&#xff0c;好比一个虚拟的…