unicstl/src/heap.c

288 lines
5.9 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;
}
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);
int p = 0;
if(self->_min_flag != true)
{
while(1)
{
p = parent(i);
// 若当前节点大于其父节点,则交换位置,否则退出循环
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
{
while(1)
{
p = parent(i);
// 若当前节点大于其父节点,则交换位置,否则退出循环
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;
}
}
}
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->_min_flag != true)
{
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
{
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;
}
}
}
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;
}
void heap_setmin(struct _heap* self, bool min_flag)
{
assert(self != NULL);
self->_min_flag = min_flag;
}
uint32_t heap_size(struct _heap* self)
{
assert(self != NULL);
return self->_size;
}
bool heap_empty(struct _heap* self)
{
assert(self != NULL);
return self->size(self) == 0;
}
bool heap_clear(struct _heap* self)
{
assert(self != NULL);
self->_size = 0;
return true;
}
void heap_destory(struct _heap* self)
{
assert(self != NULL);
self->clear(self);
if(self->obj)
{
free(self->obj);
}
}
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);
}
}
bool heap_init2(struct _heap* self, uint32_t obj_size, uint32_t capacity)
{
assert(self != NULL);
// 1. set attr
self->_obj_size = obj_size;
self->_size = 0;
self->_capacity = capacity;
self->_ratio = 2;
self->peek = heap_peek;
self->push = heap_push;
self->pop = heap_pop;
self->size = heap_size;
self->empty = heap_empty;
self->clear = heap_clear;
self->destory = heap_destory;
self->setmin = heap_setmin;
self->print = heap_print;
self->obj = (void*)malloc(self->_capacity * self->_obj_size);
if(self->obj == NULL)
{
return false;
}
return true;
}
heap_t heap_new(void)
{
return (struct _heap*)malloc(sizeof(struct _heap));
}
void heap_free(heap_t* heap)
{
if(*heap != NULL)
{
(*heap)->destory(*heap);
free(*heap);
}
*heap = NULL;
}