added qse_arr_updateheap(), qse_arr_deleteheap()

This commit is contained in:
hyung-hwan 2016-09-24 02:49:24 +00:00
parent 7f24950536
commit 6b9fd818f8
5 changed files with 238 additions and 100 deletions

View File

@ -92,6 +92,11 @@ typedef void (*qse_arr_freeer_t) (
* the arry needs to compare data. A linear dynamic array is created with a
* default comparator that performs bitwise comparison.
*
* The default comparator compares data in a memcmp-like fashion.
* It is not suitable when you want to implement a heap of numbers
* greater than a byte size. You must implement a comparator that
* takes the whole element and performs comparison in such a case.
*
* The comparator should return 0 if the data are the same, a negative
* integer if the first data is less than the second data, a positive
* integer otherwise.
@ -259,7 +264,8 @@ QSE_EXPORT qse_arr_comper_t qse_arr_getcomper (
/**
* The qse_arr_setcomper() function specifies how to compare two elements
* for equality test. The comparator @a comper must return 0 if two elements
* compared are equal, or a non-zero number otherwise.
* compared are equal, 1 if the first element is greater than the
* second, -1 if the second element is greater than the first.
*/
QSE_EXPORT void qse_arr_setcomper (
qse_arr_t* arr /**< arr */,
@ -428,6 +434,18 @@ QSE_EXPORT void qse_arr_popheap (
qse_arr_t* arr
);
QSE_EXPORT void qse_arr_deleteheap (
qse_arr_t* arr,
qse_size_t index
);
QSE_EXPORT qse_size_t qse_arr_updateheap (
qse_arr_t* arr,
qse_size_t index,
void* dptr,
qse_size_t dlen
);
#if defined(__cplusplus)
}
#endif

View File

@ -43,6 +43,8 @@
#define DPTR(slot) ((slot)->val.ptr)
#define DLEN(slot) ((slot)->val.len)
/* the default comparator is not proper for number comparision.
* the first different byte decides whice side is greater */
static int default_comparator (arr_t* arr,
const void* dptr1, size_t dlen1,
const void* dptr2, size_t dlen2)
@ -52,8 +54,11 @@ static int default_comparator (arr_t* arr,
return 1;
*/
size_t min = (dlen1 < dlen2)? dlen1: dlen2;
int n = QSE_MEMCMP (dptr1, dptr2, TOB(arr,min));
int n;
size_t min;
min = (dlen1 < dlen2)? dlen1: dlen2;
n = QSE_MEMCMP (dptr1, dptr2, TOB(arr,min));
if (n == 0 && dlen1 != dlen2)
{
n = (dlen1 > dlen2)? 1: -1;
@ -378,8 +383,7 @@ size_t qse_arr_insert (arr_t* arr, size_t pos, void* dptr, size_t dlen)
if (capa <= mincapa)
{
if (arr->freeer)
arr->freeer (arr, DPTR(slot), DLEN(slot));
if (arr->freeer) arr->freeer (arr, DPTR(slot), DLEN(slot));
QSE_MMGR_FREE (arr->mmgr, slot);
return QSE_ARR_NIL;
}
@ -392,8 +396,7 @@ size_t qse_arr_insert (arr_t* arr, size_t pos, void* dptr, size_t dlen)
if (pos >= arr->capa || arr->size >= arr->capa)
{
/* the buffer is not still enough after resizing */
if (arr->freeer)
arr->freeer (arr, DPTR(slot), DLEN(slot));
if (arr->freeer) arr->freeer (arr, DPTR(slot), DLEN(slot));
QSE_MMGR_FREE (arr->mmgr, slot);
return QSE_ARR_NIL;
}
@ -439,8 +442,7 @@ size_t qse_arr_update (arr_t* arr, size_t pos, void* dptr, size_t dlen)
slot_t* slot = alloc_slot (arr, dptr, dlen);
if (slot == QSE_NULL) return QSE_ARR_NIL;
if (arr->freeer != QSE_NULL)
arr->freeer (arr, DPTR(c), DLEN(c));
if (arr->freeer) arr->freeer (arr, DPTR(c), DLEN(c));
QSE_MMGR_FREE (arr->mmgr, c);
arr->slot[pos] = slot;
@ -465,8 +467,7 @@ size_t qse_arr_delete (arr_t* arr, size_t index, size_t count)
if (c != QSE_NULL)
{
if (arr->freeer != QSE_NULL)
arr->freeer (arr, DPTR(c), DLEN(c));
if (arr->freeer) arr->freeer (arr, DPTR(c), DLEN(c));
QSE_MMGR_FREE (arr->mmgr, c);
arr->slot[i] = QSE_NULL;
@ -498,8 +499,7 @@ size_t qse_arr_uplete (arr_t* arr, size_t index, size_t count)
if (c != QSE_NULL)
{
if (arr->freeer != QSE_NULL)
arr->freeer (arr, DPTR(c), DLEN(c));
if (arr->freeer) arr->freeer (arr, DPTR(c), DLEN(c));
QSE_MMGR_FREE (arr->mmgr, c);
arr->slot[i] = QSE_NULL;
@ -608,93 +608,163 @@ void qse_arr_popstack (arr_t* arr)
#define HEAP_LEFT(x) ((x)*2 + 1)
#define HEAP_RIGHT(x) ((x)*2 + 2)
size_t qse_arr_pushheap (arr_t* arr, void* dptr, size_t dlen)
size_t sift_up (arr_t* arr, size_t index)
{
size_t cur, par;
size_t parent;
int n;
/* add a value to the bottom */
cur = arr->size;
if (qse_arr_insert (arr, cur, dptr, dlen) == QSE_ARR_NIL)
return QSE_ARR_NIL;
while (cur != 0)
if (index > 0)
{
parent = HEAP_PARENT(index);
n = arr->comper (arr,
DPTR(arr->slot[index]), DLEN(arr->slot[index]),
DPTR(arr->slot[parent]), DLEN(arr->slot[parent]));
if (n > 0)
{
slot_t* tmp;
/* compare with the parent */
par = HEAP_PARENT(cur);
tmp = arr->slot[index];
while (1)
{
arr->slot[index] = arr->slot[parent];
index = parent;
parent = HEAP_PARENT(parent);
if (index <= 0) break;
n = arr->comper (arr,
DPTR(arr->slot[cur]), DLEN(arr->slot[cur]),
DPTR(arr->slot[par]), DLEN(arr->slot[par]));
if (n <= 0) break; /* ok */
/* swap the current with the parent */
tmp = arr->slot[cur];
arr->slot[cur] = arr->slot[par];
arr->slot[par] = tmp;
cur = par;
DPTR(tmp), DLEN(tmp),
DPTR(arr->slot[parent]), DLEN(arr->slot[parent]));
if (n <= 0) break;
}
arr->slot[index] = tmp;
}
}
return index;
}
size_t sift_down (arr_t* arr, size_t index)
{
size_t base;
base = arr->size / 2;
if (index < base) /* at least 1 child is under the 'index' position */
{
slot_t* tmp;
tmp = arr->slot[index];
do
{
qse_size_t left, right, child;
int n;
left= HEAP_LEFT(index);
right = HEAP_RIGHT(index);
if (right < arr->size)
{
n = arr->comper (arr,
DPTR(arr->slot[right]), DLEN(arr->slot[right]),
DPTR(arr->slot[left]), DLEN(arr->slot[left]));
child = (n > 0)? right: left;
}
else
{
child = left;
}
n = arr->comper (arr,
DPTR(tmp), DLEN(tmp),
DPTR(arr->slot[child]), DLEN(arr->slot[child]));
if (n > 0) break;
arr->slot[index] = arr->slot[child];
index = child;
}
while (index < base);
arr->slot[index] = tmp;
}
return index;
}
size_t qse_arr_pushheap (arr_t* arr, void* dptr, size_t dlen)
{
size_t index;
/* add a value at the back of the array */
index = arr->size;
if (qse_arr_insert (arr, index, dptr, dlen) == QSE_ARR_NIL) return QSE_ARR_NIL;
QSE_ASSERT (arr->size == index + 1);
/* move the item upto the top if it's greater than the parent items */
sift_up (arr, index);
return arr->size;
}
void qse_arr_popheap (arr_t* arr)
{
size_t cur, child;
QSE_ASSERT (arr->size > 0);
qse_arr_deleteheap (arr, 0);
}
void qse_arr_deleteheap (arr_t* arr, size_t index)
{
slot_t* tmp;
QSE_ASSERT (arr->size > 0);
QSE_ASSERT (index < arr->size);
/* destroy the top */
tmp = arr->slot[0];
/* remember the item to destroy */
tmp = arr->slot[index];
arr->size = arr->size - 1;
if (arr->size > 0 && index != arr->size)
{
int n;
/* move the last item to the deleting position */
arr->slot[index] = arr->slot[arr->size];
/* move it up if the last item is greater than the item to be deleted,
* move it down otherwise. */
n = arr->comper (arr,
DPTR(arr->slot[index]), DLEN(arr->slot[index]),
DPTR(tmp), DLEN(tmp));
if (n > 0) sift_up (arr, index);
else if (n < 0) sift_down (arr, index);
}
/* destroy the actual item */
if (arr->freeer) arr->freeer (arr, DPTR(tmp), DLEN(tmp));
QSE_MMGR_FREE (arr->mmgr, tmp);
/* move the last item to the top position also shrink the size */
arr->slot[0] = arr->slot[--arr->size];
/* empty the last slot */
arr->slot[arr->size] = QSE_NULL;
}
if (arr->size <= 1) return; /* only 1 element. nothing further to do */
for (cur = 0; cur < arr->size; cur = child)
{
size_t left, right;
size_t qse_arr_updateheap (qse_arr_t* arr, qse_size_t index, void* dptr, qse_size_t dlen)
{
slot_t* tmp;
int n;
left = HEAP_LEFT(cur);
right = HEAP_RIGHT(cur);
tmp = arr->slot[index];
QSE_ASSERT (tmp != QSE_NULL);
if (left >= arr->size)
n = arr->comper (arr, dptr, dlen, DPTR(tmp), DLEN(tmp));
if (n)
{
/* the left child does not exist.
* reached the bottom. abort exchange */
break;
if (qse_arr_update (arr, index, dptr, dlen) == QSE_ARR_NIL) return QSE_ARR_NIL;
if (n > 0) sift_up (arr, index);
else sift_down (arr, index);
}
if (right >= arr->size)
{
/* the right child does not exist. only the left */
child = left;
}
else
{
/* get the larger child of the two */
n = arr->comper (arr,
DPTR(arr->slot[left]), DLEN(arr->slot[left]),
DPTR(arr->slot[right]), DLEN(arr->slot[right]));
child = (n > 0)? left: right;
}
/* compare the current one with the child */
n = arr->comper (arr,
DPTR(arr->slot[cur]), DLEN(arr->slot[cur]),
DPTR(arr->slot[child]), DLEN(arr->slot[child]));
if (n > 0) break; /* current one is larger. stop exchange */
/* swap the current with the child */
tmp = arr->slot[cur];
arr->slot[cur] = arr->slot[child];
arr->slot[child] = tmp;
}
return index;
}

View File

@ -137,7 +137,7 @@ static qse_tmr_index_t sift_down (qse_tmr_t* tmr, qse_tmr_index_t index, int not
{
qse_size_t base = tmr->size / 2;
if (index < base) /* at least 1 child is under the 'index' positmrn */
if (index < base) /* at least 1 child is under the 'index' position */
{
qse_tmr_event_t item;
qse_size_t old_index;
@ -149,7 +149,7 @@ static qse_tmr_index_t sift_down (qse_tmr_t* tmr, qse_tmr_index_t index, int not
{
qse_size_t left, right, younger;
left= HEAP_LEFT(index);
left = HEAP_LEFT(index);
right = HEAP_RIGHT(index);
if (right < tmr->size && YOUNGER_THAN(&tmr->event[right], &tmr->event[left]))

View File

@ -372,6 +372,14 @@ static int test4 ()
qse_arr_comper_t default_comparator;
static int integer_comparator (qse_arr_t* arr,
const void* dptr1, size_t dlen1,
const void* dptr2, size_t dlen2)
{
return (*(int*)dptr1 > *(int*)dptr2)? 1:
(*(int*)dptr1 < *(int*)dptr2)? -1: 0;
}
static int inverse_comparator (qse_arr_t* arr,
const void* dptr1, size_t dlen1,
const void* dptr2, size_t dlen2)
@ -382,7 +390,7 @@ static int inverse_comparator (qse_arr_t* arr,
static int test5 ()
{
qse_arr_t* s1;
int i, j;
int i, j, oldv, newv;
s1 = qse_arr_open (QSE_MMGR_GETDFL(), 0, 3);
if (s1 == QSE_NULL)
@ -393,55 +401,74 @@ static int test5 ()
qse_arr_setcopier (s1, QSE_ARR_COPIER_INLINE);
qse_arr_setscale (s1, QSE_SIZEOF(i));
qse_arr_setcomper (s1, integer_comparator);
/* inverse the comparator to implement min-heap */
default_comparator = qse_arr_getcomper (s1);
qse_arr_setcomper (s1, inverse_comparator);
for (i = 0; i < 25; i++)
for (i = 0; i < 2500; i++)
{
j = rand () % 100;
j = rand () % 1000;
qse_arr_pushheap (s1, &j, 1);
}
qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1));
qse_arr_walk (s1, walker3, QSE_NULL);
oldv = 0;
while (QSE_ARR_SIZE(s1) > 10 )
{
qse_printf (QSE_T("top => %d\n"), *(int*)QSE_ARR_DPTR(s1,0));
newv = *(int*)QSE_ARR_DPTR(s1,0);
qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv);
QSE_ASSERT (newv >= oldv);
qse_arr_popheap (s1);
oldv = newv;
}
for (i = 0; i < 25; i++)
for (i = 0; i < 2500; i++)
{
j = rand () % 100;
j = rand () % 1000;
qse_arr_pushheap (s1, &j, 1);
}
qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1));
qse_arr_walk (s1, walker3, QSE_NULL);
while (QSE_ARR_SIZE(s1))
oldv = 0;
while (QSE_ARR_SIZE(s1) > 0)
{
qse_printf (QSE_T("top => %d\n"), *(int*)QSE_ARR_DPTR(s1,0));
newv = *(int*)QSE_ARR_DPTR(s1,0);
qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv);
QSE_ASSERT (newv >= oldv);
qse_arr_popheap (s1);
oldv = newv;
}
/* back to max-heap */
qse_arr_setcomper (s1, default_comparator);
for (i = 0; i < 25; i++)
for (i = 0; i < 2500; i++)
{
j = rand () % 100;
j = rand () % 1000;
qse_arr_pushheap (s1, &j, 1);
}
j = 88888888;
qse_arr_updateheap (s1, QSE_ARR_SIZE(s1) / 2, &j, 1);
j = -123;
qse_arr_updateheap (s1, QSE_ARR_SIZE(s1) / 2, &j, 1);
qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1));
qse_arr_walk (s1, walker3, QSE_NULL);
while (QSE_ARR_SIZE(s1))
oldv = 99999999;
while (QSE_ARR_SIZE(s1) > 0)
{
qse_printf (QSE_T("top => %d\n"), *(int*)QSE_ARR_DPTR(s1,0));
newv = *(int*)QSE_ARR_DPTR(s1,0);
qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv);
QSE_ASSERT (newv <= oldv);
qse_arr_popheap (s1);
oldv = newv;
}

View File

@ -1,11 +1,14 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <qse/cmn/BinaryHeap.hpp>
#include <qse/cmn/String.hpp>
#include <qse/cmn/alg.h>
#include <qse/cmn/time.h>
//#define MAX_HEAP
class Julia
{
public:
@ -60,7 +63,11 @@ public:
}
#endif
#if defined(MAX_HEAP)
bool operator> (const Julia& q) const { return *this->x > *q.x; }
#else
bool operator> (const Julia& q) const { return *this->x < *q.x; }
#endif
int* x;
};
@ -71,20 +78,36 @@ int main ()
JuliaHeap jh;
qse_uint32_t x;
qse_ntime_t nt;
int oldval, newval;
qse_gettime (&nt);
x = nt.sec + nt.nsec;
for (int i = 0; i < 100; i++)
for (int i = 0; i < 2500; i++)
{
x = qse_rand31(x);
jh.insert (Julia((int)x % 100));
//x = qse_rand31(x);
x = rand();
jh.insert (Julia((int)x % 1000));
}
#if defined(MAX_HEAP)
oldval = 9999999;
#else
oldval = 0;
#endif
while (!jh.isEmpty())
{
printf ("%d\n", *jh.getValueAt(0).x);
newval = *jh.getValueAt(0).x;
printf ("%d oldval => %d\n", newval, oldval);
#if defined(MAX_HEAP)
QSE_ASSERT (newval <= oldval);
#else
QSE_ASSERT (newval >= oldval);
#endif
jh.remove (0);
oldval = newval;
}
return 0;
}