【数据结构】什么是堆?

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境: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道经典面试题目带你玩转链表



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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

【01分数规划】ABC324F

[ABC324F] Beautiful Path - 洛谷 思路 首先看到这个形式很容易想到 01 分数规划&#xff0c;即去二分答案&#xff0c;然后就是转化成 是否存在一个路径使得 sigma b - mid * sigma c > 0 显然只需要改变一下边权&#xff0c;跑一遍最长路即可 #include <bits/stdc.h…

html 中vue3 的setup里调用element plus的弹窗 提示

引入Elementplus之后&#xff0c;在setup&#xff08;&#xff09;方法外面导入ElMessageBox const {ElMessageBox} ElementPlus 源码 &#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><!-- import Vue before Elemen…

运筹优化 | 模拟退火求解旅行商问题 | Python实现

"""模拟退火旅行商""" import random import numpy as np import math import time import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False location np.loadtxt(city_location.t…

python-爬取壁纸

代理池的&#xff0c;防止IP 被封 找到图片真实地址 现在看到的只是图片的预览地址 (previews) 1.检查&#xff1a; 2.鼠标变为箭头时查看网页源代码 关于怎样在源代码中找到图片的真实地址 ??? 为什么在源代码界面 ctrl f 时候搜索的是 .png ??? 首先图片地址是以 .j…

OpenStack网络详解

本文主要解释了OpenStack在安装完毕——创建网段与dhcp——创建虚拟机的过程中&#xff0c;系统中多出来的这一堆网卡到底分别连接哪两部分的网卡&#xff0c;以及哪些设备是虚拟出来的。 拓扑 红色代表ovs与网桥 蓝色代表命名空间或者虚机 绿色代表网卡 网络概况 openstack安…

【Mars3d-ModelEntity】实现gltf模型不随地图缩放而改变大小

需求场景&#xff1a; 1.实现gltf模型不随地图缩放而改变大小 相关代码&#xff1a; const graphic new mars3d.graphic.ModelEntity({ name: "警车", position: [116.346929, 30.861947, 401.34], style: { url: "//data.mars3d.cn/gltf/mars/jingche/jingc…

SpringBoot进行自然语言处理,利用Hanlp进行文本情感分析

. # &#x1f4d1;前言 本文主要是SpringBoot进行自然语言处理&#xff0c;利用Hanlp进行文本情感分析&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风…

[Unity+文心知识库]使用百度智能云搭建私有知识库,集成知识库API,打造具备知识库的AI二次元姐姐

1.简述 最近从百度智能云的官方技术支持那边了解到&#xff0c;目前百度千帆大模型平台提供有在线的知识库功能&#xff0c;能够在线上传自己的私人知识库文档&#xff0c;并且配置文心一言模型作为文本生成的引擎&#xff0c;构建自己的私有知识库。之前自己搭建知识库都是用的…

bugku--源代码

查看源代码 发显URL编码 解码 在拼接这一串 拿着去提交就行啦

【Vue】vue增加导航标签

系列文章 【C#】WebAPI&#xff0c;在Windows IIS平台部署 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126539836 【Vue】vue&#xff0c;在Windows IIS平台部署 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/13385…

docker compose部署wordpress

准备机器&#xff1a; 192.168.58.151 &#xff08;关闭防火墙和selinux&#xff09; 安装好docker服务 &#xff08;详细参照&#xff1a;http://t.csdnimg.cn/usG0s 中的国内源安装docker&#xff09; 部署wordpress: 创建目录&#xff1a; [rootdocker ~]# mkdir…

Selenium库自动化测试入门

前言 为什么要学selenium&#xff1f;&#xff1f;前面已经学了requests库我们会发现 对于绝大多数动态渲染的网页来说&#xff0c;用requests进行爬虫比较繁琐。 所以我们还是要学习一下selenium库&#xff0c;以帮助我们更高效的爬取网页。 环境&#xff1a; pychar 202…

flutter调试器查看不了副页面(非主页面/子页面)

刚接触flutter&#xff0c;写了两个页面&#xff0c;通过按钮&#xff0c;可以从主页面跳转到副页面&#xff0c;副页面我自己写的一个独立的dart文件&#xff0c;在主页面的代码中导入使用。但是当我运行代码后&#xff0c;点击跳转的时候&#xff0c;却发现查看不到对应的副页…

Linux驱动入门 —— 利用引脚号操作GPIO进行LED点灯

目录 一、字符设备驱动程序框架 编写驱动程序的步骤&#xff1a; 对于 LED 驱动&#xff0c;我们想要什么样的接口&#xff1f; LED 驱动能支持多个板子的基础&#xff1a;分层思想 二、Linux驱动如何指向一个GPIO 直接通过寄存器来操作GPIO 利用引脚号操作GPIO IMX6UL…

STM32的看门狗(WDG)

WDG&#xff08;Watchdog&#xff09;看门狗 看门狗可以监控程序的运行状态&#xff0c;当程序因为设计漏洞、硬件故障、电磁干扰等原因&#xff0c;出现卡死或跑飞现象时&#xff0c;看门狗能及时复位程序&#xff0c;避免程序陷入长时间的罢工状态&#xff0c;保证系统的可靠…

基于C/C++的rapidxml加载xml大文件 - 下部分

下载地址: RapidXml (sourceforge.net)https://rapidxml.sourceforge.net/ 将源码添加到自己的工程中 示例测试大文件耗时: 总共293w行数据&#xff0c;大概耗时不到1s。

Paper Reading: (U2PL) 基于不可靠伪标签的半监督语义分割

目录 简介目标/动机方法Pseudo-LabelingUsing Unreliable Pseudo-Labels 补充知识InfoNCE LossOHEM 实验Comparison with Existing AlternativesAblationEffectiveness of Using Unreliable Pseudo-LabelsAlternative of Contrastive Learning 总结附录U2PL 与 negative learni…

【C语言程序设计】数组程序设计

目录 前言 一、数组的定义和初始化 二、数组的基本操作 三、数组的高级应用 四、程序设计 4.1 程序设计第一题 4.2 程序设计第二题 4.3 程序设计第三题 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助…

论文阅读《DPS-Net: Deep Polarimetric Stereo Depth Estimation》

论文地址&#xff1a;https://openaccess.thecvf.com/content/ICCV2023/html/Tian_DPS-Net_Deep_Polarimetric_Stereo_Depth_Estimation_ICCV_2023_paper.html 概述 立体匹配模型难以处理无纹理场景的匹配&#xff0c;现有的方法通常假设物体表面是光滑的&#xff0c;或者光照是…