【数据结构】什么是堆?

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境:Visual Studio 2022


堆的概念及结构

堆的定义如下:

n个元素的序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为.

 \left\{\begin{matrix} k_{i}\geqslant k_{2i} \\ k_{i}\geqslant k_{2i+1} & & \end{matrix}\right.    或    \left\{\begin{matrix} k_{i}\leqslant k_{2i} \\ k_{i}\leqslant k_{2i+1} & & \end{matrix}\right.

(i= 1,2,...,\left \lfloor \frac{n}{2} \right \rfloor)

这个序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有双亲结点的值不小于(或不大于)其左,右孩子结点的值.

由此,若序列 {k1,k2,...,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最大值(或最小值).

如下面两个序列为(存储结构),则其对应的完全二叉树(逻辑结构)如下图所示:

综上,我们不难总结出堆的性质:

  • 堆中某个结点的值总是不大于或不小于其父亲结点的值.
  • 堆总是一颗完全二叉树.

堆的实现

有关堆结构的完整实现部分我放在下面这篇博客中为大家详细梳理了,并且为每个算法逻辑配备了详细明了的逻辑结构演示图和物理结构演示图,如:

堆的实现部分的具体逻辑和细节感兴趣的朋友可以点击下方链接直接跳转到相应文章:

【数据结构】C语言实现堆(附完整运行代码)icon-default.png?t=N7T8http://t.csdnimg.cn/v7qVo


建堆的时间复杂度

建堆有两种方式,一种是从堆顶开始向下建堆,另一种是从堆尾开始向上建堆.乍一听好像两种建堆方式除了向上调整和向下调整方式不同之外没什么区别,但我们仔细分析一下,其实这两种建堆方式的时间复杂度差别是很大的.

向上调整建堆

我们先一起来分析一下向上建堆的时间复杂度:

首先,按照算法算法最坏时间复杂度分析,我们假设堆是完全二叉树中的满二叉树,并且假设每个结点的移动次数都是最坏移动次数,则:

使用错位相消法,可得:

化简,可得:

使用大O阶渐近表示法,可得:

T(n) = 2^h*h = O(n*log_{2}n)

因为:

2^h=n

h=log_{2}n

(舍去低次方阶和常数阶后剩下的2^h恰好是高为h的树的结点个数n,同样的h也可化简为以2为底n的对数)


向下调整建堆

再来看看向下调整建堆:

我们继续,按照算法最坏时间复杂度分析,假设堆是完全二叉树中的满二叉树,并且假设每个结点的移动次数都是最坏移动次数,则:

使用错位相消法,可得T(n)为:

化简,可得:

使用大O阶渐近表示法,可得:

T(n) = 2^h = O(n)

(舍去低次方阶和常数阶后剩下的2^h恰好是高为h的树的结点个数n)

综上可知:

  • 向上调整的建堆方式的时间复杂度为O(n*log_{2}n)
  • 向下调整的建堆方式的时间复杂度为O(n)
  • 向下调整建堆是优于向上调整建堆的.

堆思想的应用

1.堆排序

堆排序就是利用堆(假设利用大堆)进行排序(假设为升序)的算法.

它的基本思想是:

将待排序的序列构造成一个大堆.

此时,整个序列的最大值就是堆顶的根结点.将它移走(其实就是我们前面堆实现中的出堆顶操作).

然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值(即堆顶).

如此反复执行,就可以得到一个有序的序列了.

使用堆排序的思想排序有以下几点需要注意的:

  • 排升序建大堆
  • 排降序建小堆
  • 建好堆后利用堆删除的思想进行排序

 如下是一个顺序待排数组:

为了直观的利用堆排序的思想,我们在逻辑上将其还原为一颗完全二叉树:

我们先将数组视为一个空堆,开始时堆中没有元素.

我们先模拟一下向上建堆的过程:

即数组逐渐向后遍历,模拟向堆中插入元素:

(ps:此处建堆也可以使用向下建堆的思路,时间复杂度会更小,但要注意的是,向下建堆时,我们对数组的遍历是从最后一个叶子结点的父节点开始向前遍历并向下调整的.假设数组有n个元素,即是从下标为[(n-2)/2]的结点开始向前遍历并向下调整.)

插入'75':

插入'80':

向上调整:

插入'60':

我们先按照入堆的逻辑,将数组建成一个大堆:

然后再按照堆删除的思想,将堆顶元素移动至堆尾"删除":

再将换到堆顶的元素向下调整:

调整好后再删除"新的堆顶元素":

如此循环"删除堆顶":

最终就会得到一个升序的序列:


2.Top-k问题

Top-k问题:

求数据集合中前k个最大/最小的元素,一般情况下数据量都比较大.

对于Top-k问题,最容易想到的方法是先整体排序,再取前k个,但当数据量非常大时(可能都无法加载到内存上),排序就不是一个很好的解决方法了.

这时的最佳的方案就是用堆来解决,思路如下:

1.先用数据元素中前K个元素来建堆

  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆

2.遍历剩余的N-K个元素来比较,遇到符合条件的(如求前k个最大的元素,新元素比堆顶要大)则用其替换堆顶,然后再向下调整,构建为新的大堆/小堆.

3.当遍历完剩下N-K个元素时,堆中剩余的k个元素就是所求的前Top-k个元素.

这个思路有点类似于让一个堆里最"弱"的元素去守"门",如果新来的元素比最弱的,则让它替换最弱的进堆,再在堆中选出新的最弱的去"守门".如果新来的元素比最弱的还弱,那它就完全不是我们要找的元素,可以直接把它pass掉.

利用这种方式选出top-k,当数据量大到可以忽略建堆以及后续调整堆部分的操作带来的时间复杂度时,我们可以近似的认为这个算法的时间复杂度为O(n).


结语

希望这篇有关数据结构"堆"的文章能对您有所帮助,欢迎大佬们留言或私信与我交流.学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【数据结构】C语言实现堆(附完整运行代码)

【数据结构】什么是线性表?

【数据结构】线性表的链式存储结构

【数据结构】什么是栈?

【数据结构】用C语言实现顺序栈(附完整运行代码)

【数据结构】深入浅出理解链表中二级指针的应用

【数据结构】10道经典面试题目带你玩转链表



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

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

相关文章

基于springBoot + Vue电影售票系统分前后台【完整源码+数据库】

一、项目简介 本项目是一套基于springBoot Vue的电影售票系统,主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目可以直接作为bishe使用。 项目都经过严格调试,确…

示例讲述类、接口继承,类、抽象类实现接口相关内容

定义A接口&#xff1a; public interface IService<T> {default boolean save(T entity) {return SqlHelper.retBool(this.getBaseMapper().insert(entity));} }定义B接口继承A接口&#xff1a; public interface IBaseService<T> extends IService<T> {Re…

<蓝桥杯软件赛>零基础备赛20周--第10周--二分

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

门窗企业网站建设作用是什么

门窗作为市场重要的组合部分&#xff0c;其应用广泛使得众多商家入局经营&#xff0c;无论大型建筑还是家庭应用&#xff0c;都有较高需求度&#xff0c;尤其对品牌商来说&#xff0c;无论直售还是加盟都可以获得不菲效益。 但对门窗企业来说&#xff0c;也需要解决几个痛点&a…

读写分离如何在业务中落地?

本文我们来探讨读写分离如何在业务中落地。 读写分离是业务开发中常用的技术手段&#xff0c;在面试中也是热点问题&#xff0c;今天我们要讲的是在什么业务场景下需要读写分离&#xff0c;读写分离实现的机制&#xff0c;以及实际生产中应用读写分离要注意的问题。 什么时候…

深入解析Spring Boot集成MyBatis的多种方式

文章目录 1. 引言2. 传统的XML配置方式2.1 引入依赖2.2 配置数据源和MyBatis2.3 编写Mapper接口和XML映射文件2.4 使用Mapper 3. 注解配置方式3.1 引入依赖3.2 配置数据源和MyBatis3.3 编写Mapper接口3.4 使用Mapper 4. MyBatis动态SQL4.1 使用XML配置方式4.2 使用注解配置方式…

C++容器系列之list详解与应用

C容器系列之list详解与应用 引言list的元素排列特性优缺点与其他容器的区别应用场景常见函数代码示例 引言 C标准模板库&#xff08;STL&#xff09;提供了丰富的容器类&#xff0c;其中之一就是list。list是一个双向链表实现的容器&#xff0c;与数组和向量等容器有很大的区别…

RT-DETR核心结构改进:即插即用 | 集成YOLO-MS论文SOTA核心结构,原汁原味RT-DETR改进升级版,打破性能瓶颈

💡本篇内容:RT-DETR核心结构改进:即插即用 | 集成YOLO-MS论文SOTA核心结构,原汁原味RT-DETR改进升级版,打破性能瓶颈 💡🚀🚀🚀本博客 改进源代码改进 适用于 RT-DETR 按步骤操作运行改进后的代码即可 💡本文提出改进 原创 方式:二次创新, 该专栏专注于RT-DE…

一文了解 Go 接口

如果本文对你有帮助&#xff0c;不妨点个赞&#xff0c;如果你是 Go 语言初学者&#xff0c;不妨点个关注&#xff0c;一起成长一起进步&#xff0c;如果本文有错误的地方&#xff0c;欢迎指出 接口 在 Go 语言中&#xff0c;接口是一种抽象的类型&#xff0c;是一组方法的集合…

react中使用ref属性获取元素,并判断该元素内是否含有子元素

在react中&#xff0c;可以使用ref属性来获取到一个元素的引用&#xff0c;然后再使用ref.current来访问该元素的DOM节点&#xff0c;使用DOM API来判断这个元素是否含有子元素&#xff0c;要判断一个元素是否含有子元素&#xff0c;可以使用hasChildNodes()&#xff0c;其返回…

Salesforce×阿里云,影响几何?

实际上&#xff0c;从这个视角来看&#xff0c;Salesforce和阿里云的合作也恰在成为着这个市场的一个新催化剂。“期待Salesforce能给中国市场带来一些新的增量&#xff0c;包括对合作伙伴的态度&#xff0c;对产品的态度等等。”一位CRM相关人士告诉我们。 那么&#xff0c;阿…

slurm 23.11.0集群 debian 11.5 安装

slurm 23.11.0集群 debian 11.5 安装 用途 Slurm(Simple Linux Utility for Resource Management&#xff0c; http://slurm.schedmd.com/ )是开源的、具有容错性和高度可扩展的Linux集群超级计算系统资源管理和作业调度系统。超级计算系统可利用Slurm对资源和作业进行管理&a…

【Jmeter】Jmeter基础4-Jmeter元件介绍之监听器

2.4、监听器 监听器主要用于收集、统计、查看和分析结果。 2.4.1、察看结果树 作用&#xff1a;查看取样器请求和响应结果&#xff0c;包括消息头&#xff0c;请求的数据&#xff0c;响应的数据等。一般在调试时才用&#xff0c;在实际运行压测时建议禁用&#xff0c;因为大量…

【NSX-T】6. 搭建NSX-T环境 —— 配置 Segment 网段

目录 6. 配置 SegmentLab 说明6.1 创建 Segment&#xff08;1&#xff09;创建 Web-Segment&#xff08;2&#xff09;创建 App-Segment 和 DB-SegmentApp-SegmentDB-Segment 6.2 验证 Segment&#xff08;1&#xff09;在 NSX Manager中查看&#xff08;2&#xff09;在vSpher…

前端走向未来:真相还是焦虑的贩卖?

目录 一、为什么会出现“前端已死”的言论 二、你如何看待“前端已死” 三、前端技术的未来发展趋势 四、前端人&#xff0c;该如何打好这场职位突围战&#xff1f; 我的其他博客 一、为什么会出现“前端已死”的言论 近来&#xff0c;IT圈内流传着“Java 已死、前端已凉”…

阿里云服务器环境配置,ssh免密登录和配置docker

此文章适合ubuntu20.04 64位和ubuntu22.04 64位版本 一.登陆服务器 租完服务器后&#xff0c;首选需要使用本地gitbash或者cmd进入服务器&#xff0c; 命令&#xff1a; ssh rootxxx xxx为服务器公网ip&#xff0c;然后yes&#xff0c;然后输入密码就会进入自己的服务器&am…

医院污水处理设备远程监控超标报警解决方案

行业背景 近年来&#xff0c;我国医疗机构建设得到了巨大的发展。根据《2022年我国卫生健康事业发展统计公报》&#xff0c;2022年末&#xff0c;全国医疗卫生机构总数达1032918个。截至2022年10月&#xff0c;根据全国排污许可证管理信息平台&#xff0c;共有 13316家医院核发…

修改Docker0和容器的地址

修改Docker0和容器的地址 1. 需求 默认服务器安装完Docker-ce后会给docker0分配172.17.0.1/16地址. 公司新接入一个网段正好与172.17.0.1/16冲突,此时访问这台服务器的容器时就会发生网络不可达. 2. 解决方法 修改/etc/docker/daemon.json 加入一个自定义网段 vim /etc/d…

想要在电脑桌面上使用手机便签怎么操作?

作为一名上班族&#xff0c;我们时常需要在电脑和手机之间同步使用便签&#xff0c;以记录工作、生活中的重要事项。然而&#xff0c;有些时候我们可能更习惯在手机上使用便签&#xff0c;但又希望在电脑桌面上也能够方便地查看和编辑这些便签。那么&#xff0c;如何在电脑桌面…

python 内置数据结构

python内置的数据结构有&#xff1a; 列表(list) 元组(tuple) 字典(dict) 集合(set) 在python语言中&#xff0c;以上4种数据结构和基础数据类型&#xff08;整数、浮点数等&#xff09;统称为“内置类型”&#xff08;Built-in Types&#xff09;。 1. 列表(list) 参考&…