数据结构之——堆

一、堆的基本概念

        堆是计算机科学中一类特殊数据结构的统称。它是一种完全二叉树,即除了最后一层外,其他层都是满的,并且最后一层的节点从左到右依次排列。在堆中,节点的值与父节点的值有特定的关系,从而分为最大堆和最小堆。

        最大堆的特性是对于每个节点,它的值都大于或等于其子节点的值。这意味着根节点的值是整个堆中的最大值。例如,在一个整数最大堆中,如果根节点的值为 100,那么它的两个子节点的值都小于或等于 100。

        最小堆则相反,对于每个节点,它的值都小于或等于其子节点的值。根节点的值是整个堆中的最小值。

        堆的这种特殊结构使得它在许多算法中都有重要的应用。例如,在优先队列的实现中,堆可以快速地插入和删除元素,同时保持队列的优先级顺序。在堆排序算法中,堆可以用来对数据进行高效的排序。

        堆的实现通常使用数组来表示完全二叉树。对于数组中的每个位置 i,其左子节点的位置为 2i + 1,右子节点的位置为 2i + 2,父节点的位置为 (i - 1) / 2。这种表示方法使得堆的操作可以在数组上高效地进行。

        总之,堆作为一种特殊的数据结构,具有完全二叉树的结构和特定的节点值关系,在计算机科学中有着广泛的应用。

二、堆的存储结构与实现

(一)存储结构介绍

        堆可以被看作是一棵树的数组对象。在存储结构上,堆与普通树有一些区别。普通树的存储方式可以有多种,如链式存储、数组存储等。而堆通常采用数组来存储完全二叉树,这样可以利用数组的索引关系快速定位节点的父子关系。

        孩子兄弟表示法是一种表示树结构的方式。在这种表示法中,每个节点有两个指针,分别指向其第一个孩子节点和下一个兄弟节点。相比之下,堆采用数组存储时,通过特定的索引计算可以快速找到节点的父子关系。例如,对于数组中的位置 i,其左子节点的位置为 2i+1,右子节点的位置为 2i+2,父节点的位置为 (i-1)/ 2。

        堆的这种存储结构使得在进行插入、删除等操作时,可以更高效地进行节点位置的调整,而不需要像链式存储那样进行复杂的指针操作。

(二)实现方法详解

1.结构体创建:可以定义一个结构体来表示堆,结构体中通常包含一个数组用于存储堆中的元素,以及一个表示堆大小的变量。

typedef struct Heap 
{int* data;int size;int capacity;
} Heap;

2.函数声明:声明一些用于操作堆的函数,如初始化堆、插入元素、删除元素等。

void initHeap(Heap* h, int capacity);
void insertHeap(Heap* h, int value);
void deleteHeap(Heap* h);

3.初始化:初始化堆时,分配一定大小的内存空间给数组,并设置堆的初始大小为 0。

void initHeap(Heap* h, int capacity) 
{h->data = (int*)malloc(capacity * sizeof(int));h->size = 0;h->capacity = capacity;
}

4.销毁:在不需要堆时,释放堆所占用的内存空间。

void destroyHeap(Heap* h) 
{free(h->data);h->size = 0;h->capacity = 0;
}

5.插入:插入元素时,首先将元素添加到堆的末尾,然后通过向上调整函数来维护堆的性质。

