【第十五课】数据结构:堆 (“堆”的介绍+主要操作 / acwing-838堆排序 / c++代码 )

目录

关于堆的一些知识的回顾 

数据结构:堆的特点

"down" 和 "up":维护堆的性质

down

up

数据结构:堆的主要操作

acwing-838堆排序

代码如下

时间复杂度分析


确实是在写的过程中频繁回顾了很多关于树的知识,有关的文章都在专栏里,需要的可以去回顾一下~

http://t.csdnimg.cn/0d6Iqicon-default.png?t=N7T8http://t.csdnimg.cn/0d6Iq

关于堆的一些知识的回顾 

关于堆,我的印象中是内存机制里的堆。之前写过的,在回顾一下吧~

然而我们这里说的堆,其实是一种数据结构中的完全二叉树实现的堆

(我们这里图片上写的坐标索引方式是根节点从0开始索引,我们下面会采用下标从1开始索引,那样的话,左儿子就应该是2x 右儿子是2x+1 可以理解哈)

其实这里还要回顾一下树的广度优先遍历,即一层一层,从左到右的遍历方式,对于完全二叉树来说,其广度优先遍历就是创建一个数组,按照特定的存储方式进行存储,最终直接输出数组元素。对于其他的树,采取队列的存储方式。下面这篇文章详细介绍了树的遍历,也对数组存储有更深的解释,感兴趣可以看一下

http://t.csdnimg.cn/NngZ6


数据结构:堆的特点

1.完全二叉树的结构 

堆是一个完全二叉树,这意味着除了最底层,其他层都是满的,而最底层的节点都集中在左侧。

到这里就要疑惑为什么堆是完全二叉树这种结构了 

http://www.zhihu.com/question/36134980/answer/87490177

这篇文章作者详细解释了关于"堆"这种数据结构好处包括用途,我感觉写的非常不错,可以看一下加深理解。

其中主要提到:1.完全二叉树这种结构可以使用数组实现存储,并且便于索引

2.它的出现是为了解决----对一个动态的序列进行排序,并且随时想知道这个序列的最小值或最大值

2.最小堆和最大堆

堆可以分为最小堆和最大堆两种类型。在最小堆中,每个节点的值都小于或等于其子节点的值。而在最大堆中,每个节点的值都大于或等于其子节点的值。(也叫小根堆和大根堆)

"down" 和 "up":维护堆的性质

"down" 操作通常涉及到将元素向下移动,适用于删除操作和堆化过程中。

通过 down(k) 进行下沉操作是为了调整以 k 为根的子树,确保其满足最小堆的性质。这主要关注了 k 节点向下的关系

"up" 操作涉及到将元素向上移动,适用于插入操作和堆化过程中。 

通过 up(k) 进行上浮操作是为了确保从删除元素的位置 k 开始,向上到根节点的路径上的每个父节点都满足最小堆的性质。这主要关注了 k 节点向上的关系

而我们所说的 "down" 和 "up" 是通常用于--维护堆的性质。以确保堆的性质不被破坏。

下面以小根堆为例 

down

根据这个思路我们写出代码

//调整以x为根的子树,以满足小根堆的性质(x是经过某种操作得到的值,在操作之前整棵树是满足堆的性质的)
void down(int x)
{int t=x;//t表示三个数中的最小值
//比较的前提都是孩子存在if(x*2<=size && he[x*2]<he[t])t=x*2;if(x*2+1<=size && he[x*2+1]<he[t])t=x*2+1;if(x!=t)//所以这里如果不需要交换位置,那说明更改的这个值并没有破坏原有的性质{swap(he[x],he[t]);down(t);//需要交换 说明我们又更改了一个位置的值,所以要继续判断这次更改的是否符合性质}
}

down操作的前提就是 本身这个树的每个节点都是符合性质的,只是某一个值发生了改变

我们针对这个发生改变的值,不管它是插入还是修改还是更改而导致的值的变化,我们最主要的就是关注改值之后,以其为根节点的子树。

将该值与它的原本的左右两个孩子的值的比较,如果不需要交换位置,说明这次的更改的值并没有引起堆的性质的变化

up

如上图这种完全二叉树,按照数组存储方式,观察其下标表示,我们发现孩子节点是其父节点下标的二倍

由于小根堆的性质,根节点小于左右孩子,所以我们检查的时候只看该节点与根节点的大小关系就好了,因为另一个孩子一定是大于根节点且符合性质的

void up(int x)
{while(x/2 && he[x/2]>he[x])//当该元素存在父节点且满足大小关系{swap(he[x/2],he[x]);x /= 2;//更新父节点}
}

有了上面down的详细解释这个应该很容易理解了。 

数据结构:堆的主要操作

1.插入一个元素,并仍保持堆的性质

2.删除最小/大值。

3.堆化:将一个无序数组转换为堆,或者修复一个破坏了堆性质的堆。

这里先详细说一下堆化

for(int i=n/2;i;i--)down(i);

