目录
专栏前文中,已经介绍了入堆及向上调整算法,出堆及向下调整算法,详情见下文:
以小根堆为例:
1. Heap.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap {
HPDataType* a;
int size;
int capacity;
}HP;
void HPInit(HP* php);
void HPDestory(HP* php);
void HPPush(HP* php, HPDataType x);
void HPPop(HP* php);
void HPPrint(HP* php);
void AdjustUp(HPDataType* a, int child);
void AdjustDown(HPDataType* a, int n, int parent);
void Swap(HPDataType* px, HPDataType* py);
HPDataType HPTop(HP* php);
bool HPEmpty(HP* php);
2. Heap.c
#include"Heap.h"
void HPInit(HP* php) {
assert(php);
php->a = NULL;
php->size = php->capacity = 0;
}
void HPDestory(HP* php) {
assert(php);
free(php->a);
php->a = NULL;
php->size = php->capacity = 0;
}
void Swap(HPDataType* px, HPDataType* py) {
HPDataType tmp = *px;
*px = *py;
*py = tmp;
}
// 向上调整
void AdjustUp(HPDataType* a, int child) {
int parent = (child - 1) / 2;
while (child> 0) {
// 父结点值大于子结点值:交换并更新parent和child
if (a[parent] > a[child]) {
Swap(&a[parent], &a[child]);
child = parent;
parent = (child - 1) / 2;
}
// 父结点值小于子结点值:调整结束
else {
break;
}
}
}
// 入堆
void HPPush(HP* php, HPDataType x) {
assert(php);
// 判满,满则扩容
if (php->size == php->capacity) {
int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
if (tmp== 0) {
perror("realloc fail");
return;
}
php->a = tmp;
php->capacity = newCapacity;
}
// 将新元素插入到数组尾
php->a[php->size] = x;
php->size++;
// 向上调整保证小根堆特性
AdjustUp(php->a, php->size - 1);
}
// 向下调整
void AdjustDown(HPDataType*a, int n, int parent) {
// 假设法:假设左孩子更小
int child = parent * 2 + 1;
// child=n表示已经遍历到最后的叶结点
while (child < n) {
// 确定左右孩子中更小的
if (child+1<n && a[child] > a[child + 1]) {
child++;
}
// 若子结点小于父结点,则交换并更新parent和child
if (a[child] < a[parent]) {
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
// 出堆
void HPPop(HP* php) {
assert(php);
assert(php->size>0);
// 交换堆顶结点值和最末结点值
Swap(&php->a[0], &php->a[php->size - 1]);
// 删除最后一个结点
php->size--;
AdjustDown(php->a, php->size,0);
}
void HPPrint(HP* php) {
for (int i = 0; i < php->size; i++) {
printf("%d ", php->a[i]);
}
printf("\n");
}
HPDataType HPTop(HP* php) {
assert(php);
assert(php->size > 0);
return php->a[0];
}
bool HPEmpty(HP* php) {
assert(php);
return php->size == 0;
}
3. Test_Heap.c
使用HPPush方法构建小根堆:
#include"Heap.h"
void TestHeap1() {
int a[] = { 4,2,8,1,5,6,9,7 };
HP hp;
HPInit(&hp);
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
HPPush(&hp, a[i]);
}
HPPrint(&hp);
HPDestory(&hp);
}
int main() {
TestHeap1();
return 0;
}
运行结果如下:
注:大根堆与小根堆的转换: