一、堆的定义与结构
本篇内容与树和二叉树的知识相关,如果还不了解什么是树,什么是二叉树,建议先复习基础知识。
堆的本质是一颗完全二叉树,只是它的要求比完全二叉树更加严格,它要求每颗子树的根节点都是当前子树的最大值或最小值。当根节点是最大值时,它就是一个大根堆;当根节点是最小值时,它就是一个小根堆。
在上篇文章中我们也提到了,存储完全二叉树可以使用数组,存储非完全二叉树可以使用链表。而堆就是一种特殊的完全二叉树,所以堆的存储我们就使用数组,也就是顺序表的形式。

我们将堆这个完全二叉树从上至下,从左至右的数据存放在数组中。至于怎么保证它每颗子树的根节点都是当前子树的最大值或最小值,我们在入堆和出堆的位置细讲。而顺序表的结构我们已经很熟悉了,这里直接写出来:
typedef int HPDataType;
typedef struct Heap {
HPDataType* arr;
int size;
int capacity;
} HP;
二、堆的实现
1. 堆的初始化和销毁
堆的初始化和销毁与顺序表的初始化和销毁一致,这里我们只简单提一下。
堆的初始化
堆的初始化就是将数组置空,有效数据个数和容量大小置 0,如下:
// 堆的初始化
void HPInit(HP* php) {
assert(php);
php->arr = NULL;
php->size = php->capacity = 0;
}
堆的销毁
堆的销毁就是先判断数组是否为空,不为空就将它释放掉。因为数组的空间是我们向操作系统申请来的,不会主动释放,如果我们不主动释放就会造成内存泄漏。最后我们将数组置空,有效数据个数和容量大小置 0,如下:
// 堆的销毁
void HPDestroy(HP* php) {
assert(php);
if (php->arr) free(php->arr);
php->arr = NULL;
php->size = php->capacity = 0;
}
2. 向上调整算法和入堆
接下来就是入堆操作,也就是向堆中插入数据。但是我们要知道,一般往数组中插入数据都是向数组尾部插入,那么是不是就会出现,原本堆的每颗子树的根节点都是当前子树的最大值或最小值,但是从尾部插入数据后会打破这个平衡。









