一、原理
如何手写一个堆?
堆的本质是一个完全二叉树,即除了最后一排节点,其余节点都是满的,且最后一个节点从左到右排列。
// 1、插入一个数;
heap[++size] = x; up(size);
// 2、求集合当中的最小值;
heap[1]
// 3、删除最小值;
heap[1] = heap[size]; size--; down(1);
// 4、删除任意一个元素;
heap[k] = heap[size]; size--; down(k); up(k);
// 5、修改任意一个元素;
heap[k] = x; down(k); up(k);
二、题目:堆排序
输入一个长度为n的整数数列,从小到大输出前m小的数。
输入格式:
第一行包含整数n和m;
第二行包含n个整数,表示整数数列。
二、代码
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 100010;
int m, n;
int h[N], s;
void down(int u)
{
int t = u; // 用 t 来表示三个点中的最小值
if(u * 2 <= s && h[u * 2] < h[t]) // 若左儿子节点 < 根节点
t = u * 2;
if(u * 2 + 1 <= s && 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()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &h[i]);
s = n;
for(int i = n / 2; i; i--)
down(i);
while(m--){
printf("%d", h[1]);
h[1] = h[s];
s--;
down(1);
}
return 0;
}