added qse_arr_updateheap(), qse_arr_deleteheap()
This commit is contained in:
parent
7f24950536
commit
6b9fd818f8
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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]))
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user