完整代码:https://github.com/zzaiyuyu/Heap
堆创建
首先建立一个无序完全二叉树序列,然后自底向上调整每一个非叶结点。调整规则是将调整结点值变为比左右孩子结点都小(小根堆),若不满足,循环调整到树下层,称为向下调整。
为什么从最后的非叶结点向前调整?因为每次调整起码要保证当前结点比左右子树结点都小,而如果从跟结点开始调整只能保证跟结点比左右孩子值小。
void Adjust(Heap *heap, int parent)
{
assert(heap);
int child = parent * 2 + 1;
while (child < heap->size) {
int right = child +1;
//得到左右孩子较小的
if (right < heap->size) {
if (heap->compare(heap->array[right] , heap->array[child])) {
child = right;
}
}
//与父交换,或者调整完毕
if (heap->compare(heap->array[child], heap->array[parent] )) {
swap(&heap->array[parent], &heap->array[child]);
parent = child;
child = child * 2 + 1;
}
else {
return;
}
}
}
插入元素
将待插元素放到堆尾,逐步与父节点比较,直到放入合适位置,称为向上调整。
为何只需要和父节点比较?因为原本堆已经满足父节点是左右子树中最小的。
void InsertHeap(Heap *heap, DataType data)
{
assert(heap);
if (heap->size == heap->capacity) {
//扩容,没使用realloc
int newCap = 2 * heap->capacity;
DataType *pNew = (DataType*)malloc(sizeof(DataType)*newCap);
if (NULL == pNew) {
exit(EXIT_FAILURE);
}
int i = 0;
for (i = 0; i < heap->size; i++) {
pNew[i] = heap->array[i];
}
heap->array = pNew;
heap->capacity = newCap;
}
heap->array[heap->size++] = data;
//向上调整
int parent = (heap->size - 2) >> 1;
int cur = heap->size - 1;
while (parent >= 0) {
if (heap->compare(heap->array[cur], heap->array[parent])) {
swap(&heap->array[parent], &heap->array[cur]);
cur = parent;
parent = (parent - 1) >> 1;
}
else {
return;
}
}
return;
}
删除元素
堆顶元素与堆尾元素交换,删除堆尾,调整堆顶。
void DeleteHeap(Heap *heap)
{
assert(heap);
if (heap->size > 1) {
swap(&heap->array[0], &heap->array[heap->size - 1]);
heap->size--;
int i = 0;
int end = (heap->size - 2) >> 1;
Adjust(heap, 0);
}
else if(heap->size ==1){
heap->size--;
}
}
优先级队列
优先级队列和堆的性质完全吻合。
每次出队的是值最小的(堆顶)。封装一个堆就可以了。
TopK问题
海量数据一次装不到内存里,需要分批处理。此时建立堆,或者外部排序解决。
扫描二维码关注公众号,回复:
1434466 查看本文章
堆的思想是,建立一个固定大小的小根堆,将数据剩余元素逐个与堆顶比较,如果大于堆顶,说明比堆里最小的元素大,那么将堆顶元素删除,插入这个较大元素。
void TopK(int data[], int len, int top[])
{
const int MaxLen = 5;
Heap heap;
InitHeap(&heap, Less);
CreateHeap(&heap, data, MaxLen);
int res = len - MaxLen; //剩余需要处理的元素个数
//维护一个只有五个数值的堆
while (res) {
if (data[len - res] > TopHeap(&heap)) {
DeleteHeap(&heap);
InsertHeap(&heap, data[len - res]);
}
res--;
}
//此时堆元素就是最大的5个元素
int i = 0;
for (i = 0; i < 5; i++) {
top[i] = TopHeap(&heap);
DeleteHeap(&heap);
}
}
堆排序
void HeapSort(int array[], int len)
{
if (NULL == array) {
return;
}
//建立大根堆
Heap heap;
InitHeap(&heap, Less);
CreateHeap(&heap, array, len);
//堆顶元素放数组末尾,移除堆顶元素,调整堆顶元素
while (len--) {
array[len] = TopHeap(&heap);
DeleteHeap(&heap);
}
DestroyHeap(&heap);
}