数据结构二叉树顺序结构——堆的实现

二叉树顺序结构——堆的实现

  • 结构体的创建以及接口函数
  • 结构体的创建
  • 堆的初始化
  • 交换函数
  • 堆的插入
  • 向上调整
  • 删除
  • 向下调整
  • 返回堆的个数
  • 返回堆顶数据
  • 判断堆是否为空

该文章以大堆作为研究对象

结构体的创建以及接口函数

typedef int HPDateType;//定义动态数组的数据类型
typedef struct HeaP
{
	HPDateType* a;//指针
	int size;//有效数据个数,也是即将插入的下一个有效数据的下标
	int capacity;//容量
}HP;

void HeapInit(HP* php);//堆的初始化

Swap(HPDateType* a, HPDateType* b);//交换函数

void AdjustUp(HPDateType* a, int child);//向上调整

void HeapPush(HP* php,int x);//堆的插入

void AdjustDown(HPDateType* a, int n, int parent);//向下调整

void AdjustDownSmall(HPDateType* a, int n, int parent);//向下调整(小堆)  

void HeapPop(HP* php);//删除

int HeapSize(HP* php);//返回堆的个数

HPDateType HeapTop(HP* php);//返回堆顶数据

bool HeapEmpty(HP* php);//判断是否为空 空返回ture 非空返回false

结构体的创建

  • 宏定义一个堆的数据类型,方便堆数据类型的控制
  • 堆用顺序结构来存储,由于将来会有多种接口函数对堆进行操作,所以将堆放在动态存储空间中
typedef int HPDateType;//定义动态数组的数据类型
typedef struct HeaP
{
	HPDateType* a;//指针
	int size;//有效数据个数,也是即将插入的下一个有效数据的下标
	int capacity;//容量
}HP;

堆的初始化

初始为堆开辟4个堆数据类型的空间,这里堆的数据类型为int ,也就初始开辟4个int的空间,16个字节的空间。

void HeapInit(HP* php)//堆的初始化
{
	assert(php);//断言防止空指针的引用
	php->a = (HPDateType*)malloc(sizeof(HPDateType) * 4);//初始容量为4
	if (php->a == NULL)
	{
		perror("HeapInit failed");
		return;
	}
	php->size = 0;//初始数据为0
	php->capacity = 4;//初始容量为4	
}

交换函数

因为交换函数在各种函数中多次运用,这里专门写一个函数来用

Swap(HPDateType* a, HPDateType* b)//交换函数
{
	HPDateType temp = *a;
	*a = *b;
	*b = temp;
}

堆的插入

插入函数要的任务是,新数据的插入原来堆的性质。比如下面这个大堆,100作为新数据的插入(左图),他现在的结点位置破坏了堆的性质。所有需要将新插入的数据进行调整,后面会讲到两种调整方法,这里用到的是向上调整法(原理在下面,这里建议先去下面看向上调整),向上调整后100就会到适配于这个堆的位置(右图)。
在这里插入图片描述

利用这个原理,若我们可以将一个数组的数据一个一个的插入到堆当中去。
在这里插入图片描述
所以插入一个数据只需要赋值进来后进行向上调整

void HeapPush(HP* php, int x)//堆数据的插入
{
	assert(php);//防止空指针的引用
	php->a[php->size] = x;//插入数据
	AdjustUp(php->a, php->size);//新数据的插入检查是否符合堆的结构,所以直接向上调整
	php->size++;//堆结构体的有效数据变量自增
}

向上调整

前文说道该函数功能就是将新插入的数据调整到适配于这个堆的位置。那么怎么实现呢?
显然向上调整的条件就是首先原来的数据的结构符合一个堆。
思路就是新插入的数据和他的父亲结点比较,若孩子比父亲大则交换,反复循环;若孩子比父亲小的话符合大堆,则说明新插入的数据符合大堆,所以不需要调整;
这里向上调整函数的形参传入的是数组,因为后面还可能用到他,所以形参没有传堆结构体指针。
孩子的父亲节点parent = (child-1)/2 这个知识点也是一个要点

void AdjustUp(HPDateType* a,int child)//向上调整(大堆) 时间复杂度O(logN)
{
	int parent = (child - 1) / 2;//锁定要调整孩子的父亲结点
	while (child > 0)//最坏的情况是孩子的下标为1,父亲的下标为0,所以限制条件就是child>0
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);//数据交换,也就是向上调整
			child = parent;//这时候原数据对应的下标也应该向上调整
			parent = (child - 1) / 2;//调整后的父亲节点的下标
		}
		else//孩子小于父亲节点符合大堆不需要交换
		{
			break;
		}
	}
}

删除

删除函数如果说只删除堆尾的话,虽然简单但没有意义,因为堆尾并不是一个特殊的位置,反而堆顶是一个能体现出来堆性质的一个结点,所以堆的删除一般都是删除堆顶。
那么这时候就要考虑怎么删除堆顶,然后不能将其原来的数据结构打乱。如果是平移删除的话只会将原来堆的结构打乱,大费周章。这时候会用到向下调整(建议先去下面看向下调整原理)。所以这时候删除就很简单了,首先将堆顶和堆尾交换数据,然后再size–,从堆顶的位置进行向下调整即可。

