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

       当大家看了鄙人的上一篇博客栈后,稍微猜一下应该知道鄙人下一篇想写的博客就是堆了吧。毕竟堆栈在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);//每次扩容*2if (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.rhkb.cn/news/331004.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于地理坐标的高阶几何编辑工具算法(4)——线分割面

文章目录 工具步骤应用场景算法输入算法输出算法示意图算法原理 工具步骤 选中待分割面&#xff0c;点击“线分割面”工具&#xff0c;绘制和面至少两个交点的线&#xff0c;双击结束&#xff0c;执行分割操作 应用场景 快速切分大型几何面&#xff0c;以降低面的复杂度&…

数据结构篇其三---链表分类和双向链表

​ 前言 数据结构篇其二实现了一个简单的单链表&#xff0c;链表的概念&#xff0c;单链表具体实现已经说明&#xff0c;如下&#xff1a; 单链表 事实上&#xff0c;前面的单链表本质上是无头单向不循环链表。此篇说明的双向链表可以说完全反过来了了。无论是之前的单链表还…

ElasticSearch - 删除已经设置的认证密码(7.x)

文章目录 Pre版本号 7.x操作步骤检查当前Elasticsearch安全配置停止Elasticsearch服务修改Elasticsearch配置文件删除密码重启Elasticsearch服务验证配置 小结 Pre Elasticsearch - Configuring security in Elasticsearch 开启用户名和密码访问 版本号 7.x ES7.x 操作步骤 …

从ES到ClickHouse,Bonree ONE平台更轻更快!

本文字数&#xff1a;8052&#xff1b;估计阅读时间&#xff1a;21 分钟 作者&#xff1a;博睿数据 李骅宸&#xff08;太道&#xff09;& 娄志强&#xff08;冬青&#xff09; 本文在公众号【ClickHouseInc】首发 本系列第一篇内容&#xff1a; 100%降本增效&#xff01;…

01-02.Vue的常用指令(二)

01-02.Vue的常用指令&#xff08;二&#xff09; 前言v-model&#xff1a;双向数据绑定v-model举例&#xff1a;实现简易计算器Vue中通过属性绑定为元素设置class 类样式引入方式一&#xff1a;数组写法二&#xff1a;在数组中使用三元表达式写法三&#xff1a;在数组中使用 对…

redis--redis Cluster

简介 解决了redis单机写入的瓶颈问题&#xff0c;即单机的redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素无中心架构的redis cluster机制&#xff0c;在无中心的redis集群当中&#xff0c;其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连…

数组和指针的联系(C语言)

数组和指针是两种不同的数据类型&#xff0c;数组是一种构造类型&#xff0c;用于存储一组相同类型的变量&#xff1b;而指针是一种特殊类型&#xff0c;专门用来存放数据的地址。数组名除了sizeof(数组名)和&数组名表示整个数组外&#xff0c;其他情况下都表示的是首元素的…

百度集团:AI重构,走到哪了?

内有自家公关一号“自曝”狼性文化&#xff0c;主动制造舆论危机。 外有&#xff0c;OpenAI、谷歌、字节、华为等大模型劲敌扎堆迭代新产品&#xff0c; 强敌环伺。 今天我们要说的是早就从BAT掉队的——百度。 最近&#xff0c;在武汉Aapollo Day 2024上&#xff0c;百度发布了…

增强ev代码签名证书2300

代码签名证书是软件开发者们确保软件完整性和安全性的重要工具之一。在各种类型的代码签名证书中&#xff0c;增强EV代码签名证书拥有许多独特的功能而受到企业开发者的欢迎&#xff0c;今天就随SSL盾小编了解增强EV代码签名证书的申请条件以及申请流程。 1.增强型EV代码签名证…

npm介绍、常用命令详解以及什么是全局目录

目录 npm介绍、常用命令详解以及什么是全局目录一、介绍npm的主要功能npm仓库npm的配置npm的版本控制 二、命令1. npm init: 初始化一个新的Node.js项目&#xff0c;创建package.json文件。package.json是一个描述项目信息和依赖关系的文件。2. npm install <package_name&g…

