堆的概念及结构
如果有一个关键码的集合K={,
,
.......
},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<=K2*i+1且Ki<=K2*i+2(Ki>=K2*i+1且Ki>=K2*i+2)i=0,1,2...,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树。
示意图:

简单来说,小堆:孩子大于父亲。大堆:父亲大于孩子。
堆的实现
我们用数组的形式来实现堆这种数据结构。这和我们之前构建栈基本上是一样的。
结构体:
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;//数组指针
int size;//有效元素个数
int capacity;//数组容量
}Heap;
堆的初始化
//堆的初始化
void HeapInit(Heap* hp)
{
assert(hp);
hp->a = NULL;
hp->capacity = 0;
hp->size = 0;
}
堆的创建
//堆的构建
//堆 数组 数组长度
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
for (int i = 0; i < n; i++)
{
HeapPush(hp, a[i]);
}
}
堆的销毁
// 堆的销毁
void HeapDestory(Heap* hp)
{
assert(hp);
free(hp->a);
hp->a = NULL;
hp->capacity = 0;
hp->size = 0;
}
堆的插入
构建堆,我们需要将数组中的元素依次插入,然后调整建堆,这里我们要用到一个算法:向上调整算法。
//交换
void Swap(HPDataType* a, int x, int y)
{
HPDataType temp = a[x];
a[x] = a[y];
a[y] = temp;
}
//向上调整
void AdjustUp(HPDataType* a, int child)
{
assert(a);
int parent = (child - 1) / 2;//找到孩子的父亲节点
while (child>0)
{
//如果孩子比父亲大就交换(调整大堆)
if (a[child] > a[parent])
{
Swap(a, child, parent);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
assert(hp);
//扩容
if (hp->capacity == hp->size)
{
int newcapacity = hp->capacity==0 ? 4 : hp->capacity * 2;
HPDataType* new_a = (HPDataType*)realloc(hp->a, newcapacity * sizeof(HPDataType));
if (new_a == NULL)
{
perror("realloc fail:");
return;
}
hp->a = new_a;
hp->capacity = newcapacity;
}
//插入
hp->a[hp->size] = x;
hp->size++;
//向上调整建堆
AdjustUp(hp->a, hp->size - 1);
}
堆的删除
对堆进行删除时,我们要先将堆顶的数据换到堆尾,然后进行删除。
这样删除后,我们只需要进行一次向下调整,就可以重新获取新的堆了。
向下调整算法:
条件:左右子树必须满足是堆。
void AdjustDown(HPDataType* a, int n,int parent)
{
assert(a);
//假设:左孩子较小(较大)
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, parent);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
// 堆的删除
void HeapPop(Heap* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
Swap(hp->a, 0, hp->size - 1);
hp->size--;
AdjustDown(hp->a,hp->size,0);
}
取堆顶的数据
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
assert(hp);
return hp->a[0];
}
堆的数据个数
// 堆的数据个数
int HeapSize(Heap* hp)
{
assert(hp);
return hp->size;
}
堆的判空
// 堆的判空
bool HeapEmpty(Heap* hp)
{
assert(hp);
return hp->size == 0;
}
文章介绍了堆的概念,包括大根堆和小根堆,以及如何使用数组来实现堆。堆的初始化、插入、删除等操作通过向上和向下调整算法保证堆的性质。堆是一种重要的数据结构,常用于优先队列等场景。
36万+

被折叠的 条评论
为什么被折叠?



