Change priority_heap to accept "less_fn"
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 3s

This allows for reverse order in the priority heap by using a "more_fn"
in place of a "less fn".
This commit is contained in:
Stephen Seo 2024-06-30 17:29:24 +09:00
parent d815f67b2d
commit 9e95c5e292
3 changed files with 101 additions and 6 deletions

View file

@ -26,6 +26,7 @@ void simple_archiver_priority_heap_internal_realloc(
new_priority_heap->capacity = (*priority_heap)->capacity * 2;
new_priority_heap->size = 0;
new_priority_heap->less_fn = (*priority_heap)->less_fn;
new_priority_heap->nodes =
calloc(new_priority_heap->capacity, sizeof(SDArchiverPHNode));
@ -45,11 +46,30 @@ void simple_archiver_priority_heap_internal_realloc(
*priority_heap = new_priority_heap;
}
int simple_archiver_priority_heap_default_less(long long a, long long b) {
return a < b ? 1 : 0;
}
SDArchiverPHeap *simple_archiver_priority_heap_init(void) {
SDArchiverPHeap *priority_heap = malloc(sizeof(SDArchiverPHeap));
priority_heap->capacity = SC_SA_DS_PRIORITY_HEAP_START_SIZE;
priority_heap->size = 0;
priority_heap->less_fn = simple_archiver_priority_heap_default_less;
priority_heap->nodes =
calloc(priority_heap->capacity, sizeof(SDArchiverPHNode));
return priority_heap;
}
SDArchiverPHeap *simple_archiver_priority_heap_init_less_fn(
int (*less_fn)(long long, long long)) {
SDArchiverPHeap *priority_heap = malloc(sizeof(SDArchiverPHeap));
priority_heap->capacity = SC_SA_DS_PRIORITY_HEAP_START_SIZE;
priority_heap->size = 0;
priority_heap->less_fn = less_fn;
priority_heap->nodes =
calloc(priority_heap->capacity, sizeof(SDArchiverPHNode));
@ -91,7 +111,10 @@ void simple_archiver_priority_heap_insert(SDArchiverPHeap **priority_heap,
unsigned int hole = (*priority_heap)->size + 1;
while (hole > 1 && priority < (*priority_heap)->nodes[hole / 2].priority) {
while (hole > 1 &&
(*priority_heap)
->less_fn(priority,
(*priority_heap)->nodes[hole / 2].priority) != 0) {
(*priority_heap)->nodes[hole] = (*priority_heap)->nodes[hole / 2];
hole /= 2;
}
@ -127,12 +150,15 @@ void *simple_archiver_priority_heap_pop(SDArchiverPHeap *priority_heap) {
while (hole * 2 + 1 <= priority_heap->size) {
if (priority_heap->nodes[hole * 2].is_valid != 0 &&
priority_heap->nodes[hole * 2 + 1].is_valid != 0) {
if (end.priority < priority_heap->nodes[hole * 2].priority &&
end.priority < priority_heap->nodes[hole * 2 + 1].priority) {
if (priority_heap->less_fn(
end.priority, priority_heap->nodes[hole * 2].priority) != 0 &&
priority_heap->less_fn(
end.priority, priority_heap->nodes[hole * 2 + 1].priority) != 0) {
break;
}
if (priority_heap->nodes[hole * 2].priority <
priority_heap->nodes[hole * 2 + 1].priority) {
if (priority_heap->less_fn(priority_heap->nodes[hole * 2].priority,
priority_heap->nodes[hole * 2 + 1].priority) !=
0) {
priority_heap->nodes[hole] = priority_heap->nodes[hole * 2];
hole = hole * 2;
} else {
@ -140,7 +166,8 @@ void *simple_archiver_priority_heap_pop(SDArchiverPHeap *priority_heap) {
hole = hole * 2 + 1;
}
} else if (priority_heap->nodes[hole * 2].is_valid != 0) {
if (end.priority < priority_heap->nodes[hole * 2].priority) {
if (priority_heap->less_fn(
end.priority, priority_heap->nodes[hole * 2].priority) != 0) {
break;
}
priority_heap->nodes[hole] = priority_heap->nodes[hole * 2];

View file

@ -33,9 +33,16 @@ typedef struct SDArchiverPHeap {
SDArchiverPHNode *nodes;
unsigned long long capacity;
unsigned long long size;
int (*less_fn)(long long, long long);
} SDArchiverPHeap;
/// Default "less" function to determine if a has higher priority than b.
/// Returns non-zero if "less".
int simple_archiver_priority_heap_default_less(long long a, long long b);
SDArchiverPHeap *simple_archiver_priority_heap_init(void);
SDArchiverPHeap *simple_archiver_priority_heap_init_less_fn(
int (*less_fn)(long long, long long));
void simple_archiver_priority_heap_free(SDArchiverPHeap **priority_heap);
/// If data_cleanup_fn is NULL, then "free()" is used on data when freed.

View file

@ -61,6 +61,8 @@ int get_three_fn(void *data, __attribute__((unused)) void *ud) {
return strcmp(data, "three") == 0 ? 1 : 0;
}
int more_fn(long long a, long long b) { return a > b ? 1 : 0; }
int main(void) {
// Test LinkedList.
{
@ -259,6 +261,65 @@ int main(void) {
simple_archiver_priority_heap_insert(&priority_heap, idx, data, NULL);
}
simple_archiver_priority_heap_free(&priority_heap);
// Reverse priority.
priority_heap = simple_archiver_priority_heap_init_less_fn(more_fn);
for (unsigned int idx = 0; idx < max; ++idx) {
unsigned int *data = malloc(sizeof(unsigned int));
*data = idx;
simple_archiver_priority_heap_insert(&priority_heap, idx, data, NULL);
}
for (unsigned int idx = max; idx-- > 0;) {
unsigned int *data = simple_archiver_priority_heap_top(priority_heap);
CHECK_TRUE(*data == idx);
data = simple_archiver_priority_heap_pop(priority_heap);
CHECK_TRUE(*data == idx);
free(data);
}
simple_archiver_priority_heap_free(&priority_heap);
// Insert in random order with reverse-priority-heap.
priority_heap = simple_archiver_priority_heap_init_less_fn(more_fn);
array = malloc(sizeof(unsigned int) * max);
for (unsigned int idx = 0; idx < max; ++idx) {
array[idx] = idx;
}
// Deterministic randomization.
for (unsigned int idx = max - 1; idx-- > 0;) {
unsigned int other_idx = simple_archiver_algo_lcg_defaults(idx) %
(unsigned long long)(idx + 1);
if (idx != other_idx) {
unsigned int temp = array[max - 1];
array[max - 1] = array[other_idx];
array[other_idx] = temp;
}
}
// Insert the deterministically randomized array.
for (unsigned int idx = 0; idx < max; ++idx) {
simple_archiver_priority_heap_insert(&priority_heap, array[idx],
array + idx, no_free_fn);
}
for (unsigned int idx = max; idx-- > 0;) {
unsigned int *data = simple_archiver_priority_heap_top(priority_heap);
CHECK_TRUE(*data == idx);
if (*data != idx) {
printf("idx is %u, data is %u\n", idx, *data);
}
data = simple_archiver_priority_heap_pop(priority_heap);
CHECK_TRUE(*data == idx);
if (*data != idx) {
printf("idx is %u, data is %u\n", idx, *data);
}
}
free(array);
simple_archiver_priority_heap_free(&priority_heap);
}
printf("Checks checked: %u\n", checks_checked);