当前位置: 首页 > news >正文

数据结构——堆

数据结构——堆

    • 堆简介
    • 堆的分类
  • 二叉堆
    • 过程
      • 插入操作
    • 删除操作
      • 向下调整:
    • 增加某个点的权值
    • 实现
    • 参考代码:
    • 建堆
      • 方法一:使用 decreasekey(即,向上调整)
      • 方法二:使用向下调整
  • 应用
    • 对顶堆
  • 其他:
    • 配对堆:
    • 左偏树:

堆简介

堆是一棵树,其每个节点都有一个键值,且每个节点的键值都大于等于/小于等于其父亲的键值。

每个节点的键值都大于等于其父亲键值的堆叫做小根堆,否则叫做大根堆。STL 中的 priority_queue 其实就是一个大根堆。

(小根)堆主要支持的操作有:插入一个数、查询最小值、删除最小值、合并两个堆、减小一个元素的值。

一些功能强大的堆(可并堆)还能(高效地)支持 merge 等操作。

一些功能更强大的堆还支持可持久化,也就是对任意历史版本进行查询或者操作,产生新的版本。

堆的分类

在这里插入图片描述
习惯上,不加限定提到「堆」时往往都指二叉堆。

二叉堆

结构
从二叉堆的结构说起,它是一棵二叉树,并且是完全二叉树,每个结点中存有一个元素(或者说,有个权值)。

堆性质:父亲的权值不小于儿子的权值(大根堆)。同样的,我们可以定义小根堆。本文以大根堆为例。

由堆性质,树根存的是最大值(getmax 操作就解决了)。

过程

插入操作

插入操作是指向二叉堆中插入一个元素,要保证插入后也是一棵完全二叉树。

最简单的方法就是,最下一层最右边的叶子之后插入。

如果最下一层已满,就新增一层。

插入之后可能会不满足堆性质?

向上调整:如果这个结点的权值大于它父亲的权值,就交换,重复此过程直到不满足或者到根。

可以证明,插入之后向上调整后,没有其他结点会不满足堆性质。

向上调整的时间复杂度是 O ( l o g n ) O(log n) O(logn)的。

删除操作

删除操作指删除堆中最大的元素,即删除根结点。

但是如果直接删除,则变成了两个堆,难以处理。

所以不妨考虑插入操作的逆过程,设法将根结点移到最后一个结点,然后直接删掉。

然而实际上不好做,我们通常采用的方法是,把根结点和最后一个结点直接交换。

于是直接删掉(在最后一个结点处的)根结点,但是新的根结点可能不满足堆性质……

向下调整:

在该结点的儿子中,找一个最大的,与该结点交换,重复此过程直到底层。

可以证明,删除并向下调整后,没有其他结点不满足堆性质。

时间复杂度 O ( l o g n ) O(log n) O(logn)

增加某个点的权值

很显然,直接修改后,向上调整一次即可,时间复杂度为 O ( l o g n ) O(log n) O(logn)

实现

我们发现,上面介绍的几种操作主要依赖于两个核心:向上调整和向下调整。

考虑使用一个序列 h h h 来表示堆。 h i h_i hi 的两个儿子分别是 h 2 h_2 h2 i _i i h 2 h_2 h2 i _i i + _+ + 1 _1 1 1 1 1 是根结点:

在这里插入图片描述

参考代码:

void up(int x) {while (x > 1 && h[x] > h[x / 2]) {swap(h[x], h[x / 2]);x /= 2;}
}void down(int x) {while (x * 2 <= n) {t = x * 2;if (t + 1 <= n && h[t + 1] > h[t]) t++;if (h[t] <= h[x]) break;std::swap(h[x], h[t]);x = t;}
}

建堆

考虑这么一个问题,从一个空的堆开始,插入 n 个元素,不在乎顺序。

直接一个一个插入需要 O ( n l o g n ) O(n log n) O(nlogn) 的时间,有没有更好的方法?

方法一:使用 decreasekey(即,向上调整)

从根开始,按 BFS 序进行。

void build_heap_1() {for (i = 1; i <= n; i++) up(i);
}

为啥这么做:对于第 k 层的结点,向上调整的复杂度为 O ( k ) O(k) O(k) 而不是 O ( l o g n ) O(log n) O(logn)

总复杂度: l o g 1 log 1 log1 + l o g 2 log 2 log2 + … + l o g n log n logn = O ( n l o g n ) O(n log n) O(nlogn)

(在「基于比较的排序」中证明过)

方法二:使用向下调整

