数据结构----堆的实现(附代码)

news2024/11/16 2:49:05

       当大家看了鄙人的上一篇博客栈后,稍微猜一下应该知道鄙人下一篇想写的博客就是堆了吧。毕竟堆栈在C语言中常常是一起出现的。那么堆是什么,是如何实现的嘞。接下来我就带大家去尝试实现一下堆。

堆的含义

       首先我们要写出一个堆,那么我们就需要要了解堆是什么。那么堆是什么嘞。堆是一种特殊的数据结构,它是一棵完全二叉树,同时满足堆属性,即父节点的值总是大于或小于其子节点的值。如果父节点的值总是大于子节点的值,那么我们称之为大根堆;反之,如果父节点的值总是小于子节点的值,那么我们称之为小根堆。在堆中,根节点的值最大(大根堆)或最小(小根堆),因此它也被称为堆顶。这个大家可以简单的理解,大根:谁大谁当爹。小根:谁小谁当爹。不知道大家是否有联想到我们一起学习的大小端问题。就是我们的内存存放。当然这里是没有关联的只是名字很像,大家应该会想到这些。

堆的定义

       那么当我们了解了堆是什么之后,那么我们就来实现了。首先想堆栈既然这两个字都可以组成一个词了,那么我们实现堆可不可以用实现栈的方法来实现。所以我们首先要来定义一个结构体,来存放我们要放的东西和下标。为什么有下标嘞其实大家就理解为下一个数据的坐标嘛。毕竟堆是抽象的,不想我们数组那样用下标可以直接找,那么我们结构体只有这些嘛,我们数组建立是不是要需要确定它的起始容量,就算我们最开始不确定去起始容量,也需要确定它的数组内容。那么我们是不是需要在结构体里面确定好它的起始容量?在后续使用中,如果需要的话,我们再翻二倍开始扩容。这个应该在前面的博客中有提及过。那么我们接下来就写写结构的创建:

         这其实很简单,就像我们栈一样,只需要创建结构体,然后写这些内容就可以了。

堆初始化

         既然我已经将堆定义了,但是我们没有确定里面内容呀。那么接下来我们就将写堆的初始化。我们开始知道,不就是创建结构体嘛,所以我们需要用malloc。然后将里面的内容一一初始化,这样就结束了。

堆销毁

        那么接下来我们经写了,对了,初始化了,竟然还有创建那么肯定有销毁,然后堆销毁的话其实是比较简单的,我们只需要这样申请的malloc free掉,然后将下标这些清为零就可以了。

       对于栈的销毁,堆的销毁是比较简单的。只是大多数人都会在free后忘了将其置为NULL,这个是比较常见且简单的错误,希望大家都不要犯这个错误。

堆的插入

       好,那我们写了将堆里面的内容初始化后,我们需要往里面插入我们想要的数据。那么我们往里面插入数据的话,一直插,一直插肯定需要判断是否版满了吧。然后接着就是判断满了之后我们需要扩容。当这些处理好之后,我们就需要将里面的数据处理。大家都知道我们在最开始上面写的就是一个完全二叉树,然后里面就是大根和小根的排列。然后我们这里就实现大根。  

        这里我们并没有将向上调整写出来,因为如果写出来的话就会显示这个代码比较多,且不是很方便。

堆的向上调整

     那么我们知道向上调整就需要找到该节点的父节点。那么寻找父节点的坐标是多少呢?我想我应该与大家讲过,当我们需要寻找一个节点的负极点,那么就是它的节点的下标减一除二。那么寻找他的直接点就相同是乘二加一。这个是经过验算的,大家可以是想着拿一个数组要不要来尝试,然后将它画成二叉树的样子。这样大家对于以后寻找节点的父子点都很简单了。那么当我们找到了父节点之后,我们就需要循环比较,因为我们需要将子节点向上调整。大家可以想着如果我们最后插入的数是最大的,那它是不是应该跑到第一个节点那里?所以我们需要循环来判断向上调整。我们一直判断,直到他到了最开始节点后停止。当然我们也不是只判断一路,我们还需要判断其他的合理性,如果我们只一路向上调整的话,我们需要判断他的的另外一个直接点是否符合我们大端的要求?大家可以简单的理解为我们插入一个数是在最后的,然后一直向上调整,判断是否是大于父节点,然后向上一直迭代交换。直到成为祖先节点。