void HeapPop(HP* php)//删除
{
	//思路:交换堆顶和堆尾的数据,然后删除最后一个数据,然后将新的堆进行向下调整
	Swap(&php->a[0], &php->a[php->size - 1]);//交换第一个数据和最后一个数据
	php->size--;//删除数组最后一个数据
	AdjustDown(php->a,php->size,0);//这里size已经自减过一次了,所以传参直接传size刚好
}

向下调整

向下调整适用的条件是:调整位置的左右子树都符合堆的结构。
思路:将调整位置与其孩子结点作比较,若父亲结点小于较大的孩子结点则交换数据;若大于较大的孩子结点则不需要进行调整。
孩子结点与父亲结点的关系:

leftchild=parent * 2+1;
rightchild=parent * 2+2;

该函数的传参问题:因为方便后续的使用,形参传参一个数组和数组的大小和调整结点下标;因为要进行父亲结点和孩子结点的不断比较,需要存储堆数据的数组元素个数作为循环的限制条件,所以要传参一个n,例如
在这里插入图片描述

void AdjustDown(HPDateType* a, int n, int parent)//向下调整  时间复杂度O(logN)
//向下调整的条件是调整节点的左右子树都为大堆或者小堆
//思路为从下标为parent位置开始向下的孩子节点不断比较进行调整,直到最后一个数据,
//所以需要传参堆的有效数据个数n
{
	int leftchild = parent * 2 + 1;//这里默认左孩子大于右孩子
	while (leftchild < n)
	{
		int rightchild = parent * 2 + 2;
		if (rightchild < n && a[leftchild] < a[rightchild])
		{
			//rightchild < n是判断一下该父亲节点是否有右孩子,防止数组越界
			//默认左孩子大于右孩子
			//若右孩子大于左孩子则交换下标
			Swap(&leftchild, &rightchild);
		}
		if (a[parent] < a[leftchild])
		{
			Swap(&a[parent], &a[leftchild]);//若不符合堆的要求则交换
			parent = leftchild;//将原父亲数据对应下标也赋值过来
			leftchild = parent * 2 + 1;//新的孩子的下标
		}
		else//若符合堆的要求就退出循环
		{
			break;
		}
	}

}

返回堆的个数

堆的个数就用int类型就好了,所以返回类型为int

int HeapSize(HP* php)//返回堆的个数
{
	assert(php);
	return php->size;
}

返回堆顶数据

因为返回值是堆顶数据,所以返回类型为堆的数据类型

HPDateType HeapTop(HP* php)//返回堆顶数据
{
	assert(php);
	return php->a[0];
}

判断堆是否为空

返回值为布尔类型——bool,当堆的有效数据size为0,则证明堆为空

bool HeapEmpty(HP* php)//判断是否为空,空返回ture 非空返回false
{
	assert(php);
	return php->size == 0;
}

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

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

相关文章

Spring Cloud学习

1、什么是SpringCloud Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序&#xff0c;提供与外部系统的集成。Spring cloud Task&#xff0c;一个生命周期短暂的微服务框架&#xff0c;用于快速构建执行有限数据处理的应用程序。Spring cloud 流应用程…

Oracle ADG相关介绍

文章目录 一、ADG原理1、ADG介绍2、ADG搭建流程 二、ADG相关参数三、增量修复 一、ADG原理 1、ADG介绍 Oracle ADG&#xff08;Advanced Data Guard&#xff09;是Oracle数据库的一项高可用和灾难恢复技术&#xff0c;它通过将数据保持在物理备库中来提供数据保护和容灾能力。…

Odoo系统安装部署并结合内网穿透实现固定域名访问本地ERP系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

C++ 游戏飞机大战, 字符型的

//#define _CRT_SECURE_NO_WARNINGS 1 用于禁止不安全函数的警告 #include<iostream> #include<stdlib.h> #include<string> #include<conio.h> #include<Windows.h> #include<time.h> #include <graphics.h> using namespace std;…

Python爬虫-付费代理推荐和使用

付费代理的使用 相对免费代理来说&#xff0c;付费代理的稳定性更高。本节将介绍爬虫付费代理的相关使用过程。 1. 付费代理分类 付费代理分为两类&#xff1a; 一类提供接口获取海量代理&#xff0c;按天或者按量收费&#xff0c;如讯代理。 一类搭建了代理隧道&#xff0…

