数据结构初阶——堆

news2024/11/24 10:32:59

目录

一,堆的概念

二,创建堆

2.1堆的结构

 2.2堆的初始化

 2.3堆的数据插入

2.4堆的数据的删除

注意点:

2.5 堆顶元素

 2.6堆的长度

2.7堆的销毁


思维导图:

 

一,堆的概念

堆是什么?对于一个对于电脑储存结构稍有了解的人来说,堆便是一种内存空间。它是区别于栈和静态区的。但是今天我想要介绍的堆却不是这个堆,我想要介绍的这个堆在物理上就是一个数组但是在逻辑结构上就是一个满二叉树。

就像这样:

 这个就是一个堆。这个图就是堆的一个物理结构。

它的逻辑结构是这样的:

 这个堆就是一个小堆!顺便提一句——虽然这个小堆的数组结构看起来是有序的,但是小堆不一定是有序的。我们的这个小堆只是一个特例!大堆小堆的分类的根据只是父节点与子节点之间的关系。父节点要是比子节点小那这个堆就是小堆,父节点要是比子节点要大那这个堆就是大堆!

二,创建堆

2.1堆的结构

堆,实际上就是一个数组嘛。但是你的堆可不是一个静态的数组。相反,它是一个动态的数组!所以我们的结构设计就要像顺序表一样有数组,要长度,有容量!

代码:

typedef int HeapDataType;
struct Heap {
	HeapDataType* a;//堆类型的数组
	int capacity;//堆的容量
	int size;//堆的长度
}Heap;

 2.2堆的初始化

堆的初始化就是给堆内的数组,容量,长度一个初始的值!在堆内还没有数据时我们可以给堆的长度,容量都初始化为0。而数组可以初始化为NULL。

代码:

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

 2.3堆的数据插入

堆的数据插入这一块可能就是我们写堆这个代码的一个难点。在写这个代码的时候我们必须知道我们的这个堆的插入应该插入到哪一个位置呢?很明显就是插入到堆的在最后一个位置,在数组中就是a[size-1]这个位置。而在堆的逻辑结构中,比如这个逻辑结构:

就要插入到7这个位置。

但是,凡事都要有个前提。那就是,你插入了你想要插入的数据以后,你的堆还得是堆。 也就是说,当你是小堆的时候,你插入一个数据以后堆的父节点还得小于堆的子节点。当你是大堆的时候,你插入数据以后堆的父节点还得大于堆的子节点。那我们要如何让堆实现这个功能呢?答案就是要实现向上调整算法。在你插入数据以后不断的向上调整从而维持父节点与子节点之间的特有关系。

代码:

void AdjustUp(Heap* php, int n)
{
	assert(php);
	int child = n;//孩子节点的下标
	int parent = (n - 1) / 2;//父亲节点的下标
	while (child > 0)
	{
		if (php->a[child] < php->a[parent])//实现小堆——父节点与子节点的位置交换
		{
			int temp = php->a[child];
			php->a[child] = php->a[parent];
			php->a[parent] = temp;
		child = parent;
		parent = (child - 1) / 2;
		}
		else {
			break;
		}
	}

}
void PushHeap(Heap* php,HeapDataType x)//向上调整算法
{
	assert(php);//先检查php是否为NULL
	if (php->size == php->capacity)//满了就扩容
	{
		int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;//商定新容量
		php->a = (HeapDataType*)realloc(php->a,newcapacity*sizeof(HeapDataType) );
		if (php->a == NULL)
		{
			perror("malloc fail!");
			return ;
		}
		php->capacity = newcapacity;
	}
	php->size++;//堆的长度加1.
	php->a[php->size - 1] = x;//在堆的最后一个位置上插入新元素
	AdjustUp(php,php->size-1);//实现向上调整

}

2.4堆的数据的删除

      堆的数据的删除删除的是根节点还是叶子节点呢?答案是删除的是根节点。也就是堆的第一个元素。那我们要怎么删呢?我们删除的步骤一般就是将根节点与最后一个叶子节点先调换顺序,然后将最后一个叶子节点删除掉。这样就达到了删除根节点的目的。但是就和插入堆节点一样,在我们删除掉根节点以后,我们还要保证我们的堆仍然是一个堆!怎么办呢?这时候就要引入向下调整这个概念了。

       什么是向下调整呢?写个代码就知道了!

代码:

