首页 > 编程语言 >C++堆详细讲解

C++堆详细讲解

时间:2024-03-30 10:58:35浏览次数:20  
标签:tmp sz 详细 nxt int 交换 C++ heap 讲解

介绍

二叉堆是一种基础数据结构,主要应用于求出一组数据中的最大最小值。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();
		}
	}	
}

标签:tmp,sz,详细,nxt,int,交换,C++,heap,讲解
From: https://blog.csdn.net/ros275229/article/details/137067494

相关文章

  • Junit深入讲解(JAVA单元测试框架)
    1、此处用的是Junit5,此处pom文件需要引的依赖是<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.1</version><scope&......
  • lodash已死?radash最全使用介绍(附源码详细说明)—— Array方法篇(1)
    相信很多前端同学甚至非前端都或多或少使用过lodash库,我们都知道lodash是一个非常丰富的前端工具库,比如最常用的防抖和节流,使用lodash都能很快实现,在github上更是有着58.7k的star数。但最近出现的Radash库,号称lodashplus版本,比之更新、更小、更全面、源码更易于理解。阅读本文......
  • C#多线程编程详细教学
     在C#中,多线程编程是一种非常重要的技术,它允许程序同时执行多个任务,从而提高了应用程序的响应性和整体性能。本文将详细介绍C#中的多线程编程,包括基本概念、线程创建、线程同步以及相关的代码示例。一、基本概念线程是操作系统进行运算调度的最小单位,它被包含在进程之中,是......
  • C++项目——集群聊天服务器项目(七)Model层设计、注册业务实现
    在前几节的研究中,我们已经实现网络层与业务层分离,本节实现数据层与业务层分离,降低各层之间的耦合性,同时实现用户注册业务。网络层专注于处理网络通信与读写事件业务层专注于处理读写事件到来时所需求的各项业务数据层专注于与底层数据库间进行增删改查。数据库中有User、Fr......
  • 大海捞针 Skia(C++) 第 4.1 期(特别篇):将绘制结果输出到窗口
    前言由于本人(我)没有系统学习过图形学,无法提供准确的术语表达,如果哪位大佬看到我的一些错误,还请友善指出!第四期之后,我一直纠结于应该讲些什么。图形学的东西我真的学的不多,未来也不是很想走这个方向。但是我仍然希望通过我的一些绵薄之力为一些苦苦寻找关于Skia资料的兄弟们提供......
  • 华为OD机试 - 传递悄悄话(Java & JS & Python & C & C++)
    须知哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持文章目录须知题目描述输入描述输出描述解题思路:题目描述给定一个二叉树,每个节点上站一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。初始时,根节点所在......
  • 华为OD机试 - 剩余银饰的重量(Java & JS & Python & C & C++)
    须知哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持文章目录须知题目描述输入描述输出描述解题思路:题目描述有N块二手市场收集的银饰,每块银饰的重量都是正整数,收集到的银饰会被熔化用于打造新的饰品。每一回合,从中选......
  • 2024年03月CCF-GESP编程能力等级认证C++编程八级真题解析
    本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。一、单选题(每题2分,共30分)第1题为丰富食堂菜谱,炒菜部进行头脑风暴。肉类有鸡肉、牛肉、羊肉、猪肉4种,切法有肉排、肉块、肉末3种,配菜有圆白菜、油菜、豆腐3种,辣度有......
  • 2024年03月CCF-GESP编程能力等级认证C++编程七级真题解析
    本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。一、单选题(每题2分,共30分)第1题下列关于排序的说法,正确的是()。A.冒泡排序是最快的排序算法之一。B.快速排序通常是不稳定的。C.最差情况,N个元素做归并排序......
  • ccfcsp-2019-12-2回收站选址(c++满分题解)
    该题就是考察点的保存以及索引的保存和遍历,看了他的用例说明,我原先以为暴力只能得50分,但是又没有想到别的优化方法,就写了一下暴力,发现居然AC下面是代码:#include<iostream>#include<vector>#include<map>usingnamespacestd;intmain(){ intn; cin>>n; vector<pair<......