作者简介:大家好,我是菀枯
支持我:点赞+收藏⭐️+留言
格言:不要在低谷沉沦自己,不要在高峰上放弃努力!☀️
上一次我们学习了一些树的基础概念,树的性质等。今天我们试着用C语言来实现一种数据结构:堆
n个元素的序列 k 1 , k 2 . . . , k n {k_1,k_2..., k_n} k1,k2...,kn当且仅当满足下关系时,称之为堆。
( k i ≤ k 2 i 且 k i ≤ k 2 i + 1 ) 或 者 ( k i ≥ k 2 i 且 k i > k 2 i + 1 ) , i = [ 1 , 2 n ] (k_i\leq k_{2i} 且 k_i \leq k_{2i + 1}) 或者(k_i \geq k_{2i} 且 k_i > k_{2i+1}),i=[1,\frac{2}{n}] (ki≤k2i且ki≤k2i+1)或者(ki≥k2i且ki>k2i+1),i=[1,n2]
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右子结点的值。由此,若序列 k 1 , k 2 . . . k n {k_1, k_2...k_n} k1,k2...kn是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值).
根据堆中根元素的大小我们可将堆分为两类
#include
#include
#include
#include
typedef int HeapDType; (1)
typedef struct Heap (2)
{
HeapDType* val;
int count;
int capacity;
}Heap;
void HeapInti(Heap* pheap);
// 堆的初始化
void HeapDestory(Heap* pheap);
// 堆的销毁
void HeapPop(Heap* pheap);
// 删除根的元素
void HeapPush(Heap* pheap, HeapDType x);
// 将x的加入进堆中
bool HeapEmpty(Heap* pheap);
// 判断堆是否为空
void HeapPrint(Heap* pheap);
// 显示堆中元素
HeapDType HeapTop(Heap* pheap);
// 取根元素
int HeapSize(Heap* pheap);
// 堆的大小
void HeapInti(Heap* pheap)
{
assert(pheap); //(1)
pheap->val = NULL; (2)
pheap->capacity = pheap->count = 0;
}
void HeapDestory(Heap* pheap)
{
assert(pheap);
free(pheap->val); //(1)
pheap->val = NULL; //(2)
pheap->capacity = pheap->count = 0;
}
与之前顺序表的添加,链表的添加不同,堆的添加会需要改变堆的结构。我们先来看一个动画,看看堆插入元素的思路:
代码实现:
void HeapPush(Heap* pheap, HeapDType x)
{
assert(pheap);
if (pheap->count == pheap->capacity) //(1)
{
int newCapacity = pheap->capacity == 0 ? 4 : pheap->capacity * 2;
HeapDType* tmp = (HeapDType*)realloc(pheap->val, sizeof(HeapDType) * newCapacity);
if (NULL == tmp) //(2)
{
printf("realloc error\n");
exit(-1);
}
pheap->capacity = newCapacity;
pheap->val = tmp;
}
pheap->val[pheap->count++] = x; //(3)
AdjustTop(pheap->val, pheap->count - 1);
}
void AdjustTop(HeapDType* val, int child)
{
int parent = (child - 1) / 2; //(1)
while (child > 0)
{
if (val[child] < val[parent]) //(2)
{
Swap(&(val[child]), &(val[parent]));
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void Swap(HeapDType* px, HeapDType* py) //(3)
{
HeapDType tmp = *px;
*px = *py;
*py = tmp;
}
堆的删除,我们无法用以前顺序表的那种方式直接用后面的数据覆盖前面的数据,原因如下:
所以我们需要一种新的方法,来删除根处元素,大家可以仔细思考一下,用什么样的方法比较好。
思路如下(看动图):
void HeapPop(Heap* pheap)
{
assert(pheap);
if (!HeapEmpty(pheap)) //(1)
{
Swap(&(pheap->val[0]), &(pheap->val[pheap->count - 1])); //(2)
pheap->count--;
AdjustDown(pheap->val, pheap->count, 0); //(3)
}
}
void AdjustDown(HeapDType* val, int size, int parent)
{
int child = 2 * parent + 1; //(1)
while (child < size)
{
if (val[child] > val[child + 1]) //(2)
{
child++;
}
if (val[parent] > val[child] && child <size) //(3)
{
Swap(&val[parent], &val[child]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
bool HeapEmpty(Heap* pheap)
{
assert(pheap);
return pheap->count == 0;
}
判断堆中元素是否为空即可
int HeapSize(Heap* pheap)
{
assert(pheap);
return pheap->count;
}
返回堆中元素个数
HeapDType HeapTop(Heap* pheap)
{
assert(pheap);
assert(pheap->count > 0); //(1)
return pheap->val[0];
}
void HeapPrint(Heap* pheap)
{
assert(pheap);
for (int i = 0; i < pheap->count; i++)
{
printf("%d ", pheap->val[i]);
}
}
遍历堆中元素,打印即可。
#include
#include
#include
#include
typedef int HeapDType;
typedef struct Heap
{
HeapDType* val;
int count;
int capacity;
}Heap;
void HeapInti(Heap* pheap)
{
assert(pheap);
pheap->val = NULL;
pheap->capacity = pheap->count = 0;
}
bool HeapEmpty(Heap* pheap)
{
assert(pheap);
return pheap->count == 0;
}
void HeapDestory(Heap* pheap)
{
assert(pheap);
free(pheap->val);
pheap->val = NULL;
pheap->capacity = pheap->count = 0;
}
void Swap(HeapDType* px, HeapDType* py)
{
HeapDType tmp = *px;
*px = *py;
*py = tmp;
}
void AdjustTop(HeapDType* val, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (val[child] < val[parent])
{
Swap(&(val[child]), &(val[parent]));
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(Heap* pheap, HeapDType x)
{
assert(pheap);
if (pheap->count == pheap->capacity)
{
int newCapacity = pheap->capacity == 0 ? 4 : pheap->capacity * 2;
HeapDType* tmp = (HeapDType*)realloc(pheap->val, sizeof(HeapDType) * newCapacity);
if (NULL == tmp)
{
printf("realloc error\n");
exit(-1);
}
pheap->capacity = newCapacity;
pheap->val = tmp;
}
pheap->val[pheap->count++] = x;
AdjustTop(pheap->val, pheap->count - 1);
}
void HeapPrint(Heap* pheap)
{
assert(pheap);
for (int i = 0; i < pheap->count; i++)
{
printf("%d ", pheap->val[i]);
}
}
void AdjustDown(HeapDType* val, int size, int parent)
{
int child = 2 * parent + 1;
while (child < size)
{
if (child + 1 < size && val[child] > val[child + 1])
{
child++;
}
if (val[parent] > val[child] && child <size)
{
Swap(&val[parent], &val[child]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
void HeapPop(Heap* pheap)
{
assert(pheap);
if (!HeapEmpty(pheap))
{
Swap(&(pheap->val[0]), &(pheap->val[pheap->count - 1]));
pheap->count--;
AdjustDown(pheap->val, pheap->count, 0);
}
}
HeapDType HeapTop(Heap* pheap)
{
assert(pheap);
assert(pheap->count > 0);
return pheap->val[0];
}
int HeapSize(Heap* pheap)
{
assert(pheap);
return pheap->count;
}
欢迎各位参考与指导!!!博主最近在冲击C/C++领域新人,拜托大家帮忙点赞收藏一下❤️