bool HeapEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;//当堆的长度为0时这个堆就是一个空堆,就返回true。
}
void swap(HeapDataType* p1, HeapDataType* p2)//交换节点函数
{
	HeapDataType temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
void AdjustDown(Heap* php, int n)//向下调整算法
{
	assert(php);//断言,防止php为NULL
	int parent = 0;//最初的根节点的坐标
	int child = 2 * parent + 1;//左子节点与根节点的下标关系

	while (child <n )//当你要实现向下调整的时候,循环的终止条件是子节点在范围之内
	{
			if (child + 1 < n && php->a[child + 1] < php->a[child])//当左节点不是最小的节点时那就变成右节点来比较
			{
				child++;
			}
		if ( php->a[child] < php->a[parent])
		{
			swap(&php->a[parent], &php->a[child]);//交换函数
			parent = child;
			child = parent * 2 + 1;
	    }
		else
		{
			break;
		}

	}

}
void PopHeap(Heap* php)
{
	assert(php);//断言一下php是否为NULL
	assert(!HeapEmpty(php));//断言,防止堆为空

	swap(&php->a[0], &php->a[php->size - 1]);//交换根节点与最后一个叶子节点

	php->size--;//删除掉最后一个叶子节点,也就是将根节点删除掉了

	AdjustDown(php,php->size);//向下调整来保证堆仍然是堆

}

删除的步骤:

1.利用assert断言,判断php是否为NULL指针,利用HeapEmpty函数判断堆是否是空堆。

2.交换根节点与最后一个叶子节点,利用size从视觉上删除掉根节点(实际上没有删除,只是你访问不到了)

3.从根节点处向下调整,确保删除以后的堆还是一个堆。

注意点:

1.交换左右子节点时要保证右节点是存在的

2。向下调整的循环的条件是子节点的下标在数组的范围之内。

3.在执行删除操作的时候要确保堆内是有数据的。

2.5 堆顶元素

在堆中,堆顶元素就是下标为0的元素。所以找堆顶元素就是返回下标为0的元素。

代码:

HeapDataType HeapTop(Heap* php)
{
	assert(php);
	return php->a[0];
}

 2.6堆的长度

int Heapsize(Heap*php)
{
	assert(php);
	return php->size;//返回堆的长度
}

2.7堆的销毁

void HeapDstroy(Heap* php)
{
	free(php->a);//因为php->a是realloc出来的,所以为了避免内除泄漏,需要手动释放
	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

补充:

其实,当你用这样一个代码:

int main()
{
	Heap hp;
	HeapInit(&hp);
	int a[10] = { 1,80,50,90,4,8,7,5,6,10 };
	for (int i = 0;i < sizeof(a) / sizeof(a[0]);i++)
	{
		PushHeap(&hp, a[i]);
	}
	while (!HeapEmpty(&hp))
	{
		printf("%d\n", HeapTop(&hp));
		PopHeap(&hp);
	}
	HeapDstroy(&hp);
	return 0;
}

来打印这个堆里的元素的时候,你会发现:

 这个打印结果是很有序的,但是这不是排序。这只是将堆顶元素依次打印出来的结果。

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

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

相关文章

爆肝整理,接口测试到接口自动化测试小技巧,你的测试之路不再简单...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

Vue3 详细教程

文章目录 一、API 风格1.1 选项式 API1.2 组合式 API 二、Vue 指令2.1 {{}} 文本插值2.2 v-html 标签元素2.3 v-on 绑定事件2.4 v-show 隐藏元素2.5 v-if 消除元素2.6 v-bind 属性渲染2.7 v-for 列表渲染2.8 v-model 数据双向绑定 三、组件3.1 组件组合3.2 Props 组件交互3.3 自…

Linux:命令date、ntp查看和修改(校准)时间和地区。

Linux&#xff1a;命令date、ntp查看和修改&#xff08;校准&#xff09;时间和地区。 date -d 不仅可以1还可以加其他数字&#xff0c;表达后多久&#xff0c;-表达前多久&#xff1a; 备注&#xff1a;中国所在的时区是东八区 单独使用date时&#xff0c;会出现一串内容&…

Linux驱动入门——基础概念

文章目录 Linux内核简介Unix的历史Linux简介操作系统和内核简介单内核与微内核设计之比较小结 设备驱动简介驱动程序的角色划分内核设备和模块的分类安全问题版权条款 Linux驱动开发概述驱动程序概述设备驱动程序的作用设备驱动的分类Linux操作系统与驱动的关系Linux驱动开发编…

小程序容器技术在构建超级App的技术价值

今年来&#xff0c;随着软件及开源技术的发展&#xff0c;软件应用架构的概念也随之流行起来。它提供了一种组织和设计软件系统的有效方法&#xff0c;具有许多优势和好处&#xff1a; 模块化和可维护性&#xff1a;软件应用架构将系统拆分为模块化的组件&#xff0c;每个组件…

linux 部署jenkins

安装Jenkins 使用wget 命令下载Jenkins 先安装wget yum install wget ,如果已经安装过了&#xff0c;忽略直接到下一步; 若你的java环境为11~17&#xff0c;可以执行&#xff1a;wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war 若你的java环境为8&#xff0…

Python实战基础10-正则表达式

1、正则表达式 在处理字符串时&#xff0c;经常会有查找符合某些复杂规则的字符串需求。正则表达式就算用于描述这些规则的工具。换句话说&#xff0c;正则表达式就是记录文本规则的代码。 1.1 行定位符 行定位符就是用来描述字符串的边界&#xff0c;“A”表示行的开始&…

2023新星导师活动【electron+vue3】方向,开营知识点提纲(2)

文章目录 前言一、vue是什么&#xff1f;二、vue的优势1.依托数据渲染2.新人的边界2.选项式和组合式 总结 前言 上篇文章主要讲解了electron、nodejs的相关概念。本篇文章将主要介绍vue3&#xff0c;以及vue3如何与electron协作完成桌面端功能。 同上篇文章一样&#xff0c;这…

系统集成项目管理工程师 下午 真题 及考点(2019年上半年)

文章目录 一&#xff1a;第10章 项目质量管理&#xff0c;规划质量管理输出&#xff0c;质量成本法&#xff08;一致性成本【预防、评价】 和 非一致性成本【内部失败、外部失败】&#xff09;&#xff0c;七种工具二&#xff1a;第8章 项目进度管理&#xff0c;总浮动时间&…

2023高频前端面试题合集之网络篇

近期整理了一下高频的前端面试题&#xff0c;分享给大家一起来学习。如有问题&#xff0c;欢迎指正&#xff01; 欢迎大家关注该专栏&#xff1a;点赞&#x1f44d; 收藏&#x1f91e; 大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&…

数据结构学习分享之链式二叉树(二)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:数据结构学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你了解更多数据结构的知识   &#x1f51d;&#x1f51d; 数据结构第八课 1. 前言&a…

ClickHouse:(二)数据类型

1.整型 固定长度的整型分为&#xff1a;有符号和无符合整型 有符号整型无符号整型类型范围类型范围Int8 -128 : 127 UInt8 0 : 255 Int16 -32768 : 32767 UInt16 0 : 65535 Int32 -2147483648 : 2147483647 UInt32 0 : 4294967295 Int64 -9223372036854775808 : 9223372036854…

SpringSecurity框架|荣耀磨练

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

Unity之使用Photon Server + PUN2 开发局域网多人游戏

一.前言 Photon Engine是一款跨平台的实时多人游戏引擎,它提供了可靠的基础设施和工具,使开发者能够轻松地构建和部署多人游戏。Photon Engine支持多种平台,包括PC、移动设备和Web,同时还提供了多种语言的SDK,如C++、C#、Java、JavaScript等,使得开发者可以使用自己熟悉…

多元回归预测

多元回归就像线性回归&#xff08;一个变量预测一个值&#xff09;一样&#xff0c;但是具有多个独立值&#xff0c;这意味着我们试图基于两个或多个变量来预测一个值。 比如在线性回归中我们可以根据发动机排量的大小预测汽车的二氧化碳排放量&#xff0c;但是通过多元回归&a…

Kotlin泛型<in, out, where>概念及示例

Kotlin泛型<in, out, where>概念及示例 在 Kotlin 中&#xff0c;泛型用于指定类、接口或方法可以操作的对象类型。 in in关键字用于指定泛型类型是“输入”类型&#xff0c;这意味着它将仅用作函数或类的参数。 interface ReadOnly {fun read(): Any }class ReadW…

设计模式期末复习随笔

1.以下是23种GOF设计模式对应的设计原则&#xff1a; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;&#xff1a;遵循开闭原则&#xff0c;客户端不需要修改就能够新增产品类型。 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;遵…

【严重】Kibana 8.7.0 任意代码执行漏洞

漏洞描述 Kibana是用于Elasticsearch的数据可视化仪表板。Kibana在8.7.0版本引入了Synthetic监控功能&#xff0c;用户可配置编写playwright中的javascript代码实现web应用监控。 具备Kibana登录权限的攻击者可利用此功能编写恶意playwright脚本&#xff0c; 从而在Kibana主机…

5.28 深圳活动|Jina AI 生态助力云原生场景下的 AIGC 应用开发

亚马逊云科技 Community Day 将于 5 月 28 日 在深圳南山区海德酒店 11 楼举办&#xff0c;Jina AI 软件工程师付杰将带来 《Jina AI 生态助力云原生场景下的 AIGC 应用开发》 的主题演讲。 Community Day 是亚马逊云科技全球品牌和社区旗舰活动&#xff0c;由社区领导者发起&a…

5个替代Zendesk的全面指南!

Zendesk是一种广受欢迎的客户支持软件解决方案&#xff0c;适用于各种规模的企业。然而&#xff0c;还有其他几种产品可以取代Zendesk&#xff0c;提供类似甚至更好的功能。在本文中&#xff0c;我们将探索市场上一些最好的Zendesk替代方案。 1、Zoho Desk Zoho Desk是一款基…