堆的判空

       接下来我们实现的是判断堆是否为空堆。其实这个是比较简单的,大家想一下。因为我们最开始写了堆的下标。如果都为空的话,那么下标一定为零。那么我们只需要判断对的下标是否为零,这样就结束了。

       对于堆判空我们是比较简单的,与我们上一篇栈判空差不多。

堆删除

        好了,那我们写了堆的判空之后,我们接下来要写堆的删除。我们都知道删除堆的数据的话,肯定就是删除堆顶的数据。那为什么是删除堆顶的数据而不是堆底的数据呢?大家想想,如果我们删除堆叠的数据的话,我们如同在一个排行榜中把数据最下面的人删除掉了。我们上次最顶的那一个数据的话,那我们我们就上一个排行榜一样,我们点排行榜一定会从上而下的看。并且这样写会更有一些价值。我们后面如果想要找到中国富豪榜前十的话,这样就很有用。对于删除的话,我们就只需要向头节点和结点交换之后将下标减一,那么我们就删除了尾节点了。我们还是老样子将比较多的代码单独拿出来写,这样看起来也会好些。

堆的向下调整

       好了,那我们下来写对的上下调节。向上调节我们很简单,只需要用这个节点与父亲节点比较就可以了。但是向下调整了,我们就需要多判断一下,因为他可能会有两个孩子左右节点都有可能存在,然后需要多判断一下。那么我们判断是不是只需要判断大的那个就可以了?因为我们将左右孩子判断一下谁大?然后我们再用父亲节点与他的那个还直接判断,如果比他还大的话,那么就是没问题吧?毕竟因为我们都是写的是大端。注意:向下调整的条件是左右子树必须是堆。

堆顶数据

        我们小区对定数据的话其实就很简单,就如同我们判断对是否为空一样。我们只需要先判断传过来的数据是否正确,然后向下标为零的数据传出去,那么我们就获取了堆顶数据了。

堆的数据个数

       但我们写着写着忘了我们堆里面有多少个数据的时候。那我们怎么实现的?是不是也很简单,我们只需要将我们的下标返回去就可以了,因为我们是从上标零开始的。我们直接return size就可以了。

总结

      堆的实现与我们的栈的实现其实差不多的,只需要稍微思考一下排列的方法,这样就可以了。对于堆稍微需要注意的就是堆的大端和小端的排序。好奇亚的几乎可以借鉴一下栈的实现方法。那么以上呢就是鄙人想与大家分享的关于堆的一些基本实现代码还有许多不足的地方,希望大家可以在评论区留言。

//初始化
void HpInit(Hp* pHp)
{
	//判断合法性,传过来的东西是不是空的
	assert(pHp);

	//开辟动态空间
	HpDataType* tmp = (HpDataType*)malloc(sizeof(HpDataType) * DefaultCapacity);
	if (tmp == NULL)//判断合法性,如果你嫌麻烦也可以不写,最好有
	{
		perror("malloc fail");
		return;
	}

	//初始化
	pHp->data = tmp;
	pHp->size = 0;
	pHp->capacity = DefaultCapacity;
}

//堆的销毁
void HpDestroy(Hp* pHp)
{
	//判断合法性
	assert(pHp);

	//释放内存和清理
	free(pHp->data);
	pHp->data = NULL;
	pHp->size = pHp->capacity = 0;

}


void Swap(HpDataType* p1, HpDataType* p2)
{
	HpDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向上调整建堆
void AdjustUp(HpDataType* data, int child)
{
	//判断指针有效性
	assert(data);
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//向上调整呢
		if (data[child] > data[parent])
		{
			Swap(&data[child], &data[parent]);
		}
		else
		{
			break;
		}
		//迭代
		child = parent;
		parent = (child - 1) / 2;
	}

}

