文章目录
1. 堆的概念
1.1 定义
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<=K2i+2 ,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
1.2 特性
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树。
- 堆一般被看成一个完全二叉树
1.3 堆的种类
堆按照特性1可以区分为大堆(大根堆)或者小堆(小根堆) 大堆就是每个子树的根节点都要比子节点大的树
1.4 常用场景
2.堆函数 源码实现
1. HeapInit
初始化堆
void HeapInit(HP* hp)
{
assert(hp);
hp->a = NULL;
hp->size = hp->capacity = 0;
}
2. HeapDestroy
销毁堆 ,返回堆所占用的空间
void HeapDestroy(HP* hp)
{
assert(hp);
free(hp->a);
hp->capacity = hp->size = 0;
}
3. HeapPush
在数组尾部插入数据 ,并且交换根节点与尾部的数据 然后调整堆的数据(根据大/小堆选择向上/向下调整) 使堆保持原来的性质
void HeapPush(HP* hp, HPDataType x)
{
assert(hp);
if (hp->size == hp->capacity)
{
size_t newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
HPDataType* tmp = realloc(hp->a, sizeof(HPDataType)*newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
hp->a = tmp;
hp->capacity = newCapacity;
}
hp->a[hp->size] = x;
hp->size++;
AdjustUp(hp->a, hp->size - 1);
}
4. HeapPop
删除根节点,并且调整堆的数据(根据大/小堆选择向上/向下调整) 使堆保持原来的性质
void HeapPop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
swap(&hp->a[0], &hp->a[hp->size - 1]);
hp->size--;
AdjustDown(hp->a, hp->size, 0);
}
5. HeapEmpty
检查堆是否为空
bool HeapEmpty(HP* hp)
{
assert(hp);
return hp->size == 0;
}
6.AdjustUp
向上调整,将插入的数据从最底部向上调整 ,维持堆的性质不变
void AdjustUp(int* a, int child)
{
assert(a);
int parent = (child - 1) >>1;
//while (parent >= 0)
while (child > 0)
{
if (a[child] > a[parent])
{
swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else break;
}
}
7. AdjustDown
向下调整,将插入的数据从根节点向下调整 , 维持堆的性质不变
void AdjustDown(int* a, int n, int parent)//删除堆顶的数据 删除根节点 筛选最值
{
int child = parent * 2 + 1;//只用左孩子 右孩子的下标 是左孩子 + 1
while (child < n)
{
//选出较小的那个孩子 判断右孩子是否越界
if (a[child + 1] < a[child] && child + 1 < n) child++;
//如果小的孩子小于父亲 就继续调整
if (a[child] < a[parent])
{
swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else break;//如果不符合条件就 break
}
}
8. HeapSize
返回堆的节点数
int HeapSize(HP* hp)
{
assert(hp);
return hp->size;
}
9. HeapTop
返回根节点顶元素大小
HPDataType HeapTop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
return hp->a[0];
}
10. HeapPrint
打印堆(线性 数组)
void HeapPrint(HP* hp)
{
for (int i = 0; i < hp->size; ++i)
{
printf("%d ", hp->a[i]);
}
printf("\n");
}
实现细节
- 根据
AdjustUp / AdjustDown
中的> /<
来判断是 大根堆/小跟堆 调整
例如:
2.AdjustUp
while循环的判断条件一般是 child > 0
3. AdjustDown
中while 循环的条件 一般是
child < n