void insertHeap(Heap* h, int value) 
{if (h->size == h->capacity) {// 堆已满,需要进行扩容操作h->capacity *= 2;h->data = (int*)realloc(h->data, h->capacity * sizeof(int));}h->data[h->size++] = value;// 向上调整upAdjust(h);
}

        向上调整函数的作用是在插入元素后,从插入位置开始向上调整堆,以确保满足堆的性质。具体实现方式是比较当前节点与父节点的值,如果不满足堆的性质,则交换它们的值,然后继续向上调整,直到满足堆的性质为止。

void upAdjust(Heap* h) 
{// childIndex 初始化为堆中当前最后一个元素的索引int childIndex = h->size - 1;// parentIndex 为 childIndex 对应的父节点索引int parentIndex = (childIndex - 1) / 2;// 将最后一个元素的值保存在 temp 中,用于后续的调整操作int temp = h->data[childIndex];// 当 childIndex 大于 0(即还没有到达根节点)并且 temp 小于父节点的值时,进行向上调整while (childIndex > 0 && temp < h->data[parentIndex]) {// 将父节点的值赋给子节点h->data[childIndex] = h->data[parentIndex];// 更新 childIndex 为父节点的索引childIndex = parentIndex;// 重新计算新的父节点索引parentIndex = (childIndex - 1) / 2;}// 将 temp(即最初的最后一个元素的值)赋给调整后的位置h->data[childIndex] = temp;
}

三、堆的特性与区别

(一)数据结构堆与内存堆区差异

        在计算机科学中,数据结构中的堆与内存分配中的堆是不同的概念。

        数据结构中的堆是一种特殊的数据结构,通常是完全二叉树的形式,分为最大堆和最小堆。它具有特定的节点值关系,如最大堆中每个节点的值都大于或等于其子节点的值。数据结构堆的特点是可以快速进行插入和删除操作,同时保持特定的顺序。例如,在优先队列的实现中,堆可以快速地插入和删除元素,同时保持队列的优先级顺序。

        而内存分配中的堆区是指动态分配内存的区域。在程序运行时,程序员可以通过编程语言提供的函数在堆区分配内存空间。与栈区不同,堆区的内存分配和释放需要程序员手动管理。如果不及时释放不再使用的内存,可能会导致内存泄漏。

        与数据结构中的栈相比,数据结构堆是一种树形结构,而栈是一种线性结构。栈遵循后进先出(LIFO)的原则,而堆没有特定的进出顺序,主要是根据堆的性质进行插入和删除操作。

        内存分配中的栈区通常用于存储局部变量和函数调用信息,它的内存分配和释放由编译器自动管理,速度较快。而堆区的内存分配相对较慢,但是可以分配较大的内存空间。

(二)与普通树的区别

        在节点顺序方面,普通树的节点顺序没有特定的要求,可以是任意的。而堆是一种完全二叉树,除了最后一层外,其他层都是满的,并且最后一层的节点从左到右依次排列。此外,堆中的节点值与父节点的值有特定的关系,最大堆中每个节点的值都大于或等于其子节点的值,最小堆则相反。

        在内存占用方面,普通树的存储方式可以有多种,如链式存储、数组存储等。不同的存储方式内存占用情况不同。而堆通常采用数组来存储完全二叉树,这种存储方式可以利用数组的索引关系快速定位节点的父子关系,内存占用相对较为紧凑。

        在平衡方面,普通树可以是平衡的,也可以是不平衡的。而堆虽然是完全二叉树,但不一定是平衡的。最大堆和最小堆的平衡是通过节点值的关系来维持的,而不是通过树的高度来平衡。

        总的来说,堆与普通树在节点顺序、内存占用和平衡等方面都存在不同之处。这些不同之处使得堆在特定的算法和应用中具有独特的优势。

四、堆的应用场景

(一)优先级队列

        优先级队列是一种抽象数据类型,其中每个元素都有一个优先级,高优先级的元素先出队。堆非常适合实现优先级队列,因为它可以快速地插入和删除元素,同时保持队列的优先级顺序。例如,在 Java 中,PriorityQueue就是用堆实现的优先级队列。在定时任务轮训场景中,可以将任务按照优先级放入优先级队列,高优先级的任务先执行。在合并有序小文件场景中,可以将每个小文件的最小元素放入优先级队列,每次取出最小元素写入新文件,从而实现多个有序小文件的合并。

(二)求 Top K 值

        利用大顶堆或小顶堆可以找出数组中的最大或最小的前 K 个数。如果要找出最大的前 K 个数,可以使用小顶堆。首先将数组的前 K 个数构建一个小顶堆,然后从第 K + 1 个数开始遍历数组,如果当前元素大于堆顶元素,则将堆顶元素弹出,然后将当前元素插入堆中。遍历结束后,堆中的元素就是最大的前 K 个数。同理,如果要找出最小的前 K 个数,可以使用大顶堆。

(三)求中位数

        用大顶堆和小顶堆维护数据可以求出中位数。首先创建一个大顶堆和一个小顶堆,将数据依次添加到两个堆中。如果当前数据小于大顶堆的堆顶元素,则将其添加到大顶堆中;否则,将其添加到小顶堆中。然后平衡两个堆,使得大顶堆的元素个数和小顶堆的元素个数之差不超过 1。如果两个堆的元素个数相等,则中位数为两个堆顶元素的平均值;如果大顶堆的元素个数比小顶堆多 1,则中位数为大顶堆的堆顶元素。

(四)大数据量日志统计搜索排行榜

        在大数据量日志统计搜索排行榜中,可以结合散列表和堆来实现。首先,使用散列表统计每个关键词出现的次数。然后,将关键词和出现次数作为一个元组放入一个列表中。接着,使用小顶堆来维护出现次数最多的前 K 个关键词。每次插入一个新的元组时,如果堆的大小小于 K,则直接插入堆中;如果堆的大小等于 K 且新元组的出现次数大于堆顶元组的出现次数,则将堆顶元组弹出,然后插入新元组。这样,堆中的元组就是出现次数最多的前 K 个关键词。

五、总结与展望

        堆作为一种特殊的数据结构,具有诸多鲜明的特点。首先,它以完全二叉树的形式呈现,这种结构使得堆在存储和操作上具有一定的优势。通过特定的节点值关系,分为最大堆和最小堆,能够快速进行插入和删除操作,同时保持特定的顺序。

        在应用场景方面,堆的表现极为出色。在优先级队列中,它能够确保高优先级的元素先出队,为各种任务调度和资源分配提供了高效的解决方案。例如在定时任务轮训和合并有序小文件场景中,优先级队列的应用大大提高了工作效率。

        求 Top K 值也是堆的一个重要应用。通过大顶堆或小顶堆,可以快速找出数组中的最大或最小的前 K 个数,为数据分析和处理提供了有力的工具。

        在求中位数方面,大顶堆和小顶堆的配合使用,能够准确地求出中位数,为统计分析提供了便捷的方法。

        在大数据量日志统计搜索排行榜中,结合散列表和堆,可以快速找出出现次数最多的前 K 个关键词,为大数据分析提供了有效的手段。

        总之,堆在数据结构中具有重要的地位。它的高效性和灵活性使其在各种算法和应用中发挥着关键作用。随着计算机技术的不断发展,尤其是在大数据和实时处理需求不断增长的背景下,堆的应用前景将更加广阔。未来,我们可以期待堆在更多领域的创新应用,为解决复杂的计算问题提供更加高效的解决方案。

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

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

相关文章

TMDOG的Gin学习笔记_02——Gin集成支付宝支付沙箱环境

TMDOG的Gin学习笔记_02——Gin集成支付宝支付沙箱环境 博客地址&#xff1a;TMDOG的博客 作者自述&#xff1a; 最近忙着整理自己的项目代码&#xff0c;终于有时间更新一下博客。这次的内容是关于如何在Gin框架下集成支付宝的支付沙箱环境&#xff0c;具体包括如何初始化支付…

Docker网络概述

1. Docker 网络概述 1.1 网络组件 Docker网络的核心组件包括网络驱动程序、网络、容器以及IP地址管理&#xff08;IPAM&#xff09;。这些组件共同工作&#xff0c;为容器提供网络连接和通信能力。 网络驱动程序&#xff1a;Docker支持多种网络驱动程序&#xff0c;每种驱动程…

OpenHarmony4.1蓝牙芯片如何适配?触觉智能RK3568主板SBC3568演示

当打开蓝牙后没有反应时&#xff0c;需要排查蓝牙节点是否对应、固件是否加载成功&#xff0c;本文介绍开源鸿蒙OpenHarmony4.1系统下适配蓝牙的方法&#xff0c;触觉智能SBC3568主板演示 修改对应节点 开发板蓝牙硬件连接为UART1&#xff0c;修改对应的节点&#xff0c;路径为…

QT 如何使QLabel的文字垂直显示

想要实现QLabel文字的垂直显示&#xff0c;可以通过使用“文字分割填充换行符”的方式来实现QLabel文字垂直显示的效果&#xff0c;下面是效果图&#xff1a; 具体实现代码&#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow:…

数据结构选择题及答案

一、选择题 1、下列查找方法中&#xff0c;&#xff08; &#xff09;适用于查找有序单链表。 A&#xff0e;分块查找; B&#xff0e;哈希查找; C&#xff0e;顺序查找; D&#xff0e;二分查找; 2、在有n个结点的二叉树的二叉链表表示中&#xff0c;空指针数为( )。 A&#xf…

2024上半年上午30

CPU没有减法器的说法

php实现excel表格数据快速入库

项目场景&#xff1a;大概有一百来份excel表格数据需要整理入库&#xff0c;基础字段一样&#xff0c;如果按照传统的处理方法&#xff0c;需要先整理好数据&#xff08;数据清洗、合并等&#xff09;&#xff0c;并且按照系统导入模板整理出来&#xff0c;费时费力。 需要解决…

【青牛科技】GC5931:工业风扇驱动芯片的卓越替代者

在工业领域&#xff0c;工业风扇的稳定高效运行对于维持良好的生产环境至关重要。而驱动芯片作为工业风扇控制系统的核心元件&#xff0c;其性能直接影响风扇的工作状态。芯麦 GC5931 作为一款新型驱动芯片&#xff0c;在替代 A5931/Allegro 应用于工业风扇中展现出了非凡的优势…

CST案例分析:TLM算法仿真5G毫米波手机天线和整机

5G时代&#xff0c;产品复杂&#xff0c;更新换代快&#xff0c;如何快速仿真不同的设计版本是影响研发效率的关键问题。本期我们用达索系统SIMULIA自己的手机模型来演示5G毫米波的仿真。 &#xff08;图片仅为概念演示&#xff0c;未经达索系统授权不得使用&#xff09; 完整的…

小猿口算炸鱼脚本

目录 写在前面&#xff1a; 一、关于小猿口算&#xff1a; 二、代码逻辑 1.数字识别 2.答题部分 三、代码分享&#xff1a; 补充&#xff1a;软件包下载 写在前面&#xff1a; 最近小猿口算已经被不少大学生攻占&#xff0c;小学生直呼有挂。原本是以为大学生都打着本…

【debug】QT 相关问题error汇总

总结一下碰到过的所有问题error以及解决方案 qt的UI更新之后构建后发现没有变化 取消项目中的Shadow build的勾选&#xff0c;作用是取消影子构建&#xff0c;此后构建目录与源码处于同一目录&#xff0c;每次编译更新程序使用的UI文件error: ‘class QWidget’ has no member…

滑动窗口最大值

239. 滑动窗口最大值 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 …

GEE 案例——利用哨兵-2 图像时间序列和谷歌地球引擎云计算自动绘制和监测香港海洋水质参数

目录 简介 结论 代码 结果 APP链接 引用 简介 对沿海水质的持续监测对于水资源管理和海洋生态系统的可持续性至关重要。 遥感数据&#xff08;如哨兵-2 卫星图像&#xff09;可提供用于时间序列分析的高分辨率观测数据&#xff0c;而基于云的谷歌地球引擎&#xff08;GE…

Redis4:Redis的Java客户端

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

基于Java Web的传智播客crm企业管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

【Eclipse系列】eclipse安装与常规配置(含插件)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、下载与安装 二、常规设置 1.1.设置工作空间(workspace) 1.2.设置字体和字体大小 ​编辑 1.3.设置编码 1.4.去除验证(validation) 1.5.去除单词验证(spelli…

抗辐照MCU芯片工艺解析:如何保障芯片的可靠性

行星探索、轨道飞行器任务和空间研究在内的太空项目需要创新的航天器系统技术提供通信与处理功能。随着商业航天的发展&#xff0c;对于航天电子系统需要考虑高可靠与高性能的同时&#xff0c;还需要考虑降低开发成本和缩短上市时间。 以MCU芯片AS32A401为例&#xff0c;该芯片…

qt QKeySequence详解

1、概述 QKeySequence 是 Qt 框架中的一个类&#xff0c;用于表示和处理键盘快捷键序列。它提供了一种方便的方式来解析、存储和比较键盘快捷键&#xff0c;这些快捷键通常用于触发应用程序中的特定操作或命令。QKeySequence 支持多种格式的快捷键表示&#xff0c;包括单个按键…

【RMA】基于知识注入和模糊学习的多模态歧义分析

abstract 多模态情感分析&#xff08;MSA&#xff09;利用互补的多模态特征来预测情感极性&#xff0c;主要涉及语言、视觉和音频三种模态。现有的多模态融合方法主要考虑不同模态的互补性&#xff0c;而忽略了模态之间的冲突所导致的歧义&#xff08;即文本模态预测积极情绪&…

移动取证和 Android 安全

当今的数字时代已经产生了许多技术进步&#xff0c;无论是智能手机还是虚拟现实、人工智能和物联网 (IoT) 等下一代基础技术。 智能手机已不再只是奢侈品&#xff0c;而是我们生存所必需的东西。根据各种统计数据&#xff0c;如今全球有超过 50% 的人使用手机。 由于数据存储…