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

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

💖 博主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();
}

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


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


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea__SpringBoot微服务10——整合JDBC(新依赖)

整合JDBC 完整项目地址&#xff1a;一、创建一个项目二、idea配置连接mysql三、创建yaml数据库连接配置文件四、测试一下&#xff0c;没有问题五、增删改查————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏(*&#xffe3;︶…

P4 Qt基础控件——工具按钮toolButton(上)

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f33a;本篇简介 &#xff1a;这一章我们学一…

[湖湘杯 2021 final]MultistaeAgency

文章目录 题目是给了源码&#xff0c;我们先来看web的main.go package mainimport ("bytes""crypto/md5""encoding/json""fmt""io""io/ioutil""log""math/rand""net/http""o…

数据库系统相关概念

数据&#xff1a;描述事务的符号记录。 数据库(DB)&#xff1a;按一定的数据模型组织&#xff0c;描述和存储在计算机内的&#xff0c;有组织的&#xff0c;可共享的数据集合。 数据库管理系统(DBMS)&#xff1a;位于用户和操作系统之间的一层数据管理软件。主要功能包括&#…

iframe 与主应用页面之间如何互相通信传递数据

背景 当我们的Web页面需要复用现有网站的页面时&#xff0c;我们通常会考虑代码层面的抽离引用&#xff0c;但是对于一些过于复杂的页面&#xff0c;通过 iframe 嵌套现有的网站页面也是一种不错的方式&#xff0c;。目前我就职的项目组就有多个业务利用 iframe 完成业务的复用…

【实用】sklearn决策树怎么导出规则

目录 一、什么是决策树模型 0.1 什么是决策树 02.决策树模型有哪些 二、在sklearn中怎么训练一棵决策树 三、什么是决策树的规则 0.1决策树的决策规则 02. 决策树的决策规则是怎么存储的 四、怎么导出决策树的规则 4.1 导出决策树文本规则 4.2 导出可视化决策树 4.3…

C++入门【3-C++ 变量类型】

C 变量类型 变量其实只不过是程序可操作的存储区的名称。 在 C 中&#xff0c;有多种变量类型可用于存储不同种类的数据。 C 中每个变量都有指定的类型&#xff0c;类型决定了变量存储的大小和布局&#xff0c;该范围内的值都可以存储在内存中&#xff0c;运算符可应用于变量…

初学python的体会心得20字,初学python的体会心得2000

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;学了python的心得体会200字&#xff0c;初学python的体会心得20字&#xff0c;现在让我们一起来看看吧&#xff01; 本学期&#xff0c;我们学习了杨老师的《python语言程序设计》这门课程&#xff0c;其实早在大一期间…

【RTOS学习】模拟实现任务切换 | 寄存器和栈的变化

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;认识任务切换&#x1f3d0;切换的实质&#x1f3d0;栈中的内容&#x1f3d0;切…

数据可视化:解析跨行业普及之道

数据可视化作为一种强大的工具&#xff0c;在众多行业中得到了广泛的应用&#xff0c;其价值和优势不断被发掘和利用。今天就让我以这些年来可视化设计的经验&#xff0c;讨论一下数据可视化在各个行业中备受青睐的原因吧。 无论是商业、科学、医疗保健、金融还是教育领域&…

Vue2笔记

笔记 脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue …

三天精通Selenium Web 自动化 - 如何找到元素

1. 什么是元素&#xff1f; 元素&#xff1a;HTML 元素 2. 定位方式解析 Selenium WebDriver 提供一个先进的技术来定位 web 页面元素。Selenium 功能丰富的API 提供了多个定位策略如:Name、ID、CSS 选择器、XPath 等等&#xff0c;如下图所示&#xff1a; 一般会用ID来定位…

Jmeter 测试 MQ 接口怎么做?跟我学秒变大神!

MQ(message queue)消息队列&#xff0c;是基础数据结构 先进先出 的一种典型数据结构。一般用来解决应用解耦&#xff0c;异步消息&#xff0c;流量削锋等问题&#xff0c;实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构。 MQ 主要产品包括&#xff1a;Rabb…

华清作业day45

头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> #include <QTimer> #include <QTimerEvent> #include <QTextToSpeech> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass…

Unity_ET框架项目-斗地主_启动运行流程

unity_ET框架项目-斗地主_启动运行流程 项目源码地址&#xff1a; Viagi/LandlordsCore: ET斗地主Demohttps://github.com/Viagi/LandlordsCore下载项目到本地。 启动运行步骤&#xff1a; 下载目录如下&#xff1a; 1. VS&#xff08;我用是2022版VisualStudio&#xff09…

2023年第十届GIAC全球互联网架构大会-核心PPT资料下载

一、峰会简介 谈到一个应用&#xff0c;我们首先考虑的是运行这个应用所需要的系统资源。其次&#xff0c;是关于应用自身的架构模式。最后&#xff0c;还需要从软件工程的不同角度来考虑应用的设计、开发、部署、运维等。架构设计对应用有着深远的影响&#xff0c;它的好坏决…

Facebook广告投放常见错误

在进行Facebook广告投放时&#xff0c;很容易犯一些常见的错误。这些错误可能导致广告投资的浪费&#xff0c;影响广告效果并降低回报。本文小编讲一些常见的Facebook广告投放错误&#xff0c;以及如何避免它们。 1、不明确目标受众 广告的成功与否很大程度上取决于你选择的目…

Vue 双向绑定:让数据与视图互动的魔法!(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

一天搞定jmeter入门到入职全套教程之Jmeter分布式测试

随着并发量的增大&#xff0c;一台机器就不能满足需求了&#xff0c;所以我们采用分布式&#xff08;Master-Slaver&#xff09;的方案去执行高并发的测试 注意事项&#xff1a; Master机器一般我们不执测试&#xff0c;所以可以拿一台配置差些的机器&#xff0c;主要用来采集…

Apollo配置发布原理解析

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…