支持的操作

  1. 插入一个数 h e a p [ + + s i z e ] = x ;   u p ( s i z e ) heap[++size]=x;\ up(size) heap[++size]=x; up(size)
  2. 求这个集合中的最小值 h e a p [ 1 ] heap[1] heap[1]
  3. 删除最小值 (把堆的最后一个元素覆盖到堆顶,再 d o w n down down 堆顶)

h e a p [ 1 ] = h e a p [ s i z e ] ;   s i z e − − ;   d o w n ( 1 ) ; heap[1]=heap[size];\ size--;\ down(1); heap[1]=heap[size]; size; down(1);

原因是,删除数组中的头节点非常方便,删除尾节点非常困难

  1. 删除任意一个元素(手写)和删除根节点类似

h e a p [ k ] = h e a p [ s i z e ] ;   s i z e − − ;   d o w n ( k ) , u p ( k ) heap[k]=heap[size];\ size--; \ down(k),up(k) heap[k]=heap[size]; size; down(k),up(k)

down up 只有一个会被执行

  1. 修改任意一个元素(手写)

h e a p [ k ] = x ;   s i z e − − ;   d o w n ( k ) , u p ( k ) heap[k]=x;\ size--; \ down(k),up(k) heap[k]=x; size; down(k),up(k)

down up 只有一个会被执行

堆的特点

  1. 是一个平衡二叉树,除了最后一层的节点以外,其余所有节点都是满的,最后一层节点从左到右排列
  2. 每一个点都是小于等于它的左右儿子的(小根堆) → \to 根节点一定是所有节点里的最小值

堆的存储

使用一个一维数组存储!

设 1 号点为根节点,则对于数组中任意下标为 x x x 的元素, x x x 的左儿子为 2 x 2x 2x x x x 的右儿子为 2 x + 1 2x+1 2x+1

堆的基本操作

  1. d o w n ( x ) down(x) down(x) 往下调整
  2. u p ( x ) up(x) up(x) 往上调整

堆排序:https://www.acwing.com/problem/content/840/

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
#define debug(a) cout << #a << " " << a << endl
const int maxn = 1e5 + 7;
const int N = 1e6 + 7, M = N * 2;
const int inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;

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

void down(int u) {
	int t = u; //t存储的是三个点里面最小的节点编号
	if(u * 2 <= siz && h[u * 2] < h[t]) t = u * 2;
	if(u * 2 + 1 <= siz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
	if(u != t) { //如果顶点不是最小的
		swap(h[u], h[t]);
		down(t);
	}
}

int main() {

//	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

//	ios::sync_with_stdio(false);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%d", &h[i]);
	siz = n;

	for(int i = n / 2; i > 0; i--) down(i);

	while(m--) {
		printf("%d ", h[1]);
		h[1] = h[siz];
		siz--;
		down(1);
	}

	

	return 0;
}





/*
数组开够了吗 开到上界的n+1次方
初始化了吗
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值