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

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

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

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

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

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);//初始容量为4if (php->a == NULL){perror("HeapInit failed");return;}php->size = 0;//初始数据为0php->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;
}

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

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

相关文章

020—pandas 根据历史高考分段推断当前位次的分数

前言 每年各省都会公布高考「一分一段」表&#xff0c;它是是以「一分」为单位&#xff0c;统计考得该分数的考生人数和累计人数&#xff0c;每一个分数段上有多少人一目了然。考生通过分数分布表可以查询到相关成绩在全市的排名位次&#xff0c;方便对自己进行定位。本例中&a…

Vue packages version mismatch 报错解决

问题 npm run dev 运行项目的过程中&#xff0c;报错 Vue packages version mismatch 解决方法 根据报错不难看出是 vue 与 vue-template-compiler 版本产生了冲突&#xff0c;vue 与 vue-template-compiler 的版本是需要匹配的。所以解决的办法就是先修改其中一个的版本将 v…

【深度学习笔记】3_14 正向传播、反向传播和计算图

3.14 正向传播、反向传播和计算图 前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中&#xff0c;我们只提供了模型的正向传播&#xff08;forward propagation&#xff09;的计算&#xff0c;即对输入计算模型输出&#xff0c;然后通过autograd模块来调…

mysql的日志文件在哪?

阅读本文之前请参阅----MySQL 数据库安装教程详解&#xff08;linux系统和windows系统&#xff09; MySQL的日志文件通常包括错误日志、查询日志、慢查询日志和二进制日志等。这些日志文件的位置取决于MySQL的安装和配置。以下是一些常见的日志文件位置和如何找到它们&#xff…

电子签证小程序系统源码后台功能列表

基于ThinkPhp8.0uniapp 开发的电子签证小程序管理系统。能够真正帮助企业基于微信公众号H5、小程序、wap、pc、APP等&#xff0c;实现会员管理、数据分析,精准营销的电子商务管理系统。可满足企业新零售、批发、分销、预约、O2O、多店等各种业务需求&#xff0c;快速积累客户、…

从专业到大众:Sora如何颠覆传统视频制作模式

随着科技的飞速进步&#xff0c;人工智能(AI)技术正逐渐渗透到我们生活的方方面面。在视频制作领域&#xff0c;OpenAI推出的Sora模型为这一传统行业带来了前所未有的变革。Sora不仅改变了视频制作的技术门槛&#xff0c;更将视频制作从专业人士的手中解放出来&#xff0c;推向…

【线程池项目(三)】线程池CACHED模式的实现

在上一篇【线程池项目&#xff08;二&#xff09;】线程池FIXED模式的实现 中我们了解到到线程池fixed模式的大致实现原理&#xff0c;但对于一个比较完整的项目来说&#xff0c;我们还需要考虑到可能会发生的各种情况&#xff0c;比如用户提交的任务数可能在某一时刻急剧增加&…

贪心算法---前端问题

1、贪心算法—只关注于当前阶段的局部最优解,希望通过一系列的局部最优解来推出全局最优----但是有的时候每个阶段的局部最优之和并不是全局最优 例如假设你需要找给客户 n 元钱的零钱&#xff0c;而你手上只有若干种面额的硬币&#xff0c;如 1 元、5 元、10 元、50 元和 100…

【数据结构】排序(1)

目录 一、概念&#xff1a; 二、直接插入排序&#xff1a; 三、希尔排序&#xff1a; 四、直接选择排序&#xff1a; 五、堆排序&#xff1a; 六、冒泡排序&#xff1a; 一、概念&#xff1a; 排序的概念&#xff1a; 使一串记录&#xff0c;按照其中的某个或某些关键字…

Canvas实现打砖块

一.预览 二.代码 <!DOCTYPE html> <html lang"en"> <head><title>打砖块</title><style>#myCanvas {background: #eee; /* 设置画布的背景颜色为浅灰色 */display: block;margin: 0 auto; /* 使画布在页面中居中显示 */}</s…

高原制氧机的工作原理以及对高原地区生活质量的积极影响

在广袤的高原地区&#xff0c;空气稀薄&#xff0c;氧气含量相对较低&#xff0c;给当地居民和外来游客带来了不小的困扰。然而&#xff0c;随着科技的飞速进步&#xff0c;高原制氧机应运而生&#xff0c;成为改善高原生活质量的重要利器。恒业通将探讨高原制氧机的工作原理、…

【算法与数据结构】463、LeetCode岛屿的周长

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;直接利用公式法&#xff0c;遇到一对相邻的陆地&#xff0c;总周长就减去2。那么周长公式为&#xff1…

微服务篇之任务调度

一、xxl-job的作用 1. 解决集群任务的重复执行问题。 2. cron表达式定义灵活。 3. 定时任务失败了&#xff0c;重试和统计。 4. 任务量大&#xff0c;分片执行。 二、xxl-job路由策略 1. FIRST&#xff08;第一个&#xff09;&#xff1a;固定选择第一个机器。 2. LAST&#x…

打包了一个QGIS3.34分享给大家

春节期间一时兴起编译打包了一个最新的QGIS版本QGIS3.34!秉承咱一贯理念&#xff0c;方便您使用也方便您不用&#xff01;该工具还是被打包为绿色版&#xff0c;即下即用&#xff0c;不用安装更无须卸载。微云的下载速度也比官方快很多&#xff0c;能大大节约您的时间提高您的工…

JavaAPI常用类02

目录 基本数据类型封装类 包装类常用属性方法 8中基本数据类型各自所对应的包装类 以下方法以java.lang.Integer为例 代码 运行 装箱和拆箱 装箱 何为装箱 代码 范围问题 代码 运行 拆箱 代码 String类 概述 代码 运行 创建形式 画图讲解 代码 运行 构造…

vscode使用restClient实现各种http请求

vscode使用restClient实现各种http请求 一&#xff0c;安装插件 首先&#xff0c;我们要在vscode的扩展中&#xff0c;搜索rest Client&#xff0c;然后安装它&#xff0c;这里我已经安装过了。 安装后&#xff0c;我们就可以使用rest client插件进行http各种操作了。 二&…

leetcode刷题-删除链表的倒数第N个节点(一次循环)

题目描述 解题思路 这几天玩的时间比较长&#xff0c;没有坚持更新。 解题思路很简单&#xff0c;也算是比较经典的问题。首先可以通道暴力解决&#xff0c;首先计算出来链表的长度&#xff0c;然后计算出来链表的长度&#xff0c;然后找到距离删除位置的前一个位置&#xff0…

131.乐理基础-快速识别音程(一)

上一个内容&#xff1a;130.乐理基础-倍增音程、倍减音程-CSDN博客 上一个内容里练习的答案&#xff1a; 开始不用数音数就可以辨别音程的方法&#xff0c;首先是不含升降号记号的两个音&#xff08;两个白键&#xff09;该怎样判断 方法的核心&#xff0c;就是音名中e-f和b-…

代码随想录算法训练营第28天 |第七章 回溯算法part04

学习目标&#xff1a; 93.复原IP地址 78.子集 90.子集II 学习内容&#xff1a; 93.复原IP地址 /class Solution { public:// string path;vector<string> result;bool isValid(const string& s, int start, int end) {if(start>end)return false;if(s[start]0&a…

SELF-RAG 论文详解

论文&#xff1a; https://arxiv.org/pdf/2310.11511.pdf code&#xff1a; https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_self_rag.ipynb?refblog.langchain.dev 相关工作 RAG 尽管 RAG 方法可以通过检索生成得到更为准确的结果&#xff0…