为来蓝桥杯打算法-堆

功能(操作)

插入一个数
求集合中的最小值
删除最小值

额外的操作

删除任意一个元素
修改任意一个元素

堆的本质

二叉树,且是完全二叉树(即除了最后一层的节点,其他层的节点的分支都有两个,最后一层的节点从左到右排列)

在这里插入图片描述

小根堆的特点

从上往下看,每个节点的值依次增高
所以根节点是最小的值
再往下
左边的节点比他下面的两个节点还小,右边的节点也比他下面的两个节点还小

堆的存储

用一维数组存储所有的节点

对于根节点 就存储在q[1]

根节点的左节点 存储在q[2],右节点存储在q[3]

左节点的左节点存储在q[4], 右节点存储在q[5]

右节点的左节点存储在q[6], 右节点存储在q[7]

因此可以得出一个规律,从根节点开始,节点设为x

x下面的左节点就存储在q[2 * x],右节点就存储在q[2 * x + 1]

在这里插入图片描述

down操作

在这里插入图片描述

简单来说就是把一个节点往下移
如果一个节点的值改变了,那么他在堆里应该放在适合的位置

改变时的树

down操作的原理是
如果该节点比他下面的节点大的话,那么就交换一下
如果交换后还比下面的大,那么就再和下面的节点交换
直到符合小根堆的性质

down操作后的树
在这里插入图片描述

up操作

与down操作如出一辙

最后我们可以知道一开始那些操作是如何实现的

用heap存储每一个节点,size作为元素量也是下标

插入一个数 
 把要插入的数放到数组最后一个位置,然后对新节点up操作
heap[++size] = x;
up(size);
求集合中的最小值
就是heap[1]
删除最小值
让最后一个节点覆盖掉根节点,然后对根节点down操作
heap[1] = heap[size];
size--;
down(1);
删除任意一个元素
直接让最后一个节点覆盖掉该节点,然后对他进行up和down操作
因为up和down只会执行一个,那么他是比原来节点大于等于小于都是无所谓的
heap[k] = heap[size];
size--;
up(k),down(k);
修改任意一个元素
与删除同理,只不过heap[size]变成了x
heap[k] = x;
up(k),down(k);

模板

堆排序

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5;

int n, m;
int h[N],se;

void down(int u)
{
	int t = u;
	if (u * 2 <= se && h[u * 2] < h[t])//左节点比较
		t = u * 2;
	if (u * 2 + 1 <= se && h[u * 2 + 1] < h[t]) //右节点比较
		t = u * 2 + 1;

	if (u != t)
	{
		swap(h[u], h[t]);
		down(t);
	}
}

void up(int u)
{
	while (u / 2 && h[u / 2] > h[u])
	{
		swap(h[u / 2], h[u]);
		u /= 2;
	}
}
int main()
{
	cin >> n >> m;

	for (int i = 1;i <= n;++i) scanf("%d", &h[i]);
	se = n;

	for (int i = n / 2;i;i--) down(i);//时间复杂度接近O(1)

	while (m--)
	{
		printf("%d ", h[1]);
		//删除堆顶元素
		h[1] = h[se];
		se--;
		down(1);
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

涅槃豆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值