Linux 内核之 mmap 内存映射的原理及源码解析

文章目录 前言一、简介1. mmap 是什么&#xff1f;2. Linux 进程虚拟内存空间 二、mmap 内存映射1. mmap 内存映射的实现过程2. mmap 内存映射流程2.1 mmap 系统调用函数2.2 ksys_mmap_pgoff 函数2.3 vm_mmap_pgoff 函数2.4 do_mmap_pgoff 函数2.5 do_mmap 函数2.6 get_unmappe…

ElasticSearch操作之重置密码脚本

ElasticSearch操作之重置密码脚本 #!/bin/bash # 使用样例 ./ES密码重置.sh 旧密码 新密码# 输入旧密码 es_old_password$1# 设置新的密码变量 es_password$2# 正确响应 es_reponse{"acknowledged":true}# 检查Elasticsearch是否在运行 if pgrep -f elasticsearch &g…

DNF手游攻略:角色培养与技能搭配!游戏辅助!

角色培养和技能搭配是《地下城与勇士》中提升战斗力的关键环节。每个职业都有独特的技能和发展路线&#xff0c;合理的属性加点和技能搭配可以最大化角色的潜力&#xff0c;帮助玩家在各种战斗中立于不败之地。接下来&#xff0c;我们将探讨如何有效地培养角色并搭配技能。 角色…

Leetcode | 5-21| 每日一题

2769. 找出最大的可达成数字 考点: 暴力 数学式子计算 思维 题解 通过式子推导: 第一想法是二分确定区间在区间内进行查找是否符合条件的, 本题最关键的便是 条件确定 , 第二种方法: 一般是通过数学公式推导的,这种题目我称为数学式编程题 代码 条件判断式 class Solution { …

基于SSM的“医院门诊管理系统”的设计与实现(源码+数据库+文档)

基于SSM的“医院门诊管理系统”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能模块图 医院门诊管理系统首页页面图 用户登录界面图 管…

【数据结构】------C语言实现二叉树

作者主页&#xff1a;作者主页 数据结构专栏&#xff1a;数据结构 创作时间 &#xff1a;2024年5月20日 一、二叉树的定义 二叉树(Binary Tree) 是由n个结点构成的有限集(n≥0)&#xff0c;n0时为空树&#xff0c;n>0时为非空树。 对于非空树&#xff1a; 有且仅有一个根…

用这8种方法在海外媒体推广发稿平台上获得突破-华媒舍

在今天的数字时代&#xff0c;海外媒体推广发稿平台已经成为了许多机构和个人宣传和推广的有效途径。如何在这些平台上获得突破并吸引更多的关注是一个关键问题。本文将介绍8种方法&#xff0c;帮助您在海外媒体推广发稿平台上实现突破。 1. 确定目标受众 在开始使用海外媒体推…

基于STM32实现数字示波器

目录 引言环境准备数字示波器基础代码示例&#xff1a;实现数字示波器 ADC采样数据处理显示波形用户界面应用场景&#xff1a;信号分析与电子实验问题解决方案与优化收尾与总结 1. 引言 本教程将详细介绍如何在STM32嵌入式系统中使用C语言实现数字示波器&#xff0c;包括如何…

Kali Linux安装Xrdp远程桌面工具结合内网穿透实现远程访问Kali桌面

文章目录 前言1. Kali 安装Xrdp2. 本地远程Kali桌面3. Kali 安装Cpolar 内网穿透4. 配置公网远程地址5. 公网远程Kali桌面连接6. 固定连接公网地址7. 固定地址连接测试 前言 Kali远程桌面的好处在于&#xff0c;它允许用户从远程位置访问Kali系统&#xff0c;而无需直接物理访…

【maven与tomcat配置】如何正确配置maven及tomcat环境变量及运行Java项目 (附图文说明及下载包)

maven及tomcat配置详解 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、maven和tomcat是啥&#xff1f;&#x1f367;二、maven环境变量配置2.1获取maven包2.2创建本地仓库及修改配置A&#xff0e;校验是否安装javaB&#xff0e;创建本地maven存放仓库C&#xff…