]> git.seodisparate.com - SimpleArchiver/commitdiff
Change priority_heap to accept "less_fn"
authorStephen Seo <seo.disparate@gmail.com>
Sun, 30 Jun 2024 08:29:24 +0000 (17:29 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Sun, 30 Jun 2024 08:29:24 +0000 (17:29 +0900)
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
src/data_structures/priority_heap.h
src/data_structures/test.c

index 9e5a0b13d3b9262899c750dba13dadeeef7d763d..942fdbd0a2507a52f65d507459b2fd859a3af6b0 100644 (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];
index a983f957a1349d9d074b048ce87f38479138daa7..182affe035aa1d5872684350be74e87bd74d91c6 100644 (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.
index db909579207f205ba1504f0672614211b54c79bd..99c06025bc32d2f61b16c2f76c628b4a41450743 100644 (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);