//插入数据
void HpPush(Hp* pHp, HpDataType x)
{
	//判断指针有效性
	assert(pHp);

	//判断容量是否满了
	if (pHp->size == pHp->capacity)
	{
		HpDataType* tmp = (HpDataType*)realloc(pHp->data, sizeof(HpDataType) * pHp->capacity * 2);//每次扩容*2
		if (tmp == NULL)//判断空间合法性
		{
			perror("malloc fail");
			return;
		}
		//扩容后
		pHp->data = tmp;
		pHp->capacity *= 2;
	}

	//数据入堆
	pHp->data[pHp->size] = x;
	pHp->size++;

	//向上调整建堆
	AdjustUp(pHp->data, pHp->size - 1);

}
void AdjustDown(HpDataType* data, int size, int parent)
{
	//断言检查
	assert(data);

	int child = parent * 2 + 1;

	while (child < size)
	{
		//求出左右孩子较大的那个下标
		if (child + 1 < size && data[child + 1] > data[child])
		{
			child++;
		}
		//父亲比孩子小就交换位置
		if (data[child] > data[parent])
		{
			//交换
			Swap(&data[child], &data[parent]);
			//迭代
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}

}

void HpPop(Hp* pHp)
{
	//断言检查
	assert(pHp);
	//删除数据
	Swap(&pHp->data[0], &pHp->data[pHp->size - 1]);
	pHp->size--;
	//向下调整建堆
	AdjustDown(pHp->data, pHp->size - 1, 0);

}

//判断是否为空
bool HpEmpty(Hp* pHp)
{
	assert(pHp);
	return pHp->size == 0;
}

// 取堆顶的数据
HpDataType HpTop(Hp* pHp)
{
	assert(pHp);

	return pHp->data[0];
}

// 堆的数据个数
int HpSize(Hp* pHp)
{
	assert(pHp);

	return pHp->size;
}

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

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

相关文章

nodejs 与 npm 版本对应关系

官方地址&#xff1a;https://nodejs.org/en/about/previous-releases

手机边听边充音频转接器双盲插系列:便捷充电,畅享音乐6500

在快节奏的生活中&#xff0c;手机已经成为我们不可或缺的日常用品。无论是工作、学习还是娱乐&#xff0c;手机都扮演着重要角色。然而&#xff0c;当我们沉浸在音乐的海洋中时&#xff0c;手机电量不足的困扰却时常打断我们的美好体验。为了解决这一难题&#xff0c;手机边听…

你真正了解 Java 中的 Date 类吗?以及如何正确使用它

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

设计模式8——原型模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 原型模式&#xff08;Prototyp…

css卡片横线100%宽度

所需样式: 横线不用border, 用单独一个div, 这样就不会影响父组件的padding <div class"pumpDetailView"><div class"pump_title_name"><span>{{ pumpInfo.pointname }}</span><divclass"point_state":style"…

vr商品全景展示场景编辑软件的优点

3D模型展示网站搭建编辑器以强大的3D编辑引擎和逼真的渲染效果&#xff0c;让您轻松实现模型展示的优化。让用户通过简单的操作&#xff0c;就能满足个人/设计师/商户多样化展示的需求&#xff0c;让您的模型成为独一无二的杰作。 3D模型展示网站搭建编辑器采用国内领先的实时互…

玩转盲盒潮流:从0到1搭建小程序平台

在当前的消费市场中&#xff0c;盲盒已成为一种炙手可热的消费模式&#xff0c;凭借其神秘性和随机性&#xff0c;迅速俘获了年轻消费者的心。作为一位有志于创新并紧跟市场趋势的创业者&#xff0c;你可能会想&#xff1a;如何从0到1搭建一个属于自己的盲盒小程序平台&#xf…

kafka跨地区跨集群同步工具MirrorMaker2 —— 筑梦之路

MM2简介 KIP-382: MirrorMaker 2.0 - Apache Kafka - Apache Software Foundation 有四种运行MM2的方法&#xff1a; As a dedicated MirrorMaker cluster.&#xff08;作为专用的MirrorMaker群集&#xff09; As a Connector in a distributed Connect cluster.&#xff08…

基本IO接口

引入 基本输入接口 示例1 示例2&#xff1a;有数据保持能力的外设 #RD端由in指令控制&#xff1a;将数据由端口传输到CPU内存中 #CS244信号由译码电路实现 示例3&#xff1a; a)图中由于输出端口6有连接到端口1&#xff0c;当开关与端点1闭合时期间&#xff0c;仍能维持3端口…

开放式耳机2024超值推荐!教你如何选择蓝牙耳机!

开放式耳机的便利性让它在我们的日常生活中变得越来越重要。它让我们摆脱了传统耳机的限制&#xff0c;享受到了更多的自由。不过&#xff0c;市面上的开放式耳机种类繁多&#xff0c;挑选一款既实用又实惠的产品确实需要一些小窍门。作为一位对开放式耳机颇有研究的用户&#…

柯桥职场人出差必备的商务口语-职场差旅口语提问篇

May I reconfirm my flight? 我可以确认我的班机15857575376吗&#xff1f; Where can I make a reservation? 我到哪里可以预订&#xff1f; Do I have to make a reconfirmation? 我还要再确认吗&#xff1f; Is there any discount for the USA Railpass? 火车通行…

【设计模式】JAVA Design Patterns——Bytecode(字节码模式)

&#x1f50d;目的 允许编码行为作为虚拟机的指令 &#x1f50d;解释 真实世界例子 一个团队正在开发一款新的巫师对战游戏。巫师的行为需要经过精心的调整和上百次的游玩测试。每次当游戏设计师想改变巫师行为时都让程序员去修改代码这是不妥的&#xff0c;所以巫师行为以数据…

安全态势管理的六大挑战:态势感知

德迅云安全鉴于如今的安全威胁不断变幻&#xff0c;企业对实施态势管理策略至关重要&#xff0c;可以让安全团队根据需要进行安全策略的动态调整。如果企业在研究构建态势感知管理&#xff0c;需要特别关注以下六个方面的挑战。 如果企业正在使用一个或多个平台&#xff0c;那么…

《计算机网络微课堂》课程概述

​ 课程介绍 本专栏主要是 B 站课程《计算机网络微课堂》的文字版&#xff0c;作者是湖南科技大学的老师。 B 站地址&#xff1a;https://www.bilibili.com/video/BV1c4411d7jb 该课程好评如潮&#xff0c;包含理论课&#xff0c;实验课&#xff0c;考研真题分析课&#xf…

GDB 调试器

GDB 功能 在程序启动之前指定一些可以影响程序行为的变量或条件。在某个指定的地方或条件下暂停程序&#xff0c;在程序停止时检查已经发生了什么。 调试信息与调试原理 一般要调试某个程序&#xff0c;为了能清晰地看到调试的每一行代码、调用的堆栈信息、变 量名和函数名等…

qt5core.dll怎么下载,qt5core.dll下载安装详细教程

不知道大家有没有遇到过qt5core.dll丢失这个问题&#xff1f;目前这个问题还是比较常见的&#xff0c;一般使用电脑比较多的的人&#xff0c;有很大几率遇到这种qt5core.dll丢失的问题。今天主要针对这个问题&#xff0c;来给大家讲解一下一键修复qt5core.dll的方法。 Qt5Core.…

图论(从数据结构的三要素出发)

文章目录 逻辑结构物理结构邻接矩阵定义性能分析性质存在的问题 邻接表定义性能分析存在的问题 十字链表(有向图)定义性能分析 邻接多重表(无向图)定义性能分析 数据的操作图的基本操作图的遍历广度优先遍历&#xff08;BFS&#xff09;算法思想和实现性能分析深度优先最小生成…

打开服务器远程桌面连接不上,可能的原因及相应的解决策略

在解决远程桌面连接不上服务器的问题时&#xff0c;我们首先需要从专业的角度对可能的原因进行深入分析&#xff0c;并据此提出针对性的解决方案。以下是一些可能的原因及相应的解决策略&#xff1a; 一、网络连接问题 远程桌面连接需要稳定的网络支持&#xff0c;如果网络连接…

【一步一步了解Java系列】:何为数组,何为引用类型

看到这句话的时候证明&#xff1a;此刻你我都在努力加油陌生人个人主页&#xff1a;Gu Gu Study专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 数组 数组是一推相同数据…

JavaSE--基础语法(第一期)

Java是一种优秀的程序设计语言&#xff0c;它具有令人赏心悦目的语法和易于理解的语义。不仅如此&#xff0c;Java还是一个有一系列计算机软件和规范形成的技术体系&#xff0c;这个技术体系提供了完整的用于软件开发和 跨平台部署的支持环境&#xff0c;并广泛应用于嵌入式系统…