开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第37天,点击查看活动详情
什么是堆?
堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看做一棵完全二叉树的数组对象。
然而堆又分为两种,一种是大根堆,一种是小根堆
大根堆
大根堆简单来说就是对一颗二叉树,它的左右孩子有两种情况:
- 不存在:即为NULL
- 存在:需要满足一个条件——根节点是最大的
小根堆
小根堆和大根堆差不多,对于一个二叉树的小根堆,它的左右孩子有以下两种情况:
- 不存在:即为NULL
- 存在:需要满足一个条件——根节点是三个点最小的
如何用数组手写一个堆?
up函数
up函数简单来说就是调整一个结点,将这个结点往上移动
down函数
down函数简单来说就是调整一个结点,将这个结点往下移动
什么是heap数组?
heap数组就是用来存储堆的数组
实现方法(小根堆):
这里只列举了小根堆的做法,大根堆和这个差不多
问题 | 解决方法 | 解释 |
---|---|---|
1.插入一个数 | heap[++size]=x;up(size) | 直接将这个数插入到数组的最末尾,然后向上调整 |
2.求集合中的最小值 | heap[1]; | 堆顶就是最小值 |
3.删除最小值 | heap[1]=heap[size];size--;down(1) | 最小值就是堆顶元素,让堆顶元素和末尾加一元素交换,然后直接down调整 |
4.删除任意一个元素 | heap[k]=heap[size];size--;down(k);up(k); | 可以直接判断(向上调整还是向下调整还是不用调整),这里是直接的线down一下再up一下,直接简单粗暴了 |
5.修改任意一个元素 | heap[k]=x;down(k);up(k) | down和up原因与4是一样的 |
题目示例:
题目描述:
输入一个长度为 n 的整数数列,从小到大输出前 m 小的数。
输入格式
第一行包含整数 n 和 m。
第二行包含 n 个整数,表示整数数列。
输出格式
共一行,包含 m 个整数,表示整数数列中前 m 小的数。
数据范围
输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3
代码展示:
#include<iostream>
using namespace std;
const int N = 100010;
int heap[N], idx;
void down(int u) {
int t = u;
//如果存在左孩子,且左孩子比根节点小的话进行交换
if (u * 2 <= idx && heap[u * 2] < heap[t])t = u * 2;
//如果存在右孩子,且右孩子比根节点小的话进行交换
if (u * 2 + 1 <= idx && heap[u * 2 + 1] < heap[t])t = u * 2 + 1;
if (u != t) {
swap(heap[u], heap[t]);
down(t);//此时t就是交换的点
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> heap[i];
idx = n;
//建立堆:
for (int i = n / 2; i; i--)down(i);
while (m--) {
cout << heap[1] << " ";
heap[1] = heap[idx];
idx--;
down(1);
}
return 0;
}