C++堆详细讲解

介绍

二叉堆是一种基础数据结构,主要应用于求出一组数据中的最大最小值。C++ 的STL中的优先队列就是使用二叉堆。

堆的性质 : 

1 . 堆是一颗完全二叉树 ;

2 . 堆分为大根堆 和 小根堆(这里不讨论那些更高级的如:二叉堆,二叉堆,左偏树等等)

3 . 大根堆满足每个节点的键值都小于等于其父亲键值 ;

4 . 小根堆满足每个结点的键值都大于等于其父亲键值 ;

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

6 . 大根堆和小根堆作用相反 ;

堆的操作 :

1 . 插入

        堆的插入就是把新的元素放到堆底,然后检查它是否符合堆的性质,如果符合就丢在那里了,如果不符合,那就和它的父亲交换一下,一直交换交换交换,直到符合堆的性质,那么就插入完成了 ;

示例 : 

例如下图要插入一个0 : 

First :

先将该元素插入末尾 : 

Second : 

与5比较,5>0,那么交换 : 

Third : 

再与2换 : 

fourth :

再与1交换,变成小根堆,插入结束 : 

code : 

typedef long long LL ;
const int N = 1e6 + 10 ;
void swap(int &x ,int &y){int t=x;x=y;y=t;}
int heap[N] ;
int sz ;// 堆的大小

// 小根堆的插入 
void push(int x){
	heap[++sz] = x ;
	int tmp = sz ;
	while(tmp){//还没到根节点,继续交换 
		LL nxt = tmp >> 1 ; // 找到父节点下标
		if(heap[nxt]>heap[tmp]) swap(heap[nxt],heap[tmp]);//父亲比它大,那么交换
		else break ;
		tmp = nxt ; // 交换下标 
	}
	return ;
} 

2 . 删除

示例 : 

如果要将0删掉 : 

First : 

在孩子结点中找到一个较小的值进行交换 : (这里和1交换)

Second : 

再与2交换 : 

third : 

再与5交换 : 

fourth : 

最后删掉即可 : 

        在代码实现中是直接把堆顶和堆底交换一下,然后把交换后的堆顶不断与它的子节点交换,直到这个堆重新符合堆性质 : 

code : 

void pop(){ // 删除堆顶
	swap(heap[sz],heap[1]) ;
	sz-- ;
	int now = 1 ;
	while((now<<1) <= sz){ // 对新栈顶进行向下的交换操作 
		int nxt = now << 1 ; // 找到左孩子结点下标
		if(nxt+1<=sz&&heap[nxt+1]<heap[nxt]) nxt ++ ;// 找出与那个孩子交换
		if(heap[nxt]<heap[now]) swap(heap[now],heap[nxt]);
		else break ;
		now = nxt ; // 继续下一层 
	}	
}

        手写堆支持删除任意元素 , 但是STL中的priority_queue只支持删除堆顶 ;

3 . 查询 : 

直接返回堆顶(获取最大/最小值)即可 ;

堆的STL实现 : 

首先需要引入头文件 : 

#include<queue>

然后定义priority : 

priority_queue<int> q;//这是一个大根堆q
priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q

优先队列的操作 : 

q.top()//取得堆顶元素,并不会弹出
q.pop()//弹出堆顶元素
q.push()//往堆里面插入一个元素
q.empty()//查询堆是否为空,为空则返回1否则返回0
q.size()//查询堆内元素数量

4 . 堆的复杂度

因为堆是一棵完全二叉树,所以对于一个节点数为n的堆,它的高度不会超过log2n

所以对于插入,删除操作复杂度为O(log2n)

查询堆顶操作的复杂度为O(1)

5 . 例题 : 

https://www.luogu.com.cn/problem/P3378

黑匣子 - 洛谷

[NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G - 洛谷

中位数 - 洛谷

[USACO09OPEN] Work Scheduling G - 洛谷

以【模板】堆 - 洛谷 为例 : 

手写堆 : 

#include<bits/stdc++.h>
using namespace std;

typedef long long LL ;
const int N = 1e6 + 10 ;
void swap(int &x ,int &y){int t=x;x=y;y=t;}
int heap[N] ;
int sz ;// 堆的大小

// 小根堆的插入 
void push(int x){
	heap[++sz] = x ;
	int tmp = sz ;
	while(tmp){//还没到根节点,继续交换 
		LL nxt = tmp >> 1 ; // 找到父节点下标
		if(heap[nxt]>heap[tmp]) swap(heap[nxt],heap[tmp]);//父亲比它大,那么交换
		else break ;
		tmp = nxt ; // 交换下标 
	}
	return ;
} 

void pop(){ // 删除堆顶
	swap(heap[sz],heap[1]) ;
	sz-- ;
	int now = 1 ;
	while((now<<1) <= sz){ // 对新栈顶进行向下的交换操作 
		int nxt = now << 1 ; // 找到左孩子结点下标
		if(nxt+1<=sz&&heap[nxt+1]<heap[nxt]) nxt ++ ;// 找出与那个孩子交换
		if(heap[nxt]<heap[now]) swap(heap[now],heap[nxt]);
		else break ;
		now = nxt ; // 继续下一层 
	}	
}



int main(){
	int n ; cin >> n ;
	while(n--){
		int op ; cin >> op ;
		if(op==1){
			int x ; cin >> x ;
			push(x);
		}else if(op==2){
			cout << heap[1] << endl ;
		}else{
			pop();
		}
	}	
}

使用STL : 

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n ; cin >> n ;
	priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
	while(n--){
		int op ; cin >> op ;
		if(op==1){
			int x ; cin >> x ;
			q.push(x);
		}else if(op==2){
			cout << q.top() << endl ;
		}else{
			q.pop();
		}
	}	
}

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

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

相关文章

《手把手教你》系列技巧篇(五十八)-java+ selenium自动化测试-分页测试(详细教程)

1.简介 前几天&#xff0c;有人私信里留言问宏哥&#xff0c;分页怎么自动化测试了&#xff0c;完了给他说了说思路&#xff0c;不知道最后搞定没有&#xff0c;索性宏哥就写一篇文章来讲解和介绍如何处理分页。 2.测试场景 对分页来说&#xff0c;我们最感兴趣的和测试的无非…

主流公链 - Monero

Monero: 加密货币的隐私标杆 1. 简介 Monero&#xff08;XMR&#xff09;&#xff0c;世界语中货币的意思&#xff0c;是一种去中心化的加密货币&#xff0c;旨在提供隐私和匿名性。与比特币等公开区块链不同&#xff0c;Monero专注于隐私保护&#xff0c;使用户的交易记录和余…

快速上手Pytrch爬虫之爬取某应图片壁纸

一、前置知识 1 爬虫简介 网络爬虫&#xff08;又被称作网络蜘蛛、网络机器人&#xff0c;在某些社区中也经常被称为网页追逐者)可以按照指定的规则&#xff08;网络爬虫的算法&#xff09;自动浏览或抓取网络中的信息。 1.1 Web网页存在方式 表层网页指的是不需要提交表单&…

网络: 套接字