我们通常从倒数第二层(n/2是最后一个元素的父节点)开始进行逐个元素下沉,最终达到将数组堆化的结果。 这是因为底层节点是叶子节点,它们自身已经满足堆的性质,不需要进行下沉操作。


关于手写堆的一些主要操作就是上面这些。

下面我逐个来解释。

1.插入一个数。由于我们堆结构是用数组实现存储的完全二叉树,因此对于数组来说,在末尾添加一个元素是很容易的,所以我们先把这个要插入的元素放到堆的末尾,在进行up操作,使其符合堆的性质。

2.求最小值,我们小根堆的根节点就是其最小值。

3.删除最小值。由于我们总是要删除一个元素的,在数组存储结构中,删除最后一个元素是很简单的,直接使我们使用到的下标--就行,但是我们要删的是第一个元素呀,怎么办呢?我们把最后一个元素的值标记覆盖到第一个元素的位置,再删除掉最后一个元素,再把刚刚放到第一位的元素进行down操作,使其符合堆的性质。

4.删除任意一个元素。在3思路的基础上,由于我们不清楚最后一个元素相较于原来这个位置上删除掉的元素是大还是小,如果是大于原来的元素,那就会执行down,如果小于,就会向上执行up,因此,这两个只会执行其中一个,为了简化代码,我们直接不判断,把两个都放上去

5.修改任意一个元素,解释同4

acwing-838堆排序

经过上面的介绍其实这道题的核心都已经解了,直接看代码把。

代码如下

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n,m;
int he[N],size;//调整以 x 为根的子树,以满足小根堆的性质
void down(int x)
{int t=x;//t表示三个数中的最小值if(x*2<=size && he[x*2]<he[t])t=x*2;if(x*2+1<=size && he[x*2+1]<he[t])t=x*2+1;if(x!=t){swap(he[x],he[t]);down(t);}
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&he[i]);}size=n;//size标记数组最后一个元素for(int i=n/2;i;i--)down(i);//将数组堆化while(m--)//每次输出一个最小值{printf("%d ",he[1]);he[1]=he[size];//删除最小值size--;down(1);}return 0;
}

时间复杂度分析

在这段代码中:

输入数据的for循环O(n) 

建堆的for循环,先看down函数,down是逐层比较,其时间复杂度取决于树的高度,所以最坏情况下就是该二叉树为满二叉树时的树高,即log(n)。那么真整个建堆过程时间复杂度应为O(n*log(n)) 

--关于这里的时间复杂度其实还有一种思考方式,等之后回来补写一下。

输出最小值的while循环,也是取决于down函数执行次数,即O(m*log(n)) 


哎,就差一个模拟堆(烦躁),是有点强迫症在的😢明天在写啦。。

有问题欢迎指出!一起加油!!

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

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

相关文章

使用ElEment组件实现vue表单校验空值

1.绑定表单组件数组rules 2.在data域中设定组件rules 3.设定调用方法函数 提交校验 取消&#xff1a; 测试页面 提交空值 失去焦点 取消重置 提交后重置

Studio One 6 mac 6.5.2 激活版 数字音乐编曲创作

PreSonus Studio One是PreSonus出品的一款功能强大的音乐创作软件。主要为用户提供音乐创作、录音、编辑、制作等功能。它可以让你创造音乐&#xff0c;无限的轨道&#xff0c;无限的MIDI和乐器轨道&#xff0c;虚拟乐器和效果通道&#xff0c;这些都是强大和完美的。 软件下载…

【Maven】-- 打包添加时间戳的两种方法

一、需求 在执行 mvn clean package -Dmaven.test.skiptrue 后&#xff0c;生成的 jar 包带有自定义系统时间。 二、实现 方法一&#xff1a;使用自带属性&#xff08;不推荐&#xff09; 使用系统时间戳&#xff0c;但有一个问题&#xff0c;就是默认使用 UTC0 的时区。举例…

单片机11-13

目录 蜂鸣器 蜂鸣器播放按键提示音 蜂鸣器播放音乐 AT24C02&#xff08;IIC&#xff09;总线 AT24C02数据存储 AT24C02秒表&#xff08;定时器扫描按键&#xff09; DS18B20温度传感器&#xff08;单总线&#xff09; 温度显示 温度报警器 蜂鸣器 蜂鸣器播放按键提示音…

一款相对比较强大的国产ARM单片机HC32F4A0

已经用了3年的HC32F4A0&#xff0c;已经对它比较熟悉了&#xff0c;与STM32相比它的外设使用这些的确是挺大大&#xff0c;不像GD32一类的单片机很多都能兼容STM32。用久了之后就更喜欢用HC32F4A0&#xff0c;功能强大&#xff0c;外设使用灵活&#xff0c;用点向FPGA靠拢的感觉…

AI+量化03_股票数据获取

文章目录 思维导图问答之纯小白 vs GPT4 目标: 掌握量化金融知识、使用Python进行量化开发 背景&#xff1a;纯小白 参考资料&#xff1a;https://github.com/datawhalechina/whale-quant 本章是学习了股票数据的获取&#xff1a; 理论层面&#xff1a;包括股票数据的分类和常…

【AIGC】CLIP

