108 lines
3.7 KiB
C
108 lines
3.7 KiB
C
#include "heap.h"
|
|
|
|
/* Byte-wise swap two items of size SIZE. */
|
|
#define SWAP(a, b, size) \
|
|
do \
|
|
{ \
|
|
register size_t __size = (size); \
|
|
register char *__a = (a), *__b = (b); \
|
|
do \
|
|
{ \
|
|
char __tmp = *__a; \
|
|
*__a++ = *__b; \
|
|
*__b++ = __tmp; \
|
|
} while (--__size > 0); \
|
|
} while (0)
|
|
|
|
inline char *__vector_GetPtr(Vector *v, size_t pos) {
|
|
return v->data + (pos * v->elemSize);
|
|
}
|
|
|
|
void __sift_up(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
|
size_t len = last - first;
|
|
if (len > 1) {
|
|
len = (len - 2) / 2;
|
|
size_t ptr = first + len;
|
|
if (cmp(__vector_GetPtr(v, ptr), __vector_GetPtr(v, --last)) < 0) {
|
|
char t[v->elemSize];
|
|
memcpy(t, __vector_GetPtr(v, last), v->elemSize);
|
|
do {
|
|
memcpy(__vector_GetPtr(v, last), __vector_GetPtr(v, ptr), v->elemSize);
|
|
last = ptr;
|
|
if (len == 0)
|
|
break;
|
|
len = (len - 1) / 2;
|
|
ptr = first + len;
|
|
} while (cmp(__vector_GetPtr(v, ptr), t) < 0);
|
|
memcpy(__vector_GetPtr(v, last), t, v->elemSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
void __sift_down(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *), size_t start) {
|
|
// left-child of __start is at 2 * __start + 1
|
|
// right-child of __start is at 2 * __start + 2
|
|
size_t len = last - first;
|
|
size_t child = start - first;
|
|
|
|
if (len < 2 || (len - 2) / 2 < child)
|
|
return;
|
|
|
|
child = 2 * child + 1;
|
|
|
|
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
|
// right-child exists and is greater than left-child
|
|
++child;
|
|
}
|
|
|
|
// check if we are in heap-order
|
|
if (cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, start)) < 0)
|
|
// we are, __start is larger than it's largest child
|
|
return;
|
|
|
|
char top[v->elemSize];
|
|
memcpy(top, __vector_GetPtr(v, start), v->elemSize);
|
|
do {
|
|
// we are not in heap-order, swap the parent with it's largest child
|
|
memcpy(__vector_GetPtr(v, start), __vector_GetPtr(v, first + child), v->elemSize);
|
|
start = first + child;
|
|
|
|
if ((len - 2) / 2 < child)
|
|
break;
|
|
|
|
// recompute the child based off of the updated parent
|
|
child = 2 * child + 1;
|
|
|
|
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
|
// right-child exists and is greater than left-child
|
|
++child;
|
|
}
|
|
|
|
// check if we are in heap-order
|
|
} while (cmp(__vector_GetPtr(v, first + child), top) >= 0);
|
|
memcpy(__vector_GetPtr(v, start), top, v->elemSize);
|
|
}
|
|
|
|
|
|
void Make_Heap(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
|
if (last - first > 1) {
|
|
// start from the first parent, there is no need to consider children
|
|
for (int start = (last - first - 2) / 2; start >= 0; --start) {
|
|
__sift_down(v, first, last, cmp, first + start);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
inline void Heap_Push(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
|
__sift_up(v, first, last, cmp);
|
|
}
|
|
|
|
|
|
inline void Heap_Pop(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
|
if (last - first > 1) {
|
|
SWAP(__vector_GetPtr(v, first), __vector_GetPtr(v, --last), v->elemSize);
|
|
__sift_down(v, first, last, cmp, first);
|
|
}
|
|
}
|