堆模拟(模板题)


一、什么是堆

堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
(1)堆中某个节点的值总是不大于或不小于其父节点的值;
(2)堆总是一棵完全二叉树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
堆是非线性数据结构,相当于一维数组,有两个直接后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
————————————————

参考原文链接:https://blog.csdn.net/weixin_44123362/article/details/103873058

二、堆的实现

因为堆是一个二叉树,为了代码的简洁和方便,我们可以用一维数组进行模拟堆。
用数组模拟的二叉树又有性质下标为n的父节点的下标为n/2,根据这个性质我们很快可以将二叉树的左右子树区分开来。如此即可完成堆的简要构建。

三、例题及代码的实现

1.题目:堆模拟

来源于acwing

2.题目解析

题目的大致要求为构建一个小根堆并且具备如下功能:
1.插入数据
2.输出最小数据
3.删除最小数据
4.修改或删除任意处的数据
那么为了实现这些功能,首先我们需要构建几个变量用于储存相关数据。
h[N]用来存储数据
ph[N]用来存储第N次插入的数在堆里面的下标
hp[N]用来存储堆里面的下标为N的点是第几次插入的
cnt记录当前数据的个数
m记录插入的次数
其次,我们需要写相关函数用来实现此些功能。
分析功能3,可知实现删除功能不能直接进行删除,而是变相删除,那么可将需要删除的数据与最后一个数据的位置进行交换(此处需要实现交换功能),再将需要删除的数据进行标记处理,别忘了交换后位置的数据还需要进行处理,将堆整理平衡,那么我们又需要实现平衡堆的功能

3.代码的实现

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

const int maxn = 100010;
int n,m,h[maxn],cnt,ph[maxn],hp[maxn];
// ph存第k次插入的数在堆里面的下标   hp存堆里面的下标为k的点是第几次插入的 

void hswap(int a,int b){	
	swap(h[a],h[b]);
	swap(ph[hp[a]],ph[hp[b]]);
	swap(hp[a],hp[b]);
}
void down(int u){
	int t=u;
	if(2*u<=cnt && h[t]>h[2*u])t=2*u;
	if(2*u+1<=cnt && h[t]>h[2*u+1])t=2*u+1;
	if(t!=u){
		hswap(t,u);
		down(t);
	}
}
void up(int u){
	while(u/2 && h[u]<h[u/2]){
		hswap(u,u/2);
		u/=2;
	}
}
int main() {
	string str;
	cin>>n;
	while(n--){
		cin>>str;
		if(str=="I"){
			int x;
			cin>>x;
			cnt++,m++;
			h[cnt]=x;
			ph[m]=cnt;
			hp[cnt]=m;
			down(cnt),up(cnt);
		}
		else if(str=="PM"){
			cout<<h[1]<<endl;
		}
		else if(str=="DM"){
			hswap(1,cnt);
			cnt--;
			down(1),up(1);
		}
		else if(str=="D"){
			int k;
			cin>>k;
			k=ph[k];//此处将k修改为第k次插入的数在堆中的下标
			hswap(k,cnt);
			cnt--;
			down(k),up(k);
		}
		else if(str=="C"){
			int k,x;
			cin>>k>>x;
			k=ph[k];
			h[k]=x;
			down(k),up(k);
		}
	} 
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值