CLIP的基本原理 对比学习&#xff1a; Clip使用对比学习来训练模型。对比学习的目标是通过将正样本&#xff08;相似的图像和文本对&#xff09;与负样本&#xff08;不相似的图像和文本对&#xff09;进行比较&#xff0c;从而使模型学会区分不同样本之间的差异。这有助于模型…

自然语言处理--基于HMM+维特比算法的词性标注

自然语言处理作业2--基于HMM维特比算法的词性标注 一、理论描述 词性标注是一种自然语言处理技术&#xff0c;用于识别文本中每个词的词性&#xff0c;例如名词、动词、形容词等&#xff1b; 词性标注也被称为语法标注或词类消疑&#xff0c;是语料库语言学中将语料库内单词…

【其他-闲谈】关于博客排行榜

今天在学习内核驱动&#xff0c;有个常量不知道什么意思&#xff0c;然后在一篇博客上找到了答案——GFP_KERNEL的作用 偶然注意到作者排行50&#xff0c;然后往下看了看&#xff0c;想知道为什么他排行这么靠前&#xff0c;看这文章数量&#xff0c;估摸着一天一篇&#xff0c…

浪花 - 查询队伍列表

一、接口设计 1. 请求参数&#xff1a;封装 TeamQuery package com.example.usercenter.model.dto;import com.example.usercenter.common.PageRequest; import lombok.Data;/*** author 乐小鑫* version 1.0* Date 2024-01-22-20:14*/ Data public class TeamQuery extends …

Stable Diffusion学习

参考 Stable Diffusion原理详解_stable diffusion csdn-CSDN博客 Stable Diffusion是stability.ai开源的图像生成模型&#xff0c;可以说Stable Diffusion的发布将AI图像生成提高到了全新高度&#xff0c;其效果和影响不亚于Open AI发布ChatGPT。 图像生成的发展 在Stable D…

【RT-DETR有效改进】轻量化ConvNeXtV2全卷积掩码自编码器网络

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

解决docker desktop 登录不上账号的问题

一、背景 点击“Sign in”&#xff0c;一直卡在Verifying credentials...&#xff0c;重试也没用。 二、解决办法 1、macOS下载并安装Proxifier 2、配置Proxifier 配置Proxies 配置rule 其中的Applications填&#xff1a;"Docker.app"; "Docker"; com.…

复合机器人颠覆传统上下料,实现高效精准生产

在追求高效、精准生产的现代制造业中&#xff0c;传统的上下料方式已经无法满足企业的需求。复合机器人的出现&#xff0c;为制造业带来了革命性的变革。它不仅提高了生产效率&#xff0c;降低了生产成本&#xff0c;还为企业创造了更大的竞争优势。复合机器人的广泛应用&#…

【复现】万户ezoffice协同管理平台 SQL注入漏洞_26

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 万户ezOFFICE协同管理平台分为企业版和政务版。 解决方案由五大应用、两个支撑平台组成&#xff0c;分别为知识管理、工作流程、沟…

小新22-IAP,24-IAP,27-IAP(F0GG,F0GH,F0GJ)原厂Win11.22H2系统

lenovo联想小新22寸,24寸,27寸IAP原装出厂Windows11系统镜像还原包&#xff0c;恢复出厂开箱状态 适用型号&#xff1a; 联想小新27-IAP(F0GJ),小新24-IAP(F0GH),小新22-IAP(F0GG) IdeaCentre AIO 3 22IAP7,IdeaCentre AIO 3 24IAP7,IdeaCentre AIO 3 27IAP7 链接&#xff1…

网络协议与攻击模拟_06攻击模拟SYN Flood

一、SYN Flood原理 在TCP三次握手过程中&#xff0c; 客户端发送一个SYN包给服务器服务端接收到SYN包后&#xff0c;会回复SYNACK包给客户端&#xff0c;然后等待客户端回复ACK包。但此时客户端并不会回复ACK包&#xff0c;所以服务端就只能一直等待直到超时。服务端超时后会…

算法通关村番外篇-面试150题二

​ 大家好我是苏麟 , 今天开始LeetCode面试经典150题 . ​ 大纲 1. 两数之和167. 两数之和 II - 输入有序数组15. 三数之和 1. 两数之和 描述 : 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0…

【GitHub项目推荐--开源2D 游戏引擎】【转载】

microStudio 是一个可在浏览器中运行的游戏引擎&#xff0c;它拥有一套精美、设计精良、全面的工具&#xff0c;可以非常轻松地帮助你创建 2D 游戏。 你可以在浏览器中访问 microStudio.dev 开始搭建你的游戏&#xff0c;当然你可以克隆现有项目或创建新游戏并开始编码&#x…

Flink多流转换(1)—— 分流合流

目录 分流 代码示例 使用侧输出流 合流 联合&#xff08;Union&#xff09; 连接&#xff08;Connect&#xff09; 简单划分的话&#xff0c;多流转换可以分为“分流”和“合流”两大类 目前分流的操作一般是通过侧输出流&#xff08;side output&#xff09;来实现&…