套接字: 在网络上进行进程间通信 网络字节序与主机字节序的转化 sockaddr sockaddr struct sockaddr {sa_family_t sa_family; // 地址族char sa_data[14]; // 地址数据&#xff0c;具体内容与地址族相关 };sockaddr_in :主要是地址类型, 端口号, IP地址. 基于IPv4编程…

Linux:文件增删 文件压缩指令

Linux&#xff1a;文件增删 & 文件压缩指令 文件增删touch指令mkdir指令cp指令rm指令rmdir指令 文件压缩zip & unzip 指令tar指令 文件增删 touch指令 功能&#xff1a;touch命令参数可更改文档或目录的日期时间&#xff0c;包括存取时间和更改时间&#xff0c;或者新…

vitepress builld报错

问题&#xff1a;build时报错&#xff1a;document/window is not defined。 背景&#xff1a;使用vitepress展示自定义的组件&#xff0c;之前build是没有问题了&#xff0c;由于新增了qr-code以及quill富文本组件&#xff0c;导致打包时报错。 原因&#xff1a;vitepress官…

密码学 总结

群 环 域 群 group G是一个集合&#xff0c;在此集合上定义代数运算*&#xff0c;若满足下列公理&#xff0c;则称G为群。 1.封闭性 a ∈ G , b ∈ G a\in G,b\in G a∈G,b∈G> a ∗ b ∈ G a*b\in G a∗b∈G 2.G中有恒等元素e&#xff0c;使得任何元素与e运算均为元素本…

vue实现把Ox格式颜色值转换成rgb渐变颜色值(开箱即用)

图示&#xff1a; 核心代码&#xff1a; //将0x格式的颜色转换为Hex格式&#xff0c;并计算插值返回rgb颜色 Vue.prototype.$convertToHex function (colorCode1, colorCode2, amount) {// 确保输入是字符串&#xff0c;并检查是否以0x开头let newCode1 let newCode2 if (t…

YOLOv9改进策略:block优化 | Transformer架构ConvNeXt 网络在检测中大放异彩

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;Transformer架构 ConvNeXt 网络在图像分类和识别、分割领域大放异彩&#xff0c;同时对比 Swin-T 模型&#xff0c;在多种任务中其模型的大小和准确率均有一些提升&#xff0c;模型的 FLOPs 较大的减小且 Acc …

Solana 低至 0.4 Sol 创建OpenBook市场ID教程

Raydium上线代币之前&#xff0c;需要OpenBook ID&#xff0c;但是Raydium官方提供的链接创建需要花费 3-4 SOL。这成本使得我们对发行代币望而却步。 本篇文章介绍OpenBook的概念和教大家如何更低成本 (最低0.4 SOL) 创建 OpenBook Market ID。 目录 1、Raydium加池子创建为什…

机器学习中的 K-Means算法及其优缺点(包含Python代码样例)

一、简介 K-Means算法是一种经典的无监督学习算法&#xff0c;用于将数据集中的样本分为 K 个不同的类别。K-均值聚类算法的工作原理如下&#xff1a; 随机选择 K 个中心点作为初始聚类中心。将每个样本点分配到离其最近的聚类中心&#xff0c;形成 K 个初始聚类。通过计算每…

亮数据——让你的IP走出去,让价值返回来

亮数据——让你的IP走出去&#xff0c;让价值返回来 前言跨境电商最最最大的痛点——让IP走出去超级代理服务器加速网络免费的代理管理软件亮数据解决痛点亮数据优势介绍亮数据浏览器的使用示例总结 前言 当前社会信息的价值是不可想象的&#xff0c;今天在亮数据中看到了个【…

大话设计模式之模板方法模式

模板方法模式&#xff08;Template Method Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个算法的框架&#xff0c;将特定步骤的实现延迟到子类中。模板方法模式通过在父类中定义算法的骨架&#xff0c;而将具体步骤的实现留给子类来完成&#xff0c;从而使子类…

用搜索引擎收集信息-常用方式

1&#xff0c;site csdn.net &#xff08;下图表示只在csdn网站里搜索java&#xff09; 2&#xff0c;filetype:pdf &#xff08;表示只检索某pdf文件类型&#xff09; 表示在浏览器里面查找有关java的pdf文件 3&#xff0c;intitle:花花 &#xff08;表示搜索网页标题里面有花…

linux查找指定目录下包含指定字符串文件,包含子目录

linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 linux查找指定目录下包含指定字符串的指定文件格式&#xff0c;包含子目录 指定目录 cd /home/www/linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 grep -r "指定字符串"注释 gr…

微信开发者工具接入短剧播放器插件

接入短剧播放插线 申请添加插件基础接入app.jsonapp.jsplayerManager.js数据加密跳转到播放器页面运行出错示例小程序页面页面使用的方法小程序输入框绑定申请添加插件 添加插件:登录微信开发者平台 ——> 设置 ——> 第三方设置 ——> 插件管理 ——> 搜索“短剧…

操作系统导论-py2文件修改为py3文件快捷解决方法

在操作系统导论作业中&#xff0c;我们需要用到HW文件。但是这个代码包中&#xff0c;所有.py文件都是py2格式的&#xff0c;需要我们修改为py3文件后运行&#xff0c;即将.py文件开头的 #! /usr/bin/env python 修改为&#xff1a; #! /usr/bin/env python3 在前面小部分文件中…

【快捷部署】010_MySQL(5.7.27)

&#x1f4e3;【快捷部署系列】010期信息 编号选型版本操作系统部署形式部署模式复检时间010MySQL5.7.27Ubuntu 20.04Docker单机2024-03-28 一、快捷部署 #!/bin/bash ################################################################################# # 作者&#xff1a…

idea类已经存在却报错

一句话导读 在idea中导入新的项目&#xff0c;很多类都飘红报错&#xff0c;mvn compile可以通过&#xff0c;可能是因为idea缓存问题导致。 由于这个项目是由老项目复制过来后&#xff0c;再继续开发新的功能&#xff0c;很多同事导入后&#xff0c;都爆出新的类找不到。而编译…

正弦实时数据库(SinRTDB)的使用(4)-快照查询

前文已经将松果实时数据库的安装、创建点表、创建测点、接入OPC DA的数据进行了介绍&#xff0c;没有了解的可以先看如下博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入O…
最新文章