堆的数据结构是一种数组,也可以说堆是一种有个性的数组,他可以被视为一颗完全二叉树(也有可能是满二叉树)
最大堆:
任一节点的值均大于等于他左右孩子节点的值,其中堆顶的值最大(根节点)已知父节点
左孩子节点=2*父节点+1 右孩子节点=2*父节点+2 父节点=(孩子节点-1)/2堆的应用场景:
从很多个数中找出最大的前k个数
最大堆的算法实现:
#include<iostream>
#include<stdio.h>
#include<string.h>
#define DEFAULT_CAPCITY 128
typedef struct _Heap {
int *arr; //存储堆元素的数据
int size; //当前已存储的元素数据
int capacity; //当前存储的容量
}Heap;
//初始堆
bool initHeap(Heap &heap, int *orginal, int size);
//建堆
static void buildHeap(Heap &heap);
//调整堆
static void adjustDown(Heap &heap, int index);
int main(void) {
Heap hp;
int origVals[] = { 1,2,3,87,93,82,92,86,95 };
int size = sizeof(origVals) / sizeof(int);
if (!initHeap(hp, origVals, size)) {
fprintf(stderr, "初始化堆失败!\n");
exit(-1);
}
int i = 0;
for (i = 0; i < hp.size; i++) {
printf("the %dth element:%d\n", i, hp.arr[i]);
}
system("pause");
return 0;
}
bool initHeap(Heap & heap, int * orginal, int size)
{
int capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;
heap.arr = new int[capacity];
if (!heap.arr)return false;
heap.size = 0;
//如果存在原始数据则建堆
if (size > 0) {
memcpy(heap.arr, orginal, size * sizeof(int));
heap.size = size;
buildHeap(heap);
}
return true;
}
void buildHeap(Heap & heap)
{
int i = 0;
for (i = heap.size / 2 - 1; i >= 0; i--) {
adjustDown(heap, i);
}
}
//将当前叶子节点调整为最大堆
void adjustDown(Heap & heap, int index)
{
int cur = heap.arr[index];//当前待调节点
int parent, child;
/*
判断是否存在大于当前节点的叶子节点,如果不存在,则堆本身是平衡的,
不需要调整;如果存在,则将最大子节点与之交换,交换后,
如果这个子节点还有子节点,则需要按照同样的步骤对这个
子节点进行调整
*/
for (parent = index; parent * 2 + 1 < heap.size;parent=child) {
child = parent * 2 + 1;
//取两个叶子节点中最大的子节点
if (child + 1 < heap.size&&heap.arr[child] < heap.arr[child + 1]) {
child++;//判断右叶子节点是否存在并且左右叶子节点的大小关系
}
//判断最大的节点是否大于当前节点,若大于则交换他们
if (cur > heap.arr[child]) {//不大于,不需要调整,跳出循环
break;
}
else {//大于,则交换他们,然后从叶子节点位置继续向下调整
heap.arr[parent] = heap.arr[child];
heap.arr[child] = cur;
}
}
}
运行结果:
将以上得出的数据按照二叉树方式排好得到的完全二叉树即满足最大堆的所有性质