数据结构进阶之堆

今天我们学习的是数据结构里面的,大家先看看我们今天要学习的内容

一、堆概念及认识

在学习堆之前我们得先明白完全二叉树是什么样子,因为堆是依据完全二叉树的结构来实现的,所以在这里我先告诉大家完全二叉树的是什么,如下图:

完全二叉树就是从根节点开始依次往下延伸展开,其他层都是满节点,只有最后一层不同,最后一层可满可不满,但是最后一层必须是从左往右,这就是完全二叉树,也就是堆的逻辑结构。

堆的概念及认识:堆是一种数据结构,分为大堆和小堆,数据从上开始往下排序,上一层的数据如果大于下一层的每个数据,那么它就是大堆,反之就是小堆。

二、堆的结构及操作原理

堆的逻辑结构就是完全二叉树的结构,但是我们要实现自己的堆就需要了解堆的物理结构,它是如何实现对数据的储存的,在这里实现堆我们用数组来实现堆,大家可能会一脸懵,所以接下来我向大家解释为什么用数组来实现。

先看下图来理解:

如果把上层看作父节点,下层看作子节点,再看看它们的的数组下标大家会不会发现父子节点之间存在某种关系,这也是其他大佬发现的规律,在这里我直接告诉大家,用 parent 作为父节点的下标,child 作为子节点的下标,就会有下面的下标规律

child = 2 * parent + 1 ,parent = (child - 1)/  2 。

因为有上面的规律,所以我们实现自己的堆才选择用数组来储存,上面的规律也是堆实现的底层逻辑。

三、堆的实现

在这里我们以实现小堆为例,首先我得先告诉大家小堆的储存结构,大家先看下图:

如果是小堆,那么上一层的数据必须小于下一层的数据,并且最高层的数据是最小的,这就是小堆。那么接下来我们就来实现一个自己的堆。

首先需要创建一个结构体用来储存堆的数组和堆的大小和堆的数据个数,如下:

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;// 堆的物理结构时数组,逻辑结构是满二叉树或完全二叉树int size;int capacity;
}HP;

接下来我们先写出最简单的堆的初始化和销毁和一个交换函数,如下:

//堆的初始化
void HPInit(HP* hp)
{assert(hp);hp->a = NULL;hp->capacity = hp->size = 0;
}//堆的销毁
void HPDestroy(HP* hp)
{assert(hp);free(hp->a);hp->capacity = hp->size = 0;
}//实现交换数据
void Swap(HPDataType* hp1, HPDataType* hp2)
{HPDataType tem = *hp1;*hp1 = *hp2;*hp2 = tem;
}

最难的部分就是堆数据放入时的向上调整,因为是小堆,所以上一层的数据必须小于下一层的每个数据,所以每次放进一个数据就要向上进行调整,用来保证小堆的结构,那如何来实现数据的想上调整呢,请看下面:

根据上面的讲解我们开始实现向上调整,请结合代码中的注释加以理解:

//堆数据的向上调整 时间复杂度:O(logN)
void AdjustUp(HP* hp, int child)
{assert(hp);assert(hp->size > 0);// 截至条件是 当最后一次的子节点小于或者等于0的时候 说明上层没有数据 也就不用再向上调整了while (child > 0){// 实现数据的交换// 根据父子的关系规律来找到父节点int parent = (child - 1) / 2;if (hp->a[parent] > hp->a[child]){//交换Swap(&(hp->a[parent]), &(hp->a[child]));child = parent;}else{// 如果已经符合小堆 就直接退出break;}}
}

有了上面的向上调整,我们就可以开始实现数据的入队列了,操作如下:

//堆的放入数据
void HPPush(HP* hp, HPDataType x)
{assert(hp);if (hp->capacity == hp->size){// 堆内存的开辟int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;HPDataType* tem = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);if (tem == NULL){perror("realloc");exit(1);}hp->a = tem;hp->capacity = newcapacity;}// 堆数据的放入hp->a[hp->size] = x;hp->size++;// 每次放入一个数据都需要进行向上调整来保证小堆的完整性AdjustUp(hp, hp->size - 1);
}

接下来我们继续实现堆的其他简单操作,如下:

//获取堆顶数据
HPDataType HPTop(HP* hp)
{assert(hp);return hp->a[0];
}//堆中的数据个数
int HPSize(HP* hp)
{assert(hp);return hp->size - 1;
}//堆的判空
bool HPEmpty(HP* hp)
{assert(hp);return hp->size == 0;
}

 接下来还有一个难点就是堆顶数据的删除,首先我们得了解一下堆顶数据是如何进行删除的,我来告诉大家,堆顶数据的删除不是真的删除,而是把堆顶的数据和堆的最后一位数据进行交换,并且对堆顶的数据再进行向下调整,来保证小堆的结构。上面我有提到了向下调整,这其实和向上调整一样,请大家看原理图:

那为什么要和两个子节点中较小的进行比较呢,因为要符合小堆,必须最高层数据是最小值,所以要和两个子节点中较小的进行比较,实现如下请结合注释一起理解:

//堆数据的向下调整 时间复杂度:logN
void AdjustDown(HP* hp, int parent)
{assert(hp);// 用父子节点之间的规律来找到子节点int child = 2 * parent + 1;// 退出条件为 最后一次的子节点超出堆的大小就不用在进行向下调整 直接退出循环while (child < hp->size){// 要判断两个子节点中的最小值 首先这个父节点下面要有两个子节点才可以 如果没有就直接和子节点比较饥渴if (child + 1 < hp->size){if (hp->a[child] > hp->a[child + 1]){// 假设法选出两个儿子中的最小值child = child + 1;}}if (hp->a[parent] > hp->a[child]){// 交换两个值Swap(&(hp->a[child]), &(hp->a[parent]));parent = child;child = 2 * parent + 1;}else{// 如果没有交换 说明满足小堆的结构 直接退出即可break;}}}

接下来堆顶数据的删除就可以结合堆顶数据的删除原则(如堆顶数据删除的原理图)就可以写出来了,如下:

//堆顶数据的删除
void HPPop(HP* hp)
{assert(hp);Swap(&(hp->a[0]), &(hp->a[hp->size - 1]));hp->size--;AdjustDown(hp, 0);
}

这就是堆的实现,大家还有什么不会的或者没理解的,可以评论区留言或者私信我,我来帮大家解答。

好了,今天的内容就到这,下期再见!!!

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

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

相关文章

linux运行ant 报错 Unable to locate tools.jar【已解决】

linux安装 ant 运行时报错 Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/lib/tools.jar 原因 已安装的jdk只有运行环境&#xff0c;没有tool.jar&#xff0c;而ant运行需要java开发环境&#xff0c;因…

通过腾讯云搭建跨境电商demo的详细操作过程(建站系统 保姆级指导,巨详细)

引言&#xff1a; 有许多做跨境电商的朋友&#xff0c;或者为跨境电商服务的小企业&#xff0c;都会面临搭建电商平台V1.0的问题 因此&#xff0c;花了点时间&#xff0c;找了一个开源的项目&#xff0c;让大家可以跑起来&#xff0c;一方面了解平台都有哪些模块&#xff0c;另…

JVM虚拟机(九)如何开启 GC 日志

目录 一、引言二、开启 GC 日志三、解析 GC 日志四、优化建议 一、引言 在 Java 应用程序的运行过程中&#xff0c;垃圾收集&#xff08;Garbage Collection&#xff0c;简称 GC&#xff09;是一个非常重要的环节。GC 负责自动管理内存&#xff0c;回收不再使用的对象所占用的…

Cisco ACI使用Postman配置交换机-未完待续

先看下不使用脚本的情况下是怎么配置交换机端口的&#xff1f; 例&#xff1a; 有10个交换机接口要开trunk&#xff0c;透传50个vlan&#xff0c; 使用GUI的操作方式为 1 进入EPG -->Static port 2 右键&#xff0c;绑定接口 3 选中node -->指定接口—>指定vlan —>…

Python SQL解析和转换库之sqlglot使用详解

概要 Python SQLGlot是一个基于Python的SQL解析和转换库,可以帮助开发者更加灵活地处理和操作SQL语句。本文将介绍SQLGlot库的安装、特性、基本功能、高级功能、实际应用场景等方面。 安装 安装SQLGlot库非常简单,可以使用pip命令进行安装: pip install sqlglot安装完成后…

我用这10招,能减少了80%的BUG

前言 对于大部分程序员来说&#xff0c;主要的工作时间是在开发和修复BUG。 有可能修改了一个BUG&#xff0c;会导致几个新BUG的产生&#xff0c;不断循环。 那么&#xff0c;有没有办法能够减少BUG&#xff0c;保证代码质量&#xff0c;提升工作效率&#xff1f; 答案是肯…

固定资产管理系统解决方案(Word原件)

固定资产管理系统解决方案 1系统概述 1.1需求描述 1.2需求分析 1.3重难点分析 1.4重难点解决措施 2系统架构设计 2.1系统架构图 2.2关键技术 3系统功能设计 3.1功能清单列表 3.2资产采购 3.3资产验收 3.4资产入库 3.5资产领用 3.6资产出库 3.7资产维修 3.8资产…

景区导览系统平台|智能导览|数字人导游|VR游园

随着人工智能、元宇宙等技术的飞速发展&#xff0c;文旅行业正迎来一场前所未有的变革。道可云文旅元宇宙平台以其独特的智慧景区导览系统、元宇宙空间以及数字人导游等创新应用&#xff0c;为景区和游客带来了全新的旅游体验&#xff0c;也标志着文旅行业正式步入了元宇宙时代…

超声波清洗机哪个品牌好?四款超值超声波清洗机汇总安利

在我们的日常生活中&#xff0c;眼镜已经成为了许多人不可或缺的伙伴&#xff0c;无论是度数眼镜还是防护眼镜&#xff0c;它们都为我们的生活带来了极大的便利。然而&#xff0c;随着频繁的使用&#xff0c;眼镜上积累的污渍和细菌也在悄悄增加&#xff0c;长时间不清洁不仅会…

CAD二次开发 快速选择插入其他项目块

需求&#xff1a;选择其他CAD文件&#xff0c;展示选择CAD文件中所有的块定义&#xff0c;然后选择需要插入的块&#xff0c;鼠标有块定义的跟随&#xff0c;点击放置块定义。 实现效果 代码 1.定义BlockJig拖拽类 public class BlockJig : EntityJig {private Point3d _curr…

开源项目|使用go语言搭建高效的环信 IM Rest接口(附源码)

项目背景 环信 Server SDK 是对环信 IM REST API 的封装&#xff0c; 可以节省服务器端开发者对接环信 API 的时间&#xff0c;只需要配置自己的 App Key 相关信息即可使用。 环信目前提供java和PHP版本的Server SDK&#xff0c;此项目使用go语言对环信 IM REST API 进行封装…

plsql developer 一键格式化sql/美化sql

PL/SQL 格式化工具 以 Oracle SQL Developer 为例&#xff0c;使用一键格式化的步骤如下&#xff1a; 打开 Oracle SQL Developer。在“文件”菜单中&#xff0c;选择“打开文件”&#xff0c;然后选择你的 PL/SQL 文件。打开文件后&#xff0c;你可以通过右键菜单选择“格式…