基础数据结构及其应用

一,栈

1,普通栈

2,单调栈

3,对顶栈

一,队列

1,普通队列

2,单调队列

三,堆

1、二叉堆

对象: 以数为元素的集合(数组)
特性:O(1)的取出数组最大值(大根堆)或者最小值(小跟堆)
维护: 1,向上修改 (用于加入新元素) 2,向下修改(用于删除最值点(根节点))
手段: 逐层交换

操作1 插入:

二叉堆是完全二叉树,所以,树的根节点是1,对于任意非根节点,父亲=x/2,儿子=x * 2 或 x * 2 + 1

void inss(int x)       小跟堆插入
{
	nums++;            堆内数字个数统计更改
	int i=nums;
	s[i]=x;
	while (i/2&&s[i/2]>s[i])swap(s[i],s[i/2]),i/=2;   向上操作
} 

void insb(int x)        大跟堆插入
{
	numb++; 
	int i=numb;
	b[i]=x;
	while (i/2&&b[i/2]<b[i])swap(b[i],b[i/2]),i/=2;
}

操作2 取堆顶并删除:

由于根在儿子确定后非常唯一,所以需要讨论的其实只有左右儿子谁大或者(谁小),并记录那个孩子的序号,父亲可能就是和他换了,所以每次循环op操作的是初始op的儿子,这姑且算是一个小改变 (编者自编,正确性未知~~)

范围说: op只能到倒数第二层,留一层给他的儿子在循环中操作

int popb()     大根堆取顶删除操作 
{
	int ans=b[1];
	swap(b[1],b[numb]);   b[numb]=0;   numb--;
	int op=1;
	while (op*2<=numb)      由于可能删除后某些 二叉树只有左儿子,所以先判左儿子 
	{
		op*=2;  //向下到左儿子 
		if(op+1<=numb&&b[op+1]>b[op])op++;    右儿子没有超范围,且由于维护了大根,我们只要儿子中最大的 
		if(b[op]>b[op/2])swap(b[op],b[op/2]);     若最大的儿子比父亲大,换!否则就止步于此了 
		else break;
	}
	
	return ans;    反正 我只要堆顶(dogeeee!)
}
 
int pops()      小根堆取顶删除操作 (注释同上,懒得搬了)
{
	int ans=s[1];
	swap(s[1],s[nums]);  s[nums]=0;   nums--;
	int op=1;
	while (op*2<=nums)
	{
		op=op*2;
		if(op+1<=nums&&s[op+1]<s[op])op++;
		if(s[op]<s[op/2])swap(s[op],s[op/2]);
		else break;
	}
	
	return ans;
}

2、对顶堆

联系: 一个大根堆和一个小跟堆的集合
特性: 取出数组中第k大的数,并且动态改k也是可以的
思维:小根堆维护第k个以及比k大的所有,大根堆维护比第k个小的所有(俩堆由于k联系,如同头顶相对一样)

在这里插入图片描述

操作1 维护:

以维护小跟堆为主,当小跟堆的数据数高于k,取对顶并插入大根堆,恒令小根堆有k个元素

	cin>>x;
	inss(x);
	if(nums>k)insb(pops());

操作2 删取第k大的数:

小根堆弹出,大根堆抽数补充

	cout<<pops()<<endl;
	inss(popb());

操作3 改k并维护:

k若是大于小根堆数目,就抽小根入大根,反之就抽大根入小跟(总之保证k==size of 小根堆)

	cin>>k;
	if(k>nums)inss(popb());
	if(k<nums)insb(pops());

若是要第K小,就就是维护大根堆为主

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流苏贺风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值