学习了 Heap,其实不难。
用途:在 O(log(n)) 的时间内插入、返回和删除最大值或最小值。
它是这样一颗二叉树,父节点的值总是大于(小于)子节点的值(为了方便,我们把这句称作“要求”)。
显然,Heap 的树根就是那个动态的最大值或最小值。
首先需要一个维护堆的性质的函数 heapify,它的作用是,当以节点 i 为根的堆不满足要求时,调用这个函数使其满足要求。
其实思路也好想,对于某个节点 i ,如果它的值小于子节点的值,那么就将它与两个子节点的值的较大者交换位置。
然后是建立,思路是从底向上建立。而且为了方便,我们把树建立成一棵完全二叉树的形式。
最后一层显然不需要调整,对于倒数第二层,如果需要调整,我们就调用 heapify。
这样一直循环到第一层即可。
还有是插入,插入的时候,将新加入的值加到树的底部,然后不断向上更新,这样不会影响其他子树的堆的性质。
最后是删除,删除的时候,将树底的点换到树根,然后对树根调用 heapify 函数就行了。
/*
Title : Heap
Author: nyist_xiaod
Date : 2013.3.14
*/
#include <stdio.h>
#include <algorithm>
using namespace std;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
const int N = 1e5+5;
template<typename T>
struct Heap
{
int n;
T A[N];
Heap()
{
n = 0;
}
bool empty()
{
return n == 0;
}
void heapify(int u)
{
int max_i = u;
if(L(u) <= n && A[max_i] < A[L(u)])
max_i = L(u);
if(R(u) <= n && A[max_i] < A[R(u)])
max_i = R(u);
if(max_i == u)
return ;
swap(A[max_i],A[u]);
heapify(max_i);
}
void build()
{
for(int i=n/2;i>=1;i--)
heapify(i);
}
void insert(T x)
{
A[++n] = x;
int u = n;
while(u > 1 && A[u>>1] < x)
{
A[u] = A[u>>1];
u >>= 1;
}
A[u] = x;
}
void pop()
{
A[1] = A[n--];
heapify(1);
}
T top()
{
return A[1];
}
};