思路
如何手写一个堆,在这主要应用数组去实现一个堆。
- 插入一个数 heap[++ size] = x; up(size);
- 求集合当中的最小值 heap[1]
- 删除最小值 heap[1] = heap[size];size--;down(1);
- 删除任意一个元素 heap[k] = heap[size];size--;up(k);down(k);
- 修改任意一个元素 heap[k] = x;down(k);up(k);
题目
输入一个长度为 n 的整数数列,从小到大输出前 m 小的数。
输入格式
第一行包含整数 n 和 m
第二行包含 n 个整数,表示整数数列。
输出格式
共一行,包含 m 个整数,表示整数数列中前 m 小的数。
数据范围
1≤m≤n≤10^5 1≤数列中元素≤10^9
输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3
代码
java
import java.util.Scanner;
public class Main {
static int cnt, n, m, N = 100010;
static int[] a = new int[N];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt(); // 输入数组的大小
m = in.nextInt(); // 操作次数
for (int i = 1; i <= n; i++) {
a[i] = in.nextInt(); // 输入数组元素
}
cnt = n; // 堆中元素个数初始化为n
// 建堆过程
for (int i = n / 2; i >= 1; i--) {
down(i); // 对每个非叶子节点进行下沉操作,构建小顶堆
}
// 执行m次操作
while (m > 0) {
m--;
System.out.print(a[1] + " "); // 输出堆顶元素(最小值)
a[1] = a[cnt--]; // 将堆顶元素替换为堆尾元素,堆元素个数减1
down(1); // 对新的堆顶元素进行下沉操作,维护小顶堆性质
}
}
// 下沉操作,将节点u下沉到合适的位置,以维护小顶堆性质
private static void down(int u) {
int t = u; // 记录最小值的位置
// 如果存在左子节点,且左子节点的值小于当前节点值,则更新最小值位置
if (u * 2 <= cnt && a[u * 2] < a[t]) t = u * 2;
// 如果存在右子节点,且右子节点的值小于当前节点值,则更新最小值位置
if (u * 2 +