经典堆排序

55 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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 小的数。

数据范围

1mn1051≤m≤n≤10^5, 1数列中元素1091≤数列中元素≤10^9

输入样例:

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;
}