以小堆为例,大堆就举一反三了。
堆的物理结构就是普通的数组,但是逻辑结构看成了一颗完全二叉树。
小堆,就是树的每一个父节点都小于他的孩子节点。如图中第一排的a与b。大堆,就是树的每一个父节点都大于他的孩子节点。如图中第二排的a与b。我们要实现的功能就是将一个数组排成符合要求的序列。
创建小堆
cpp
typedef int HeapDataType;
typedef struct Heap//小堆
{
HeapDataType* a;
int size;
int capacity;
}HP;
堆初始化
cpp
//初始化堆
void HeapInit(HP* php)
{
assert(php);
php->a = NULL;
php->size = php->capacity = 0;
}
向堆增加数据
cpp
//Push数据
void HeapPush(HP* php, HeapDataType x)
{
assert(php);
if (php->size == php->capacity)
{
int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HeapDataType* temp = (HeapDataType*)realloc(php->a, sizeof(HeapDataType) * newcapacity);
if (temp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
php->capacity = newcapacity;
php->a = temp;
}
php->a[php->size++] = x;
HeapAdjustUp(php->a, php->size-1);
}
删除堆顶数据
每一次删除堆顶元素,都会再次形成一个新的堆,新堆的堆顶元素就是数组a中次
小的值,再次删除,再形成新堆,堆顶就变成次次小的元素了。以此类推。
cpp
//Pop数据
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
HeapAdjustDown(php->a, php->size, 0);
}
获得堆顶数据
cpp
//获得堆顶数据
HeapDataType HeapTop(HP* php)
{
assert(php);
return php->a[0];
}
获得堆的有效大小
cpp
//获得堆的有效大小
size_t HeapSize(HP* php)
{
return php->size;
}
判断堆是否为空
cpp
//判断堆是否为空
bool HeapEmpty(HP* php)
{
assert(php);
return php->size == 0 ? 1 : 0;
}
交换数据
cpp
//交换数据
void Swap(HeapDataType* p1,HeapDataType* p2)
{
HeapDataType p3 = *p1;
*p1 = *p2;
*p2 = p3;
}
向上调整数组形成堆
cpp
//向上调整数组形成堆
void HeapAdjustUp(HeapDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[parent] > a[child])
{
Swap(&a[parent], &a[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
向下调整数组形成堆
cpp
//向下调整数组形成堆
void HeapAdjustDown(int* 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[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
销毁堆
cpp
//销毁堆
void HeapDestory(HP* php)
{
assert(php);
free(php->a);
php->a = NULL;
php->size = php->capacity = 0;
}
所需头文件
cpp
#pragma once
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdbool.h"
#include "assert.h"
main函数测试
cpp
#include "Heap.h"
int main()
{
int a[] = { 4,6,2,1,5,8,2,9};
HP hp;//创建堆
HeapInit(&hp);//初始化堆
//将数组a内数据Push到堆中
for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
{
HeapPush(&hp, a[i]);
}
int k = 3;
while (k--)
{
printf("%d\n", HeapTop(&hp));
HeapPop(&hp);//每一次删除堆顶元素,都会再次形成一个新的堆,新堆的堆顶元素就是数组a中次
//小的值,再次删除,再形成新堆,堆顶就变成次次小的元素了。以此类推。
//所以打出来的会是升序的
}
while (!HeapEmpty(&hp))
{
printf("%d\n", HeapTop(&hp));
HeapPop(&hp);
}
printf("\n");
return 0;
}