Skip to content

Instantly share code, notes, and snippets.

@martinkunev
Created November 14, 2011 22:52
Show Gist options
  • Save martinkunev/1365481 to your computer and use it in GitHub Desktop.
Save martinkunev/1365481 to your computer and use it in GitHub Desktop.
Binary heap (C implementation)
// WARNING: Requires C99 compatible compiler
#include <unistd.h>
#include <stdlib.h>
#include "heap.h"
#define CMP(a, b) ((a) >= (b))
static const unsigned int base_size = 4;
// Prepares the heap for use
void heap_init(struct heap *restrict h)
{
*h = (struct heap){
.size = base_size,
.count = 0,
.data = malloc(sizeof(type) * base_size)
};
if (!h->data) _exit(1); // Exit if the memory allocation fails
}
// Inserts element to the heap
void heap_push(struct heap *restrict h, type value)
{
unsigned int index, parent;
// Resize the heap if it is too small to hold all the data
if (h->count == h->size)
{
h->size <<= 1;
h->data = realloc(h->data, sizeof(type) * h->size);
if (!h->data) _exit(1); // Exit if the memory allocation fails
}
// Find out where to put the element and put it
for(index = h->count++; index; index = parent)
{
parent = (index - 1) >> 1;
if CMP(h->data[parent], value) break;
h->data[index] = h->data[parent];
}
h->data[index] = value;
}
// Removes the biggest element from the heap
void heap_pop(struct heap *restrict h)
{
unsigned int index, swap, other;
// Remove the biggest element
type temp = h->data[--h->count];
// Resize the heap if it's consuming too much memory
if ((h->count <= (h->size >> 2)) && (h->size > base_size))
{
h->size >>= 1;
h->data = realloc(h->data, sizeof(type) * h->size);
if (!h->data) _exit(1); // Exit if the memory allocation fails
}
// Reorder the elements
for(index = 0; 1; index = swap)
{
// Find the child to swap with
swap = (index << 1) + 1;
if (swap >= h->count) break; // If there are no children, the heap is reordered
other = swap + 1;
if ((other < h->count) && CMP(h->data[other], h->data[swap])) swap = other;
if CMP(temp, h->data[swap]) break; // If the bigger child is less than or equal to its parent, the heap is reordered
h->data[index] = h->data[swap];
}
h->data[index] = temp;
}
// Heapifies a non-empty array
void heapify(type data[restrict], unsigned int count)
{
unsigned int item, index, swap, other;
type temp;
// Move every non-leaf element to the right position in its subtree
item = (count >> 1) - 1;
while (1)
{
// Find the position of the current element in its subtree
temp = data[item];
for(index = item; 1; index = swap)
{
// Find the child to swap with
swap = (index << 1) + 1;
if (swap >= count) break; // If there are no children, the current element is positioned
other = swap + 1;
if ((other < count) && CMP(data[other], data[swap])) swap = other;
if CMP(temp, data[swap]) break; // If the bigger child is smaller than or equal to the parent, the heap is reordered
data[index] = data[swap];
}
if (index != item) data[index] = temp;
if (!item) return;
--item;
}
}
// WARNING: Requires C99 compatible compiler
typedef int type;
struct heap
{
unsigned int size; // Size of the allocated memory (in number of items)
unsigned int count; // Count of the elements in the heap
type *data; // Array with the elements
};
void heap_init(struct heap *restrict h);
void heap_push(struct heap *restrict h, type value);
void heap_pop(struct heap *restrict h);
// Returns the biggest element in the heap
#define heap_front(h) (*(h)->data)
// Frees the allocated memory
#define heap_term(h) (free((h)->data))
void heapify(type data[restrict], unsigned int count);
@martinkunev
Copy link
Author

martinkunev commented Oct 1, 2019

This is actually an old version but thanks for the feedback anyway.
@mucamaca Good catch about heapify() with length 1, I have actually fixed this in a later version.
about pop(), my intention when writing this was to suppose design by contract. I guess an abort() call inside pop() can be made in case the heap is empty.

Latest version is at https://gitlab.com/martinkunev/conquest_of_levidon/tree/2019/src/generic/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment