堆的概念与结构
堆的底层逻辑是一个完全二叉树(或满二叉树)。
堆的分类
大根堆和小根堆
大根堆
所谓大根堆就是每一个父节点都要大于等于子结点
小根堆
所谓小根堆就是每一个父节点都要小于等于子结点
堆的实现
实现接口
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 AdjustUp(HPDataType* a, int child);
//向下调整
void AdjustDown(HPDataType* a, int size, int parent);
//往堆里插入数据
void HpPush(Hp* php,HPDataType x);
//删除数据
void HpPop(Hp* php);
//获取堆首元素
HPDataType HpTop(Hp* php);
//堆中元素个数
int Hpsize(Hp* php);
//判空
bool HpEmpty(Hp* php);
//销毁堆
void HpDestory(Hp* php);
实现函数
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
//大堆小堆只需要改变调整关系即可
#include"Heap.h"
//初始化堆
void HpInit(Hp* php) {
assert(php);
php->a = NULL;
php->capacity = 0;
php->size = 0;
}
//交换孩子和父亲的位置
void Swap(HPDataType* child,HPDataType* parents) {
HPDataType tem = *child;
*child = *parents;
*parents = tem;
}
//向上调整
void AdjustUp(HPDataType* a, int child) {
int parents = (child - 1) / 2;
while (child > 0) {
if (a[child] > a[parents]) {
Swap(&a[child], &a[parents]);
child = parents;
parents = (child - 1) / 2;
}
else {
break;
}
}
}
//向下调整
void AdjustDown(HPDataType* a,int size, int parent) {
int child = parent * 2 + 1;
while(child<size){
if (child+1<size && a[child + 1] > a[child]) {
child++;
}
if (a[parent] < a[child]) {
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
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* tem = (HPDataType*)realloc(php->a,sizeof(HPDataType) * Newcapacity);
if (tem == NULL) {
perror("realoc");
exit(-1);
}
php->capacity = Newcapacity;
php->a = tem;
}
php->a[php->size] = x;
php->size++;
//在此之前已经数据插入到数组中
//然后在比较大小
AdjustUp(php->a, php->size - 1);
}
//删除数据 默认删除堆顶数据
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);
}
//获取堆首元素
HPDataType HpTop(Hp* php) {
assert(php);
assert(php->size > 0);
return php->a[0];
}
//堆中元素个数
int Hpsize(Hp* php) {
assert(php);
assert(php->size > 0);
return php->size;
}
//判空
bool HpEmpty(Hp* php) {
assert(php);
return php->size == 0;
}
//销毁堆
void HpDestory(Hp* php) {
assert(php);
free(php->a);
php->a = NULL;
php->capacity = php->size= 0;
}
测试函数
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void test01() {
Hp hp;
HpInit(&hp);
int a[] = { 2,4,6,7,1,23,434,5,9,20,1,2,4,3 };
for (int i = 0; i < sizeof(a) / sizeof(int); i++) {
HpPush(&hp, a[i]);
}
int k = 0;
while (!HpEmpty(&hp)) {
//printf("%d ", HpTop(&hp));
//把取到的数据全部放入a数组中
a[k++] = HpTop(&hp);
HpPop(&hp);
}
for (int i = 0; i < sizeof(a) / sizeof(int); i++) {
printf("%d ", a[i]);
}
HpDestory(&hp);
}
int main() {
test01();
return 0;
}