这时换一种思路,从叶子开始,逐个向下调整

void build_heap_2() {for (i = n; i >= 1; i--) down(i);
}

换一种理解方法,每次「合并」两个已经调整好的堆,这说明了正确性。

注意到向下调整的复杂度,为 O ( l o g n − k ) O(log n - k) O(lognk),另外注意到叶节点无需调整,因此可从序列约 n/2 的位置开始调整,可减少部分常数但不影响复杂度。

之所以能 O ( n ) O(n) O(n) 建堆,是因为堆性质很弱,二叉堆并不是唯一的。
要是像排序那样的强条件就难说了。

应用

对顶堆

这个问题可以被进一步抽象成:动态维护一个序列上第 k k k 大的数, k k k 值可能会发生变化。

对于此类问题,我们可以使用对顶堆这一技巧予以解决(可以避免写权值线段树或 B S T BST BST带来的繁琐)。

对顶堆由一个大根堆与一个小根堆组成,小根堆维护大值即前 k k k 大的值(包含第 k k k 个),大根堆维护小值即比第 k k k 大数小的其他数。

这两个堆构成的数据结构支持以下操作:

1.维护:当小根堆的大小小于 k k k 时,不断将大根堆堆顶元素取出并插入小根堆,直到小根堆的大小等于 k k k;当小根堆的大小大于 k k k 时,不断将小根堆堆顶元素取出并插入大根堆,直到小根堆的大小等于 k k k

2.插入元素:若插入的元素大于等于小根堆堆顶元素,则将其插入小根堆,否则将其插入大根堆,然后维护对顶堆;

3.查询第 k 大元素:小根堆堆顶元素即为所求;

4.删除第 k 大元素:删除小根堆堆顶元素,然后维护对顶堆;

显然,查询第 k k k 大元素的时间复杂度是 O ( 1 ) O(1) O(1) 的。由于插入、删除或调整 k k k 值后,小根堆的大小与期望的 k k k 值最多相差 1 1 1,故每次维护最多只需对大根堆与小根堆中的元素进行一次调整,因此,这些操作的时间复杂度都是 O ( l o g n ) O(log n) O(logn) 的。

其他:

配对堆:

详见:链接: 数据结构——配对堆

左偏树:

详见后文。

相关文章:

数据结构——堆

数据结构——堆 堆堆简介堆的分类 二叉堆过程插入操作 删除操作向下调整&#xff1a; 增加某个点的权值实现参考代码&#xff1a;建堆方法一&#xff1a;使用 decreasekey&#xff08;即&#xff0c;向上调整&#xff09;方法二&#xff1a;使用向下调整 应用对顶堆 其他&#…...

重复学习1:NLP

目录 1. 自然语言处理与知识图谱1.1 RNN 循环神经网络初探 2. 吴恩达深度学习 1. 自然语言处理与知识图谱 1.1 RNN 循环神经网络初探 1.1.2 回顾数据维度与神经网络(1) 2. 吴恩达深度学习 P151 1.1 为什么选择序列模型&#xff08;1,2&#xff09; P152 1.2 数学符号(1,)...

做海外游戏推广有哪些条件?

做海外游戏推广需要充分准备和一系列条件的支持。以下是一些关键条件&#xff1a; 市场调研和策略制定&#xff1a;了解目标市场的文化、玩家偏好、竞争格局等是必要的。根据调研结果制定适合的推广策略。 本地化&#xff1a;将游戏内容、界面、语言、货币等进行本地化&#…...

JavaFx基础学习【五】:FXML布局文件使用

目录 前言 一、介绍 二、简单体验 三、FXML标签元素 四、fx属性介绍 五、重写initialize&#xff08;名字需要保持一致&#xff09;方法 六、Scene Builder快速布局 前言 如果你还没有看过前面的文章&#xff0c;可以通过以下链接快速前往学习&#xff1a; JavaFx基础学…...

通过Python爬虫提升网站搜索排名

目录 怎么使用Python爬虫提升排名 1. 抓取竞争对手数据&#xff1a; 2. 关键词研究&#xff1a; 3. 网页内容优化&#xff1a; 4. 内部链接建设&#xff1a; 5. 外部链接建设&#xff1a; 6. 监测和调整&#xff1a; 需要注意哪些方面 1. 合法性和道德性&#xff1a; …...

【博客698】为什么当linux作为router使用时,安装docker后流量转发失败

为什么当linux作为router使用时&#xff0c;安装docker后流量转发失败 场景 当一台linux机器作为其它服务器的router&#xff0c;负责转发流量的时候&#xff0c;让你在linux上安装docker之后&#xff0c;就会出现流量都被drop掉了 原因 没装docker之前&#xff1a; [root~]…...

el-dialog嵌套,修改内层el-dialog样式(自定义样式)

el-dialog嵌套使用时,内层的el-dialog要添加append-to-body属性 给内层的el-dialog添加custom-class属性,添加自定义类名 <el-dialog:visible.sync"dialogVisible"append-to-bodycustom-class"tree-cesium-container"><span>这是一段信息<…...

B树和B+树区别

B树和B树的区别 B树 B树被称为平衡树&#xff0c;在B树中&#xff0c;一个节点可以有两个以上的子节点。B树的高度为log M N。在B树中&#xff0c;数据按照特定的顺序排序&#xff0c;最小值在左侧&#xff0c;最大值在右侧。 B树是一种平衡的多分树&#xff0c;通常我们说m阶…...

intelJ IDEA\PHPStorm \WebStorm\PyCharm 通过ssh连接远程Mysql\Postgresql等数据库

最容易出错的地方是在general面板下的host&#xff0c;不应该填真实的host地址&#xff0c;而应该填localhost或者127.0.0.1 具体操作步骤见下图...

vfuhyuuy

Sublime Text is an awesome text editor. If you’ve never heard of it, you shouldcheck it out right now. I’ve made this tutorial because there’s no installer for the Linux versions of Sublime Text. While that’s not a real problem, I feel there is a clean…...

CSS自学框架之表单

首先我们看一下表单样式&#xff0c;下面共有5张截图 一、CSS代码 /*表单*/fieldset{border: none;margin-bottom: 2em;}fieldset > *{ margin-bottom: 1em }fieldset:last-child{ margin-bottom: 0 }fieldset legend{ margin: 0 0 1em }/* legend标签是CSS中用于定义…...

使用Spring Boot和Redis实现用户IP接口限流的详细指南

系列文章目录 文章目录 系列文章目录前言一、准备工作二、编写限流过滤器三、配置Redis四、测试接口限流总结 前言 在高并发场景下&#xff0c;为了保护系统免受恶意请求的影响&#xff0c;接口限流是一项重要的安全措施。本文将介绍如何使用Spring Boot和Redis来实现用户IP的…...

前端性能优化——包体积压缩插件,打包速度提升插件,提升浏览器响应的速率模式

前端代码优化 –其他的优化可以具体在网上搜索 压缩项目打包后的体积大小、提升打包速度&#xff0c;是前端性能优化中非常重要的环节&#xff0c;结合工作中的实践总结&#xff0c;梳理出一些 常规且有效 的性能优化建议 ue 项目可以通过添加–report命令&#xff1a; "…...

配置vscode

配置vscode 设置相关 网址&#xff1a;https://code.visualstudio.com/ 搜索不要用百度用这个&#xff1a;cn.bing.com 1.安装中文包 Chinese (Simplified) (简体中文) 2.安装 open in browser 3.安装主题 Atom One Dark Theme 4. 安装图标样式 VSCode Great Icons 5.安装 L…...

【Spring】深入理解 Spring 事务及其传播机制

文章目录 一、Spring 事务是什么二、Spring 中事务的实现方法2.1 Spring 编程式事务&#xff08;手动&#xff09;2.1.1 编程式事务的使用演示2.1.2 编程式事务存在的问题 2.2 Spring 声明式事务&#xff08;自动&#xff09;2.2.1 Transactional 作用范围2.2.2 Transactional …...

eclipse常用设置

1、调整编辑页面字体大小 窗口 (Window)- 首选项&#xff08;Preferences&#xff09;- 常规&#xff08;General&#xff09;- 外观 (Appearence)- 颜色与字体 (Colors And Fonts)&#xff0c;在右边的对话框里选择 Java - Java Editor Text Font&#xff0c;点击出现的修改&…...

ajax解析

Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于在不重新加载整个页面的情况下与服务器交换数据的技术。它通过异步的方式发送请求和接收响应&#xff0c;能够实现在后台与服务器进行数据交互&#xff0c;然后更新页面的部分内容&#xff0c;从而提升用…...

CSS3:图片边框

简介 图片也可以作为边框&#xff0c;以下是实例演示 注意 实现该效果必须添加border样式&#xff0c;且必须位于border-image-socure之前否则不会生效 实例 <html lang"en"><head><style>p {width: 600px;margin: 200px auto;border: 30px soli…...

