堆的基本操作操作:
1、插入一个数:
数组末尾插入一个元素,并up()操作维护一下堆
heap[ ++ size] = x; up(size);
2、求集合当中的最小值:
小根堆的堆顶元素
heap[1]
3、删除最小值:
使用最后一个节点的值覆盖第一个节点的值,再把数组的下标--,再使用头节点down(1)运算维护一下堆。
heap[1] = heap[size]; size --; down(1);
4、删除任意一个元素(STL里面的堆无法进行的操作):
分情况判断,变大了或者变小了。
heap[k] = heap[size]; size -- ; down(k)或者up(k)
5、修改任意一个元素(STL里面的堆无法进行的操作)
heap[k] = x; down(k);或者 up(k);
堆的基本结构:
1、是一个平衡二叉树(即树除了最后一层节点可以不满以外,其它层的节点都是非空的,且最后一层节点是从左往右排列的)
2、小根堆:根节点的值小于左右子节点的值,所以根节点是最小值
堆的存储:
x的左二子是:2*x;x的右二子是:2*x+1;
注:下标从1开始比较好
堆的基本操作(时间复杂度为O(nlogn)):
down(x):x往下移动;当某个数变大的时候可以使用down操作
令根节点和根节点、左、右子节点中的最小值进行交换,重复此操作
up(x):x往上移动;当某个数变小的时候可以使用up操作
令数值较小节点和根节点、左、右子节点中的最小值进行交换,重复此操作
例题及模板代码:
堆排序(down()函数的使用)
题目内容
输入一个长度为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
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,m;
int h[N],size;
void down(int u) {
int t = u;//使用t记录根节点的值
//让根节点分别和左右子节点进行对比
if(u*2<=size&&h[u*2]<h[t])
t=u*2;
if(u*2+1<=size&&h[u*2+1]<h[t])
t=u*2+1;
if(u!=t) {//说明根节点不是最小的值,需要进行交换
swap(h[u],h[t]);
down(t);
}
}
int main() {
scanf("%d%d",&n, &m);
for(int i=1; i<=n; i++)
scanf("%d",&h[i]);
size=n;
for(int i=n/2; i; i--)//从n/2开始排序能将时间复杂度降到O(n)
down(i);
while(m--) {
printf("%d ",h[1]);//取出最小值
h[1]=h[size];//删除根节点
size--;
down(1);
}
return 0;
}