堆排序
用堆封装优先级队列
海量数据TopK问题
堆的完整源代码
什么是堆
首先,堆是完全二叉树。
小堆: 任何一个节点的值都小于它的左右孩子的值,位于堆顶节结点的值是最小的,从根结点到每个结点的路径上数组元素组成的序列是递增的。
大堆:任何一个节点的值都大于它的左右孩子的值,位于堆顶节结点的值是最大的,从根结点到每个结点的路径上数组元素组成的序列是递减的。
堆的基本操作简单解析
建堆
- 先申请一块空间,然后在对其赋值形成二叉树,在对二叉树调整使之形成小堆
- 这里要注意,每次向下调整只是对一个元素调整,因此需要一个for循环。
//创建堆
void CreateHeap(Heap *hp, DataType *array, int size)
{
assert(hp);
//申请空间
hp->_array = (DataType *)malloc(sizeof(DataType)*size);
if (NULL == hp)
assert(0);
hp->_size = 0;
hp->_capacity = size;
//赋值
for (int i = 0; i < size; ++i)
{
hp->_array[i] = array[i];
hp->_size += 1;
}
hp->_capacity = size;
//找出最后一个非叶子节点
int root = (size - 1 - 1) >> 1;
//调整元素
for (; root >= 0; root--)
AdjustDown(hp,root);
}
向下调整算法(小堆为例)
- 设该结点的下标为parent
- 找到该结点的左孩子(child = (parent<<1)+1;)
- 如果右孩子存在,则找出左右孩子中最小的孩子(建立大堆,则找出最大的孩子)
- 比较parent和child的大小,如果parent小于child,则调整结束,否则,交换parent的child的值,此时如果其子树还不满足,则继续调整,直至子树也满足堆的性质
void AdjustDown(Heap *hp, DataType parent)
{
int child = (parent<<1)+1;
if (NULL == hp)
return;
while (child < hp->_size)
{
//找到孩子中较小的一个
if ((child+1) < hp->_size &&
hp->cmp(hp->_array[child+1], hp->_array[child]))
{
child += 1;
}
//如果双亲大于孩子,则交换
if (hp->cmp(hp->_array[child], hp->_array[parent]))
{
Swop(&hp->_array[parent], &hp->_array[child]);
parent = child;
child = (parent << 1) + 1;
}
else
{
break;
}
}
}
插入元素
- 如果堆为空,返回
- 检测容量,看是否还有空间,没有则扩容
- 将元素添加到二叉堆的最后
- 然后调整堆
void InsertHeap(Heap *hp, DataType data)
{
if (NULL == hp)
return;
CheckCatacity(hp);
hp->_array[hp->_size] = data;
hp->_size++;
if (hp->_size > 1)
AdjustUp(hp, hp->_size - 1);
}
向上调整算法(插入元素)
在插入之前堆已经使最小堆了,因此插入元素之后,需要重新对堆进行调整。
- 比较新插入的元素和parent的值的大小,如果大于,则返回,如果小于,则需要交换parent和child的值,然后继续比较,调整后的parent和他的parent的大小,直至满足小堆的性质
void AdjustUp(Heap *hp, int child)
{
int parent = (child - 1) >> 1;
while (child)
{
if (hp->cmp(hp->_array[child] , hp->_array[parent]))
{
Swop(&hp->_array[parent], &hp->_array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
break;
}
}
删除元素
- 将堆中最后一个元素和堆顶元素交换
- 将堆的元素个数减少一个,相当于删除堆中最后一个元素
- 然后利用向下调整,使其满足最小堆的性质
void DeleteHeap(Heap *hp)
{
assert(hp);
if (NULL == hp)
return;
if (EmptyHeap(hp))
return;
Swop(&hp->_array[0], &hp->_array[hp->_size-1]);
hp->_size--;
AdjustDown(hp, 0);
}