(七)Unity VR项目升级至Vision Pro需要做的工作

Vision Pro 概述 定位为混合现实眼镜&#xff0c;对AR支持更友好 无手柄&#xff0c;支持手&#xff08;手势&#xff09;、眼&#xff08;注视&#xff09;、语音交互 支持空间音频&#xff0c;相比立体声、环绕声更有沉浸感和空间感 支持VR/AR应用&#xff0c;支持多种应用模…...

【计算机视觉|生成对抗】生成对抗网络(GAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Generative Adversarial Nets 链接&#xff1a;Generative Adversarial Nets (nips.cc) 摘要 我们提出了一个通过**对抗&#xff08;adversarial&#xff09;**过程估计生成模型的新框架…...

神经网络基础-神经网络补充概念-15-神经网络概览

概念 神经网络是一种机器学习模型&#xff0c;受到人脑神经元网络的启发而设计。它可以用来解决各种各样的问题&#xff0c;包括图像识别、自然语言处理、语音识别、游戏策略等。神经网络的核心思想是通过一系列的层次结构&#xff0c;从原始数据中自动地学习和提取特征&#…...

iOS Epub阅读器改造记录

六个月前在这个YHEpubDemo阅读器的基础上做了一些优化&#xff0c;这里做一下记录。 1.首行缩进修复 由于分页的存在&#xff0c;新的一页的首行可能是新的一行&#xff0c;则应该缩进&#xff1b;也可能是前面一页段落的延续&#xff0c;这时候不应该缩进。YHEpubDemo基于XDS…...

负载均衡搭建

LVS-DR部署 [客户端] node1 192.168.157.148 [lvs] node2 192.168.157.142 [web服务器] node3 192.168.157.145 node4 192.168.157.146&#xff08;1&#xff09;[lvs] yum install -y ipvsadm.x86_64 配置LVS负载均衡服务 &#xff08;1&#xff09;手动添加LVS转发1&#xff…...

form表单input标签的23种type类型值?

当你学了很多技术以后&#xff0c;再回头看来&#xff0c;竟然被一个被一个基础问题虐了&#xff0c;23个类型值说不全&#xff0c;不是少这个&#xff0c;就是少那个&#xff0c;那么23种类型都有什么呢&#xff1f; text 单行文本输入框 password 密码输入框 file …...

python selenium如何保存网站的cookie用于下次自动登录

## 一、python selenium如何保存网站的cookie 使用Selenium保存网站的Cookie非常简单。下面是一个示例&#xff0c;展示了如何使用Selenium打开网站&#xff0c;然后保存获取到的Cookie&#xff1a; from selenium import webdriver# 初始化浏览器 browser webdriver.Chrome…...

DHCP Server

简介 动态主机配置协议 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09; 是 RFC 1541&#xff08;已被 RFC 2131 取代&#xff09;定义的标准协议&#xff0c;该协议允许服务器向客户端动态分配 IP 地址和配置信息。 使用UDP协…...

DMR+PoC宽窄融合互通解决方案

当前&#xff0c;Tetra、PDT、DMR、P25等专网通信的主流窄带技术&#xff0c;能够保障在紧急情况下可靠的关键语音通信对讲&#xff0c;但随着行业用户对图片、视频、数据等宽带业务的需求越来越强烈&#xff0c;原本单一的语音通信早已无法满足用户对新需求。 北峰BF-SCP810 D…...

Springboot定时执行任务

定时任务 TaskScheduler 任务调度者 TaskExecutor 任务执行者 EnableScheduling//开启定时功能的注释 Scheduled(cron"* * * * * * *")//什么时候执行~ cron表达式(秒 分 时 日 月 星期 ) Cron表达式 主启动类加上注解开启任务调度 package com.qf.sping09te…...

【Apollo】阿波罗自动驾驶:塑造自动驾驶技术的未来

前言 Apollo (阿波罗)是一个开放的、完整的、安全的平台&#xff0c;将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统&#xff0c;快速搭建一套属于自己的自动驾驶系统。 开放能力、共享资源、加速创新、持续共赢是 Apollo 开放平台的口号。百度把自己所拥有的强大、…...

JavaEE初阶:多线程 - Thread 类的基本用法

上次我们了解了多线程的五种创建方法&#xff0c;今天来学习Thread的基本用法。 目录 run和start Thread常见的构造方法 Thread的几个常见属性 后台线程 是否存活 线程终止 1.使用标志位 2.使用Thread自带的标志 等待线程 run和start 首先需要理解Thread的run和star…...