mirror of
https://gitee.com/apaki/unicstl.git
synced 2025-05-17 19:41:36 +08:00
382 lines
7.8 KiB
C
382 lines
7.8 KiB
C
/**
|
|
* @brief
|
|
*
|
|
* @param self
|
|
* @param obj_size
|
|
* @return true
|
|
* @return false
|
|
*/
|
|
#include "heap.h"
|
|
|
|
static int left(int i)
|
|
{
|
|
return 2 * i + 1;
|
|
}
|
|
|
|
static int right(int i)
|
|
{
|
|
return (i << 1) + 2;
|
|
}
|
|
|
|
static int parent(int i)
|
|
{
|
|
if(i == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
return (i-1) >> 1;
|
|
}
|
|
|
|
static bool heap_peek(struct _heap* self, void* obj)
|
|
{
|
|
assert(self != NULL);
|
|
assert(obj != NULL);
|
|
if(obj == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
if(self->empty(self))
|
|
{
|
|
return false;
|
|
}
|
|
memmove(obj, self->obj, self->_obj_size);
|
|
return true;
|
|
}
|
|
|
|
static void heap_swap(struct _heap* self, int i, int j)
|
|
{
|
|
assert(self != NULL);
|
|
assert(self->_obj_size != 0);
|
|
// #define C99_VLA
|
|
#ifdef C99_VLA
|
|
char tmp[self->_obj_size];
|
|
#else
|
|
char* tmp = malloc(self->_obj_size);
|
|
if (tmp == NULL)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
memmove(tmp, (char *)self->obj + i * self->_obj_size, self->_obj_size);
|
|
memmove((char*)self->obj + i * self->_obj_size, (char*)self->obj + j * self->_obj_size, self->_obj_size);
|
|
memmove((char*)self->obj + j * self->_obj_size, tmp, self->_obj_size);
|
|
|
|
#ifndef C99_VLA
|
|
free(tmp);
|
|
#endif
|
|
}
|
|
|
|
static void heap_fixed_up(struct _heap* self, int i)
|
|
{
|
|
assert(self != NULL);
|
|
assert(self->compare != NULL);
|
|
int p = 0;
|
|
|
|
if(self->compare == NULL)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
if(self->_type == HEAP_MAX)
|
|
{
|
|
while(1)
|
|
{
|
|
p = parent(i);
|
|
// if current node is greater than its parent, swap the position. otherwise break out of loop
|
|
if(p < 0 || self->compare((char *)self->obj + i * self->_obj_size, (char *)self->obj + p * self->_obj_size) <= 0)
|
|
{
|
|
break;
|
|
}
|
|
heap_swap(self, i, p);
|
|
i = p;
|
|
}
|
|
}
|
|
else /* if(self->_type == HEAP_MIN) */
|
|
{
|
|
while(1)
|
|
{
|
|
p = parent(i);
|
|
// if current node is less than its parent, swap the position. otherwise break out of loop
|
|
if(p < 0 || self->compare((char *)self->obj + i * self->_obj_size, (char *)self->obj + p * self->_obj_size) >= 0)
|
|
{
|
|
break;
|
|
}
|
|
heap_swap(self, i, p);
|
|
i = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool heap_push(struct _heap* self, void* obj)
|
|
{
|
|
assert(self != NULL);
|
|
if(self->size(self) > self->_capacity)
|
|
{
|
|
return false;
|
|
}
|
|
uint32_t index = self->size(self);
|
|
memmove((char *)self->obj + index * self->_obj_size, obj, self->_obj_size);
|
|
self->_size++;
|
|
|
|
heap_fixed_up(self, index);
|
|
return true;
|
|
}
|
|
|
|
static void heap_fixed_down(struct _heap* self, int i)
|
|
{
|
|
assert(self != NULL);
|
|
int l = 0,r = 0;
|
|
int max = 0, min = 0;
|
|
|
|
if(self->compare == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(self->_type == HEAP_MAX)
|
|
{
|
|
while(1)
|
|
{
|
|
l = left(i);
|
|
r = right(i);
|
|
max = i;
|
|
|
|
if(l < self->size(self) && self->compare((char *)self->obj + l * self->_obj_size, (char *)self->obj + max * self->_obj_size) > 0)
|
|
{
|
|
max = l;
|
|
}
|
|
|
|
if(r < self->size(self) && self->compare((char *)self->obj + r * self->_obj_size, (char *)self->obj + max * self->_obj_size) > 0)
|
|
{
|
|
max = r;
|
|
}
|
|
if(max == i)
|
|
{
|
|
break;
|
|
}
|
|
heap_swap(self, i, max);
|
|
i = max;
|
|
}
|
|
}
|
|
else /* if(self->_type == HEAP_MIN) */
|
|
{
|
|
while(1)
|
|
{
|
|
l = left(i);
|
|
r = right(i);
|
|
min = i;
|
|
|
|
if(l < self->size(self) && self->compare((char *)self->obj + l * self->_obj_size, (char *)self->obj + min * self->_obj_size) < 0)
|
|
{
|
|
min = l;
|
|
}
|
|
|
|
if(r < self->size(self) && self->compare((char *)self->obj + r * self->_obj_size, (char *)self->obj + min * self->_obj_size) < 0)
|
|
{
|
|
min = r;
|
|
}
|
|
if(min == i)
|
|
{
|
|
break;
|
|
}
|
|
heap_swap(self, i, min);
|
|
i = min;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool heap_pop(struct _heap* self, void* obj)
|
|
{
|
|
assert(self != NULL);
|
|
if(self->empty(self))
|
|
{
|
|
return false;
|
|
}
|
|
int index = self->size(self) - 1;
|
|
heap_swap(self, 0, index);
|
|
if(obj != NULL)
|
|
{
|
|
memmove(obj, (char *)self->obj + index * self->_obj_size, self->_obj_size);
|
|
}
|
|
self->_size--;
|
|
heap_fixed_down(self, 0);
|
|
return true;
|
|
}
|
|
|
|
static uint32_t heap_size(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
return self->_size;
|
|
}
|
|
|
|
static bool heap_empty(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
return self->size(self) == 0;
|
|
}
|
|
|
|
static bool heap_clear(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
self->_size = 0;
|
|
return true;
|
|
}
|
|
|
|
static void heap_destory(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
self->clear(self);
|
|
if(self->obj)
|
|
{
|
|
free(self->obj);
|
|
}
|
|
}
|
|
|
|
static void heap_print(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
assert(self->obj != NULL);
|
|
|
|
void* obj = NULL;
|
|
uint32_t offset = 0;
|
|
|
|
for (int i = 0; i < self->size(self); i++)
|
|
{
|
|
offset = self->_obj_size * i;
|
|
obj = (char *)self->obj + offset;
|
|
self->print_obj(obj);
|
|
}
|
|
}
|
|
|
|
|
|
iterator_t heap_iter(struct _heap* self)
|
|
{
|
|
assert(self != NULL);
|
|
iterator_t iter = &self->_iter;
|
|
|
|
iter->_container = self;
|
|
iter->_index = 0;
|
|
iter->_node = self->obj;
|
|
return iter;
|
|
}
|
|
|
|
bool heap_iter_hasnext(struct _iterator* iter)
|
|
{
|
|
assert(iter != NULL);
|
|
assert(iter->parent != NULL);
|
|
|
|
heap_t self = (heap_t)iter->_container;
|
|
if(iter->_index < self->size(self))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const void* heap_iter_next(struct _iterator* iter)
|
|
{
|
|
assert(iter != NULL);
|
|
assert(iter->parent != NULL);
|
|
|
|
heap_t self = (heap_t)iter->_container;
|
|
void *obj = NULL;
|
|
|
|
uint32_t index = iter->_index;
|
|
obj = self->obj + self->_obj_size * index;
|
|
|
|
iter->_index += 1;
|
|
return obj;
|
|
}
|
|
|
|
static bool heap_init2(struct _heap* self, uint32_t obj_size, uint32_t capacity)
|
|
{
|
|
assert(self != NULL);
|
|
|
|
// -------------------- private --------------------
|
|
self->_obj_size = obj_size;
|
|
self->_size = 0;
|
|
self->_capacity = capacity;
|
|
self->_ratio = 2;
|
|
|
|
self->obj = (void*)malloc(self->_capacity * self->_obj_size);
|
|
if(self->obj == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
self->_iter.hasnext = heap_iter_hasnext;
|
|
self->_iter.next = heap_iter_next;
|
|
|
|
self->_destory = heap_destory;
|
|
|
|
// -------------------- public --------------------
|
|
// kernel
|
|
self->peek = heap_peek;
|
|
self->push = heap_push;
|
|
self->pop = heap_pop;
|
|
self->empty = heap_empty;
|
|
|
|
// base
|
|
self->size = heap_size;
|
|
self->clear = heap_clear;
|
|
|
|
// iter
|
|
self->iter = heap_iter;
|
|
|
|
// config
|
|
self->compare = NULL;
|
|
|
|
// -------------------- debug --------------------
|
|
self->print = heap_print;
|
|
return true;
|
|
}
|
|
|
|
heap_t heap_max_new2(uint32_t obj_size, uint32_t capacity)
|
|
{
|
|
heap_t heap = NULL;
|
|
heap = (struct _heap*)malloc(sizeof(struct _heap));
|
|
if(heap == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if(heap_init2(heap, obj_size, capacity) != true)
|
|
{
|
|
free(heap);
|
|
return NULL;
|
|
}
|
|
|
|
heap->_type = HEAP_MAX;
|
|
return heap;
|
|
}
|
|
|
|
heap_t heap_min_new2(uint32_t obj_size, uint32_t capacity)
|
|
{
|
|
heap_t heap = NULL;
|
|
heap = (struct _heap*)malloc(sizeof(struct _heap));
|
|
if(heap == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if(heap_init2(heap, obj_size, capacity) != true)
|
|
{
|
|
free(heap);
|
|
return NULL;
|
|
}
|
|
|
|
heap->_type = HEAP_MIN;
|
|
return heap;
|
|
}
|
|
|
|
void heap_free(heap_t* heap)
|
|
{
|
|
if(*heap != NULL)
|
|
{
|
|
(*heap)->_destory(*heap);
|
|
free(*heap);
|
|
}
|
|
*heap = NULL;
|
|
}
|