mirror of
https://gitee.com/apaki/unicstl.git
synced 2025-07-04 08:06:52 +08:00
288 lines
5.9 KiB
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;
|
|
}
|