#include <stdlib.h>
#include <stdio.h>
struct heap_elem
{
int data;
unsigned heap_idx;
/* data */
};
typedef struct min_heap
{
struct heap_elem** data;
int element_num;
int size;
/* data */
} min_heap_t;
static int min_heap_elem_greater(struct heap_elem* elem1, struct heap_elem* elem2)
{
return elem1->data > elem2->data;
}
static void min_heap_shift_up(min_heap_t* heap, unsigned idx, struct heap_elem* data)
{
/* 1.先计算出父节点的下标 */
unsigned parent = (idx - 1) / 2;
/* 1. 保证idx>0,才能确保parent是有效的下标
2. 只有当parent下标的值大于要插入的值才需要继续向上找
*/
while (idx && min_heap_elem_greater(heap->data[parent], data))
{
/* code */
heap->data[idx] = heap->data[parent];
heap->data[idx]->heap_idx = idx;
idx = parent;
parent = (idx - 1) / 2;
}
heap->data[idx] = data;
heap->data[idx]->heap_idx = idx;
}
static int min_heap_reserve(min_heap_t* heap, unsigned element_num)
{
if (heap->size < element_num) {
unsigned s = heap->size == 0 ? 8 : 2 * heap->size;
struct heap_elem** p = (struct heap_elem**)realloc(heap->data, s * sizeof(struct heap_elem*));
if (p == NULL) {
return -1;
}
heap->data = p;
heap->size = s;
}
return 0;
}
int min_heap_push(min_heap_t* heap, struct heap_elem* data)
{
if (min_heap_reserve(heap, heap->element_num + 1)) {
return -1;
}
min_heap_shift_up(heap, heap->element_num++, data);
return 0;
}
static int min_heap_shift_down(min_heap_t* heap, unsigned idx, struct heap_elem* data)
{
unsigned min_child = (idx + 1) * 2;
while (min_child <= heap->element_num) {
min_child -= min_child == heap->element_num || min_heap_elem_greater(heap->data[min_child], heap->data[min_child - 1]);
// 如果当前的元素大于要插入的元素,直接break,说明已经找到了
if (!min_heap_elem_greater(data, heap->data[min_child])) {
break;
}
heap->data[idx] = heap->data[min_child];
heap->data[idx]->heap_idx = idx;
idx = min_child;
min_child = (idx + 1) * 2;
}
min_heap_shift_up(heap, idx, data);
}
struct heap_elem* min_heap_pop(min_heap_t* heap)
{
struct heap_elem* ptr = 0;
if (heap->element_num) {
ptr = *heap->data;
min_heap_shift_down(heap, 0, heap->data[--heap->element_num]);
ptr->heap_idx = -1;
}
return ptr;
}