首先堆是一棵完全二叉树,其次堆分大顶堆和小顶堆。
大顶堆的堆顶,也就是根节点,其值大于左孩子的值且大于右孩子的值,左右孩子的大小不做区分,其子树满足这一性质。
小顶堆的堆顶,也就是根节点,其值小于左孩子的值且小于右孩子的值,左右孩子的大小不做区分,其子树满足这一性质。
然后我们来看看如果创建一个堆:在创建堆的时候,我们要给堆所需的元素,否则创建的堆为空堆,空堆的实际意义不大,所以此处讨论的是创建有元素的堆,此堆的底层空间为一个数组,满足parent = parent * 2 + 1
为子节点的性质。
堆的核心思想在于调整,正因为向上(向下)调整,使得堆在排序上的时间复杂度可以达到O(log2N),是一种相当高效的排序算法。
void Swap(int* parent, int* child)
{
int tmp = *parent;
*parent = *child;
*child = tmp;
}
void _Adjustup(Heap* hp, int child)
{
int parent = (child - 1) >> 1;
while (child)
{
if ((child + 1) < hp->_size && hp->comp(hp->_data[child + 1] , hp->_data[child]))
++child;
if (hp->comp(hp->_data[child], hp->_data[parent]))
{
Swap(&hp->_data[parent], &hp->_data[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
break;
}
}
void _Adjustdown(Heap* hp, int parent)
{
assert(hp);
int child = (parent << 1) + 1;
while (child < hp->_size)
{
if (child + 1 < hp->_size && hp->comp(hp->_data[child + 1], hp->_data[child]))
{
++child;
}
if (hp->comp(hp->_data[child], hp->_data[parent]))
{
Swap(&hp->_data[parent], &hp->_data[child]);
parent = child;
child = (parent << 1) + 1;
}
else
{
break;
}
}
}
//创建堆
void CreteHeap(Heap* hp, int arr[], int size)
{
assert(hp);
int i = 0;
int child = 0;
int parent = 0;
hp->_data = (DataType*)malloc(sizeof(DataType)* size);
if (NULL == hp->_data)
{
assert(0);
return;
}
hp->_capacity = size;
hp->_size = size;
for (; i < size; ++i)
{
hp->_data[i] = arr[i];
}
parent = size - 1;
for (; parent >= 0; --parent)
{
_Adjustdown(hp, parent);
}
}
下面给出了堆的基本操作以及堆的几个简单的应用案例:
void InsertHeap(Heap* hp, DataType data)
{
int parent = 0;
assert(hp);
if (hp->_size == hp->_capacity)
{
DataType* NewBase = (DataType*)realloc(hp->_data, hp->_capacity * 2 * sizeof(DataType));
if (NULL == NewBase)
{
assert(0);
return;
}
hp->_data = NewBase;
hp->_capacity = hp->_capacity * 2;
}
hp->_data[hp->_size] = data;
++hp->_size;
for (; parent < hp->_size; ++parent)
{
_Adjustup(hp, parent);
}
}
//返回堆顶元素
DataType HeapTop(Heap* hp)
{
assert(hp);
return hp->_data[0];
}
// 检测一个堆是否为空堆
int EmptyHeap(Heap* hp)
{
assert(hp);
if (0 == hp->_size)
return 1;
return 0;
}
// 获取堆中元素的个数
int SizeHeap(Heap* hp)
{
assert(hp);
return hp->_size;
}
// 删除堆顶元素
void DeleteHeap(Heap* hp)
{
assert(hp);
int parent;
Swap(&hp->_data[0], &hp->_data[hp->_size - 1]);
--hp->_size;
parent = hp->_size - 1;
for (; parent >= 0; --parent)
{
_Adjustdown(hp, parent);
}
}
// 销毁堆
void DestroyHeap(Heap* hp)
{
assert(hp);
free(hp->_data);
hp->_data = NULL;
hp->_size = 0;
hp->_capacity = 0;
}
//堆排序
void HeapSort(Heap* hp)
{
assert(hp);
while (!EmptyHeap(hp))
{
printf("%d ", HeapTop(hp));
DeleteHeap(hp);
}
}
void TopK(Heap* hp,int k)
{
assert(hp);
if (SizeHeap(hp) > k)
{
while (k--)
{
printf("%d ", HeapTop(hp));
DeleteHeap(hp);
}
}
else
{
k = SizeHeap(hp);
while (k--)
{
printf("%d ", HeapTop(hp));
DeleteHeap(hp);
}
}
}