堆模板的详细讲解~通俗易懂,快进来学吧!!!

堆模板



🤖 作者简介: w20,自律才有自由 ⭐⭐⭐

1.学习难点:理解ph[]和hp[]数组、堆的调整

2.学习要求:掌握各种堆操作

(1)交换堆中元素
(2)下调堆
(3)上调堆
(4)建堆
(5)删除堆中最小值
(6)删除堆中任意一个元素
(7)修改堆中任意一个元素
(8)向堆中插入一个元素
(9)可以先看看这里的完整代码,有各种变量的详细解释,方便大家理解!!!

3.练习:链接在这里

AcWing 838 堆排序
AcWing 839 模拟堆

掌握标题2中内容后,恭喜你~ ~ ~ 你很棒!!! 可以愉快地进行上面的练习啦!!!
如果对屏幕前的你有点帮助的话,就请帮小博主点个赞吧~ ~ ~ 收藏一下下次可以更快找到哦~ ~ ~谢谢啦!

(1)交换堆中元素

h[N]存储堆中的值,h[1]是堆顶,x的左儿子是2x,右儿子是2x+1
ph[k]存储第k个插入的点在堆中的位置
hp[k]存储堆中下标是k的点是第几个插入的 交换时,映射关系和值都需要交换

void heap_swap(int a,int b)//交换两个点,及其映射关系
{
	swap(ph[hp[a]],ph[hp[b]]);
	swap(hp[a],hp[b]);
	swap(h[a],h[b]);
} 

(2)下调堆

首先判断这个节点是否有左右儿子,若有,则分别与左右两个儿子比较,判断是否需要交换,采用递归的思想,层层下调。交换遵循的原则:此堆为小根堆,越往下走,值越大。

void down(int u)//下调 
{
	int t=u;
	if(u*2< = size && h[u *2]<h[t])t=u*2;
	if(u*2+1<=size && h[u*2+1]<h[t])t=u*2+1;
	if(u!=t)
	{
		heap_swap(u,t);
		down(t);
	} 
}

(3)上调堆

与下调堆的思想类似,但上调是从下往上调整堆。交换遵循的原则不变:此堆为小根堆,越往下走,值越大。

void up(int u)
{
	while(u/2 && h[u]<h[u/2])
	{
		heap_swap(u,u/2);
		u>>=1;
	}
}

(4)建堆

建堆的思想是遍历数组中的每个节点依次下调,最终形成一个堆。由于节点的儿子至少是此节点下标的2倍,所以i只需从n/2处开始就能遍历所有节点,最后的叶子节点(终端节点)没有儿子,不用再往下调。

void create_heap()//建堆 
{
	for(int i=n/2;i;i--)
	down(i); 
}

(5)删除堆中最小值

此堆是小根堆,堆顶元素即为最小值。删除的思想是把最后一个根节点放在堆顶。只需先将堆顶元素与最后一个元素交换,再把堆中元素的个数减1,这样堆中就少了一个元素了。但是到这里还没有结束,此时堆顶为之前的最后一个根节点,堆还没变成小根堆,所以需要从堆顶处下调堆便大功告成啦。

void delete_top()//O(log n) ,删除最小值 
{
	heap_swap(1,size--);//删除堆顶,并把最后一个根结点放在堆顶,之后进行下调,以重新调整堆 
	down(1);
}

(6)删除堆中任意一个元素

删除的思想与上面类似,删除第k个插入堆中的元素(k下标从1开始)。
找到第k个插入堆中的元素在堆中的下标,即ph[k]。之后交换k所在节点与最后一个根节点。因为不确定k所在节点是在哪里,所以上调下调都进行一遍。(提醒:下调和上调两者只会执行一个)

void delete_one(int k)//删除任意一个元素,删除第k个插入堆中的元素,k从1开始 
{
	k=ph[k]; 
	heap_swap(k,size--); 
	down(k);
	up(k);//up和down两者只执行其一 
} 

(7)修改堆中任意一个元素

修改第k个插入堆中的元素,找到第k个插入堆中的元素在堆中的下标,即ph[k]。再修改值,改完值后下调+上调。

void update_one(int k,int x)//修改任意一个元素,把堆中第k个插入堆中的元素的值设置成x,k从1开始 
{
	k=ph[k]; 
	h[k]=x;
	down(k);
	up(k);
} 

(8)向堆中插入一个元素

size表示堆中元素的个数,也表示堆中最后一个元素的位置。将size+1,插入一个节点,值为x。之后更新ph[]与hp[],m与size两者互相映射。(m与size设成全局变量,初始值均为1。)因为插入是在最后一个位置插入,所以上调堆即可。

void insert(int x)//插入一个数
{
	h[++size]=x;
	m++;
	ph[m]=size,hp[size]=m;//m与size互相映射
	//第m个插入的数在堆中给的位置是size,堆中位置为size的数是第m个插入的。 
	up(size);
} 

(9)完整代码

//小根堆 
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
typedef long long ll;
//h[N]存储堆中的值,h[1]是堆顶,x的左儿子是2x,右儿子是2x+1
//ph[k]存储第k个插入的点在堆中的位置
//hp[k]存储堆中下标是k的点是第几个插入的
int h[N],ph[N],hp[N],size;
int m;//用m记录字符出现的序号 
void heap_swap(int a,int b)//交换两个点,及其映射关系
{
	swap(ph[hp[a]],ph[hp[b]]);
	swap(hp[a],hp[b]);
	swap(h[a],h[b]);
} 
void down(int u)//下调 
{
	int t=u;
	if(u*2< = size && h[u *2]<h[t])t=u*2;
	if(u*2+1<=size && h[u*2+1]<h[t])t=u*2+1;
	if(u!=t)
	{
		heap_swap(u,t);
		down(t);
	} 
}
void up(int u)
{
	while(u/2 && h[u]<h[u/2])
	{
		heap_swap(u,u/2);
		u>>=1;
	}
}
void create_heap()//建堆 
{
	for(int i=n/2;i;i--)
	down(i); 
}
void delete_top()//O(log n) ,删除最小值 
{
	heap_swap(1,size--);//删除堆顶,并把最后一个根结点放在堆顶,之后进行下调,以重新调整堆 
	down(1);
}
void insert(int x)//插入一个数
{
	h[++size]=x;
	m++;
	ph[m]=size,hp[size]=m;//m与size互相映射
	//第m个插入的数在堆中给的位置是size,堆中位置为size的数是第m个插入的。 
	up(size);
} 
void delete_one(int k)//删除任意一个元素,删除第k个插入堆中的元素,k从1开始 
{
	k=ph[k]; 
	heap_swap(k,size--); 
	down(k);
	up(k);//up和down两者只执行其一 
} 
void update_one(int k,int x)//修改任意一个元素,把堆中第k个插入堆中的元素的值设置成x,k从1开始 
{
	k=ph[k]; 
	h[k]=x;
	down(k);
	up(k);
} 
int main()
{}

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值