一. 堆的接口函数(续)
虽然我们的上一篇博客已经写过了堆的前面一些接口函数
这里我们再重复一遍
1. 结构体形式
我们这里形式上使用一个数组来表示一个逻辑上的二叉树
typedef int HPDateType;
typedef struct Heap
{
HPDateType* a;
int size;
int capacity;
}HP;
2. 初始化和销毁
这里的两个接口函数都很简单 我们直接连起来动手实现一下
初始化
void HeapInit(HP* php)
{
assert(php);
php->a = (HPDateType*)malloc(sizeof(HPDateType) * 4);
if (php->a == NULL)
{
perror("malloc fail");
return;
}
php->size =0;
php->capacity = 4;
}
销毁
void HeapDestroy(HP* php)
{
assert(php);
free(php->a);
php = NULL;
php->size = 0;
php->capacity = 0;
}
3. 添加数据(小堆为例)
当我们这里插入一个10的时候 这里明显是错误的啊 怎么办呢?
这个时候我们就需要将它跟它的父亲比较 是否小于它的父亲
如果不小于就填入
如果大于就交换它和它的父亲
知道孩子等于0为止
下面开始写代码
void HeapPush(HP* php, HPDateType x)
{
assert(php);
if (php->size == php->capacity)
{
HPDateType* tmp = (HPDateType*)realloc(php->a,sizeof(HPDateType) * php->capacity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
php->a = tmp;
php->capacity *= 2;
}
php->a[php->size] = x;
php->size++;
AdJustUp(php->a, php->size - 1);
}
这里因为判断是否需要调整这个函数要使用很多次
所以说我们单独写出一个函数出来
void Swap(HPDateType* p1, HPDateType* p2)
{
HPDateType x = *p1;
*p1 = *p2;
*p2 = x;
}
//除child这个位置,前面数据构成堆
//向上调整
void AdJustUp(HPDateType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] < a[parent])
{
Swap(&a[child], &a[parent]);
child = parent;
//更新父亲的位置
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
整体代码如下
void Swap(HPDateType* p1, HPDateType* p2)
{
HPDateType x = *p1;
*p1 = *p2;
*p2 = x;
}
//除child这个位置,前面数据构成堆
//向上调整
void AdJustUp(HPDateType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] < a[parent])
{
Swap(&a[child], &a[parent]);
child = parent;
//更新父亲的位置
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(HP* php, HPDateType x)
{
assert(php);
if (php->size == php->capacity)
{
HPDateType* tmp = (HPDateType*)realloc(php->a,sizeof(HPDateType) * php->capacity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
php->a = tmp;
php->capacity *= 2;
}
php->a[php->size] = x;
php->size++;
AdJustUp(php->a, php->size - 1);
}
4. 删除数据
我们想要删除堆中的一个数据 还要不改变这个堆的结构 这个时候怎么办呢
这个时候我们这里给出一种很巧妙的解法
我们先将最前面的元素和最后面的元素交换位置
然后再删除掉堆最后面的元素
之后开始向下调整这个堆
如上图所示
下面是删除数据的大体逻辑
void HeapPop(HP* php)
{
assert(php);
assert(!HeapEmpty(&php));
//删除数据
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
这里我们还需要再写一个函数向下调整
void AdJustDown(HPDateType* a, int n, int parent)
{
int child = parent * 2 + 1;
while(child < n)
{
//选出左右孩子中大的那一个
//需要先判断右孩子是否存在防止出现越界问题
if (child + 1<n && a[child + 1] > a[child])
{
child++;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
//更新孩子的位置
child = parent * 2 + 1;
}
else
{
break;
}
}
}
调整函数如上
我们再来整体看看这个函数
void AdJustDown(HPDateType* a, int n, int parent)
{
int child = parent * 2 + 1;
while(child < n)
{
//选出左右孩子中大的那一个
//需要先判断右孩子是否存在防止出现越界问题
if (child + 1<n && a[child + 1] > a[child])
{
child++;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
//更新孩子的位置
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapPop(HP* php)
{
assert(php);
assert(!HeapEmpty(&php));
//删除数据
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
AdJustDown(php->a, php->size, 0);
}
测试一下试试
5. 返回大小
这个很简单 返回size大小
int HeapSize(HP* php)
{
assert(php);
return php->size;
}
7. 判断为空
bool HeapEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
8.返回堆顶数据
HPDateType HeapTop(HP* php)
{
assert(php);
return php->a[0];
}
以上便是本文所有内容了,如有错误请各位大佬不吝赐教,感谢留言