/* *
* 堆的特性
*
* 1. 堆是一颗二叉树
* 2. 堆的每个节点都比它的子节点要大
*
* 堆的常见应用
*
* 1. 堆排序
* 2. 优先队列
*
* */
/* *
* 下面是一个堆的普通实现
* */
class Heap {
/* *
* 这里用数组来表示一个堆,
* +-+-+-+-+-+-+-+
* |0|1|2|3|4|5|6|
* +-+-+-+-+-+-+-+
* */
int *data;
int maxSize;
int size;
public:
Heap();
Heap(int n);
~Heap();
/* *
* 从数组中自底向上用下沉操作构建堆
* */
static Heap* Build(int *array, int n);
/* *
* 数组尾部插入一个元素, size加1, 然后沿着根节点路径上浮
* */
void Push(int val);
/* *
* 交换数组末尾的节点和根节点, size减1, 对新的根节点执行下沉操作
* */
void Pop();
/* *
* 节点i沿着到达根节点的路径一直冒泡(比较并交换), 直到到达根节点或者
* 遇到比它大的节点时结束
* */
void ToUp(int i);
/* *
* 节点i沿着较大的子节点向下沉,
* 直到叶子节点或者两个子节点都比他小时结束
* */
void ToDown(int i);
/* *
* 获得堆顶元素
* */
int &Top();
/* *
* 判断堆是否为空
* */
bool Empty();
private:
/* *
* 节点i的左节点在数组中的下标是2*i + 1
*/
int Left(int i);
/* *
* 节点i的左节点在数组中的下标是2*i + 2
* */
int Right(int i);
/* *
* 节点i的父节点在数组中的下标是(i - 1) / 2
* */
int Parent(int i);
/* *
* 二叉树中非叶子节点的个数是size / 2
* */
int NotLeaf();
/* *
* 交换数组中下标为i和j的节点内容
* */
void Swap(int i, int j);
/* *
* 比较数组中下标为i和j的节点内容的大小
* */
bool Compare(int i, int j);
};
int Heap::Left(int i) {
return (i << 1) + 1;
}
int Heap::Right(int i) {
return (i << 1) + 2;
}
int Heap::Parent(int i) {
return i - 1 >> 1;
}
void Heap::Swap(int i, int j) {
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
bool Heap::Compare(int i, int j) {
return data[i] >= data[j];
}
int Heap::NotLeaf() {
return size >> 1;
}
void Heap::ToUp(int i) {
while(i && Compare(i, Parent(i))) {
Swap(i, Parent(i));
i = Parent(i);
}
}
void Heap::ToDown(int i) {
while(i < NotLeaf()) {
if(Right(i) >= size || Compare(Left(i), Right(i))) {
if(!Compare(Left(i), i))
break;
Swap(Left(i), i);
i = Left(i);
continue;
}
if(!Compare(Right(i), i))
break;
Swap(Right(i), i);
i = Right(i);
}
}
Heap* Heap::Build(int *array, int n) {
Heap *heap = new Heap();
heap -> data = new int[n + 1];
heap -> maxSize = n;
heap -> size = n;
for(int i=0;i<n;++i)
heap -> data[i] = array[i];
for(int i=heap->NotLeaf()-1;i>=0;--i)
heap->ToDown(i);
return heap;
}
Heap::Heap() : data(0), size(0), maxSize(0) {}
Heap::Heap(int n) : data(new int[n + 1]), size(0), maxSize(n) {}
Heap::~Heap() {
delete []data;
}
void Heap::Push(int val) {
data[size++] = val;
ToUp(size - 1);
}
void Heap::Pop() {
Swap(0, --size);
ToDown(0);
}
int &Heap::Top() {
return data[0];
}
bool Heap::Empty() {
return 0 == size;
}
void HeapSort(int a[], int n) {
Heap *heap = Heap::Build(a, n);
while(!heap -> Empty()) {
a[--n] = heap -> Top();
heap -> Pop();
}
delete heap;
}
void TopK(int src[], int n, int dst[], int k) {
Heap *heap = Heap::Build(src, k);
for(int i=k;i<n;++i)
if(src[i] <= heap -> Top()) {
heap -> Top() = src[i];
heap -> ToDown(0);
}
while(!heap -> Empty()) {
dst[--k] = heap -> Top();
heap -> Pop();
}
delete heap;
}
#include "stdio.h"
int main() {
int a[] = {3, 1, 2, 4 ,5, 7, 5, 2, 9, 3};
int n = sizeof(a) / sizeof(int);
int b[5];
TopK(a, n, b, 5);
for(int i=0;i<5;++i)
printf("%d ", b[i]);
printf("\n");
HeapSort(a, n);
for(int i=0;i<n;++i)
printf("%d ", a[i]);
printf("\n");
return 0;
}