二叉堆的简单板子+理解+例题

首先,我们先要了解堆是什么?

堆:是一种高级树状数据结构,是一种完全二叉树。

(完全二叉树指的是,除了叶子节点,每个节点均有左右两个子节点的树状结构)

而,二叉堆是堆的最常见的实现方式。

二叉堆又可以分为:大根堆,小根堆。(可以用c++ 的 stl实现)
大根堆:每一个节点,大于等于其子节点。(从堆顶到堆底不严格递增)

小根堆:每一个节点,小于等于其子节点。(从堆顶到堆底不严格递减)

那么对于二叉堆,我们是需要手动去实现一些它的一些基本操作。

  1. 向下调整
  2. 向上调整
  3. 插入一个元素
  4. 求堆中最大值/最小值(堆顶)
  5. 删除堆中最大值/最小值

下面先实现最大堆/大根堆的操作:

1.使用vector容器实现:

//定义一个最大堆,先给里面装填一个空元素,使得后续插入的元素下标一一对应:
//意思是,第一个数的下标就是 1,而不是0 ,同时也是 size() -1 
vector<int > big(1);

2.向上调整

void upp(int pos) {while (pos > 1) {                        // 循环直到节点到达堆顶if (big[pos] > big[father]) {        // 如果当前节点的值大于其父节点的值swap(big[pos], big[father]);     // 交换当前节点与父节点的值}else break;                          // 如果不满足最大堆性质,终止循环pos = father;                        // 更新当前节点的位置为父节点}
}

3.向下调整

void down(int pos) {int size = big.size();                    // 获取堆的大小while (2*pos <= size-1) {                 // 当前节点有至少一个子节点时循环int son;if (rson <= size - 1 and big[lson] < big[rson]) {       // 如果当前节点有右子节点且右子节点的值大于左子节点的值son = rson;                                         // 则选取右子节点作为子节点}else son = lson;                                        // 否则选取左子节点作为子节点if (big[pos] < big[son])swap(big[son], big[pos]);        // 如果当前节点的值小于子节点的值,则交换它们的位置else break;                                             // 如果不满足最大堆性质,终止循环pos = son;                                              // 更新当前节点的位置为子节点}
}

4.插入一个数:

void insert(int val) {big.push_back(val);              // 将元素 val 添加到堆的末尾upp(big.size() - 1);             // 调用 upp 函数,以维护最大堆性质
}

5.删除最大值:

void earse_big() {if (big.size() > 1) {                   // 如果堆中有至少两个元素big[1] = big[big.size() - 1];       // 将第一个元素用最后一个元素覆盖big.pop_back();                     // 删除最后一个元素down(1);                            // 对堆顶元素进行向下调整,以满足最大堆性质}
}

6.返回最大值:

int get_max() {if (big.size() > 1) {return big[1];}
}

以上就是二叉堆中的最大堆实现的过程。

不过在实际的写题中,我们不需要每次手写一个二叉堆。

可以直接用现成的stl 容器,priority_queue;

下面简单介绍以下stl的用法:

priority_queue<int>  bigheap;  //priority_queue 默认大根堆
priority_queue<int, vector<int>, greater<int> > littleheap; // 如果要定义小根堆,就要写全参数
// priority_queue 的参数为: 数据类型、容器类型、定义类型。 
//如果是小根堆, 我们在第三个参数那里改成: greater<int> 
//如果是大根堆:完整的写法就是: priority_queue<int , vector<int> , less<int> >  堆的名字

然后,下面是一些堆的函数:

priority_queue<int>  big;
priority_queue<int, vector<int>, greater<int> > little;int main() {big.push(1); //插入的同时自动调整位置big.pop();//删除堆顶元素big.top()//返回堆顶元素 最大值/最小值}

下面给一道堆的模板题:

P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P3378答案:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cctype>
#include<map>
#include<set>
#include<queue>
#include<numeric>
#include<iomanip>
#include<stack>
#include<list>
using namespace std;#define ll long long
#define lson pos<<1
#define rson (pos<<1)|1
#define father pos>>1
const int N = 1e6 + 7;
//二叉堆:
// 最大堆,最小堆
// 最大堆要满足一个性质:任意一个节点,如果它的子节点存在的话,这个节点的值是要大于等于它的子节点的任意的值
// 
// 1、向下调整的函数
// 2、向上调整的函数
// 3、向一堆数据中插入一个元素
// 4、在一堆数据中删除一个元素(最大值)
// 5、求出一堆数据里面的最大值。
//
//
vector<int > heap(1);
void heapup(int pos) { //node 指的是vector下标while (pos > 1) {if (heap[pos] < heap[father]) {swap(heap[pos], heap[father]);}else {break;}pos = father;}}//第一个问题: 为什么heapdown函数中 循环的条件要取等
void heapdown(int pos) {int size = heap.size(); //实际上堆里面的元素为 size-1, size指的是一个空的下标while ( lson < size) {int son;if (rson<size and heap[lson] > heap[rson]) {son = rson;}else son = lson;if (heap[pos] < heap[son])break;else {swap(heap[pos], heap[son]);}pos = son;}
}void insert(int val) {heap.push_back(val);int size = heap.size();heapup(size - 1);}int get_min() {return heap[1];}void earse_min() {if (heap.size() > 1) {heap[1] = heap[heap.size() - 1];heap.pop_back();heapdown(1);}}bool empty() {if (heap.size() > 1)return true;else return false;
}int main() {int n;cin >> n;while (n--) {int op;cin >> op;if (op == 1) {int x;cin >> x;insert(x);}else if (op == 2) {cout<<get_min();cout << '\n';}else {earse_min();}}
}

下面讲一下,二叉堆的综合运用:

1. 对顶堆

先给一个模板题,来看看对顶堆的使用场景

P1801 黑匣子 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1801然后,来介绍一下对顶堆:

堆顶堆由两个堆组成,一个大根堆,一个小根堆。

比如一遍往堆里插入元素,一遍问第i大的元素是哪个?

我们可以这样写:

它问第i大的元素是哪个?

我们就可以构造出一个这样的形状

 不断往小根堆中插入元素,直到插满i个元素,此后的话,执行这样一个操作:

先往小根堆里插入元素,然后取出小根堆的堆顶,加入上面的大根堆,然后删除小根堆的堆顶。

这样就实现了一个目的:

小根堆内的元素仍然是i个,但在新元素插入后,调整了大小关系,仍然使得小根堆的堆顶的元素是当前的第i大的元素(即时现在有超过i个元素,大于第i大的元素,都被放到了大根堆里)

如果i开始变化,如i变成i+1,那么我们直接把当前大根堆的堆顶的元素加入小根堆中,这个元素一定会在小根堆的堆顶,然后我们在删除大根堆的堆顶,使之调整结构

那么对于求第i小的元素,我们也是同样的道理,只要下面放大根堆,上面放小根堆,维护大根堆内的元素为i个,那么大根堆的堆顶就是在当前两个堆中,第i小的那个元素:

上题解:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cctype>
#include<map>
#include<set>
#include<queue>
#include<numeric>
#include<iomanip>
#include<stack>
#include<list>
using namespace std;#define ll long long
#define lson pos<<1
#define rson (pos<<1)|1
#define father pos>>1
const int N = 2e6 + 7;
priority_queue<int>  bigheap;
priority_queue<int, vector<int>, greater<int> > littleheap;int a[N];//元素
int opt[N];//操作
int main() {int m, n; //元素个数,操作个数cin >> m >> n;for (int i = 1; i <= m; i++) {cin >> a[i];}for (int j = 1; j <= n; j++) {cin >> opt[j];}int tot = 1, j = 1;for (int i = 1; i <= m; i++) {bigheap.push(a[i]);if (bigheap.size() >= tot) {littleheap.push(bigheap.top());bigheap.pop();}while (i == opt[j]) {cout << littleheap.top() << endl;bigheap.push(littleheap.top());littleheap.pop();j++;tot++;}}
}

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

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

相关文章

古有华山论剑,今有流程之争|谁在误导人?

有意思&#xff0c;今天被人怼了&#xff0c;说我误导人。 起因是我前些天写过两篇文章&#xff0c;第一篇是&#xff1a;Nextflow生物信息流程&#xff08;一&#xff09;&#xff1a;简介 一个入门帖子&#xff0c;反响平平。我原本也是打算好好学习一下 Nextflow 来着&#…

Deeplearning4j 实战 (22):基于DSSM的语义匹配建模

Deeplearning4j 实战 &#xff08;22&#xff09;&#xff1a;基于DSSM的语义匹配建模 Eclipse Deeplearning4j GitChat课程&#xff1a;Deeplearning4j 快速入门_专栏 Eclipse Deeplearning4j 系列博客&#xff1a;万宫玺的专栏_wangongxi_CSDN博客 Eclipse Deeplearning4j G…

记录 Docker 中安装 ROS2

目录 1 安装 Docker 2 安装 ROS2 3 启动 Docker 4 测试 ROS2 环境 1 安装 Docker 1. 更新软件包sudo apt updatesudo apt upgrade2. 安装 docker 依赖sudo apt-get install ca-certificates curl gnupg lsb-release3. 添加 docker 官方 GPG 密钥curl -fsSL http://mirror…

Jetpack Compose中使用Android View

使用AndroidView创建日历 Composable fun AndroidViewPage() {AndroidView(factory {CalendarView(it)},modifier Modifier.fillMaxWidth(),update {it.setOnDateChangeListener { view, year, month, day ->Toast.makeText(view.context, "${year}年${month 1}月$…

Oracle开发经验总结

文章目录 1. 加注释2. 增加索引3. nvl(BOARDCODE&#xff0c;100)>004. 去掉distinct可以避免hash比较&#xff0c;提高性能5. like模糊查询优化(转化为instr()函数)6. SQL计算除数为0时&#xff0c;增加nullif判断7. 分页8. 查看执行计划9. <if test"productCode !…

【2023】hadoop基础介绍

&#x1f4bb;目录 Hadoop组成HDFSHDFS操作HDFS分布式文件存储NameNode元数据数据读写流程 YARN和MapReduceMapReduce&#xff1a;分布式计算YARN&#xff1a;资源管控调度YARN架构提交任务到**YARN中运行** Hadoop组成 hadoop安装教程可以看我这篇文章> &#x1f345;hado…

C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)

本文主要介绍回调函数的使用&#xff0c;包括函数指针、异步回调编程、主要通过详细的例子来指导在异步编程和事件编程中如何使用回调函数来实现。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;C/C精进之路 &…

JavaScript 基础通关

快速熟悉 JavaScript 的基础语法&#xff0c;比较高级的比如事件放在后面的笔记中。 JavaScript 1. JavaScript 介绍 1.1 JavaScript 基本介绍 JavaScript 是一门运行在客户端&#xff08;浏览器&#xff09;的编程语言&#xff0c;实现人机交互的效果。实现网页特效、表单验…

海康visionmaster-渲染结果:控件颜色:控件颜色修改的方法

描述 环境&#xff1a;VM4.0.0 VS2015 及以上 现象&#xff1a;简易修改 VM 控件的颜色&#xff1f; 解答 对二次开发中嵌入控件的颜色进行修改&#xff0c;具体代码如下&#xff1a; C# string colorinfo “ColorStyle3”; AppColorService.CurColorDefine colorinfo; “Co…

OpenWrt 编译入门(小白版)

编译环境 示例编译所用系统为 Ubuntu 22.04&#xff0c;信息如下 编译时由于网络问题&#xff0c;部分软件包可能出现下载问题&#xff0c;还请自备网络工具或尝试重新运行命令 编译步骤 下图为官网指示 编译环境设置&#xff08;Build system setup&#xff09; 这里根据我…

springboot实现用户操作日志记录

springboot实现用户操作日志记录 简介&#xff1a;之前写了《aop实现日志持久化记录》一文&#xff0c;主要介绍自定义aop标注方法上&#xff0c;通过切面方法对用户操作插入mysql。思路正确但是实际操作上存在一些小问题&#xff0c;本文将从项目出发&#xff0c;对细节进行补…

Nginx 代理静态资源,解决跨域问题

&#x1f602; 背景&#xff1a;移动端 H5 项目&#xff0c;依赖了一个外部的 JS 文件。访问时&#xff0c;出现跨域&#xff0c;导致请求被 block。 当前域名&#xff1a;https://tmcopss.test.com要访问的 JS 文件&#xff1a;https://tm.test.com/public/scripts/y-jssdk.j…