一元函数微分学——刷题(22

目录 1.题目&#xff1a;2.解题思路和步骤&#xff1a;3.总结&#xff1a;小结&#xff1a; 1.题目&#xff1a; 2.解题思路和步骤&#xff1a; 由于是极坐标方程&#xff0c;所以这个式子一定成立&#xff1a; 然后代入r即可变为参数方程的求导&#xff1a; 3.总结&#xff…

52.仿简道云公式函数实战-文本函数-LEFT

1. LEFT函数 从一个文本字符串的第一个字符开始返回指定个数的字符。 2. 函数用法 LEFT(text,[num_chars]) 3. 函数示例 从一个文本字符串的第一个字符开始返回指定个数的字符。 4. 代码实战 首先我们在function包下创建text包&#xff0c;在text包下创建LeftFunction类…

POST参数里加号+变成空格的问题处理

今天遇到个这样的问题&#xff0c;从前端传到后端的加密报文&#xff0c;里面包含了号&#xff0c;但在后端日志输出看出&#xff0c;变成空格。这个是由于经过RSA加密后引起的 解决办法&#xff1a; 1.前端转码&#xff1a;使用encodeURIComponent对参数进行转码 2.后端解码…

msvcp110.dll找不到的处理方法,一键修复msvcp110.dll文件

如果你遭遇到了“msvcp110.dll文件丢失”的现象&#xff0c;那就要引起足够的重视&#xff0c;因为这通常意味着你的电脑上某些依赖此DLL文件的应用程序将无法正常启动。msvcp110.dll是许多软件中必须的组件&#xff0c;一旦发生丢失&#xff0c;影响的不仅是单个程序&#xff…

Java SpringBoot 整合 MyBatis 小案例

Java SpringBoot 整合 MyBatis 小案例 基础配置&#xff08;注意版本号&#xff0c;容易报错&#xff09; pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http…

武汉灰京文化:中国手游行业新技术的涌现与产业链的完善

中国手游行业正迎来新技术的涌现&#xff0c;如虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能&#xff08;AI&#xff09;。这些技术为游戏提供了全新的可能性&#xff0c;扩展了游戏的玩法和体验。例如&#xff0c;VR技术可以让玩家沉浸…

卖家横扫海外露营市场的机会来了,赛盈分销预测2024年消费者新需求

甲辰龙年开篇&#xff0c;就要迎来国外野营浪潮了&#xff0c;希望点开这篇推送的你&#xff0c;红红火火、热辣滚烫一整年。每年的3月份&#xff0c;海外用户对露营设备的搜索开始迅速增长。今天和大家聊聊露营市场出海的一些布局方向。 全球露营商品的市场规模愈发壮大&#…

Maven jar 的查找及依赖版本确定

关于 jar 的查找&#xff0c;及使用版本的确定&#xff0c;及依赖的版本确认&#xff0c;避免 jar 冲突或版本不兼容 在使用 maven 构建项目时&#xff0c;需要的 jar 可以通过在 https://mvnrepository.com/ 可以找到部分需要的依赖&#xff0c;这里以查找 mybatis 依赖为例&…

再次委托|工科背景老师赴美国斯坦福大学自费访学

工科背景的I老师&#xff0c;几年前曾通过我们获得美国哈佛大学医学院的无薪博士后职位&#xff0c;从事医工交叉学科研究。回国完成2年服务期后&#xff0c;I老师再次委托并仍希望去美国顶尖高校&#xff0c;最终我们落实了世界名校斯坦福大学的访问学者职位&#xff0c;满足了…

微信小程序自制动态导航栏

写在前面 关于微信小程序导航栏的问题以及解决办法我已经在先前的文章中有提到&#xff0c;点击下面的链接即可跳转~ &#x1f90f;微信小程序自定义的导航栏&#x1f90f; 在这篇文章中我们需要做一个这样的导航栏&#xff01;先上效果图 &#x1f447;&#x1f447;&#x1f…

HTTP/HTTPS协议

什么是HTTP协议 HTTP被称为超文本传输协议(里面不仅仅可以是字符串,还可以是图片,特殊字符等),这是一种应用非常广泛的应用层协议. HTTP协议诞生于1991年,现在是最主流使用的一种应用层协议.它从诞生到现在为止迭代了多个版本. 但目前最主流使用的还是HTTP1.1和HTTP2.0. HTTP协…

大学餐厅菜品推荐和点评系统设计与实现

**&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;**一 、设计说明 1.1 研究背景…

Opencv(2)深浅拷贝与基本绘图(c++python

Opencv(2)深浅拷贝与基本绘图 文章目录 Opencv(2)深浅拷贝与基本绘图三、深浅拷贝四、HSV色域(1).意义(2).cvtColor()(3).inRange()(4).适应光线 三、深浅拷贝 浅拷贝是指当图像之间进行赋值时&#xff0c;图像数据并未发生复制&#xff0c;而是两个对象都指向同一块内存块。 …

Amazon Generative AI | 基于 Amazon 扩散模型原理的代码实践之采样篇

以前通过论文介绍 Amazon 生成式 AI 和大语言模型&#xff08;LLMs&#xff09;的主要原理之外&#xff0c;在代码实践环节主要还是局限于是引入预训练模型、在预训练模型基础上做微调、使用 API 等等。很多开发人员觉得还不过瘾&#xff0c;希望内容可以更加深入。因此&#x…

鲲鹏arm64架构下安装KubeSphere

鲲鹏arm64架构下安装KubeSphere 官方参考文档: https://kubesphere.io/zh/docs/quick-start/minimal-kubesphere-on-k8s/ 在Kubernetes基础上最小化安装 KubeSphere 前提条件 官方参考文档: https://kubesphere.io/zh/docs/installing-on-kubernetes/introduction/prerequi…