From 9e95c5e2928b1eb5549b38e5416dd6d5fe013a62 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sun, 30 Jun 2024 17:29:24 +0900 Subject: [PATCH] Change priority_heap to accept "less_fn" This allows for reverse order in the priority heap by using a "more_fn" in place of a "less fn". --- src/data_structures/priority_heap.c | 39 +++++++++++++++--- src/data_structures/priority_heap.h | 7 ++++ src/data_structures/test.c | 61 +++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/data_structures/priority_heap.c b/src/data_structures/priority_heap.c index 9e5a0b1..942fdbd 100644 --- a/src/data_structures/priority_heap.c +++ b/src/data_structures/priority_heap.c @@ -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]; diff --git a/src/data_structures/priority_heap.h b/src/data_structures/priority_heap.h index a983f95..182affe 100644 --- a/src/data_structures/priority_heap.h +++ b/src/data_structures/priority_heap.h @@ -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. diff --git a/src/data_structures/test.c b/src/data_structures/test.c index db90957..99c0602 100644 --- a/src/data_structures/test.c +++ b/src/data_structures/test.c @@ -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);