|
| 1 | +/** |
| 2 | + * @file |
| 3 | + * @brief Implementation of [Min Binary |
| 4 | + * Heap](https://en.wikipedia.org/wiki/Binary_heap) |
| 5 | + * @details |
| 6 | + * A Min Binary Heap is a complete binary tree-based data structure where the |
| 7 | + * value of each node is less than or equal to the values of its children. This |
| 8 | + * property ensures that the minimum element is always at the root, allowing |
| 9 | + * efficient retrieval and removal of the smallest element. |
| 10 | + * |
| 11 | + * @author [Aryan Singh](https://github.com/Dibbu-cell) |
| 12 | + */ |
| 13 | + |
| 14 | +#include <assert.h> /// for assert |
| 15 | +#include <stdbool.h> /// for bool type |
| 16 | +#include <stdio.h> /// for IO operations |
| 17 | +#include <stdlib.h> /// for malloc, realloc, free |
| 18 | + |
| 19 | +/** |
| 20 | + * @brief Structure representing a Min Binary Heap |
| 21 | + */ |
| 22 | +struct min_binary_heap |
| 23 | +{ |
| 24 | + int *arr; ///< pointer to the heap array |
| 25 | + size_t size; ///< current number of elements in the heap |
| 26 | + size_t capacity; ///< current capacity of the heap array |
| 27 | +}; |
| 28 | + |
| 29 | +/** |
| 30 | + * @brief Create a new Min Binary Heap with given initial capacity |
| 31 | + * @param capacity initial capacity of the heap |
| 32 | + * @returns pointer to the created heap, or NULL on failure |
| 33 | + */ |
| 34 | +struct min_binary_heap *min_heap_create(size_t capacity) |
| 35 | +{ |
| 36 | + struct min_binary_heap *heap = |
| 37 | + (struct min_binary_heap *)malloc(sizeof(struct min_binary_heap)); |
| 38 | + if (!heap) |
| 39 | + return NULL; |
| 40 | + heap->arr = (int *)malloc(capacity * sizeof(int)); |
| 41 | + if (!heap->arr) |
| 42 | + { |
| 43 | + free(heap); |
| 44 | + return NULL; |
| 45 | + } |
| 46 | + heap->size = 0; |
| 47 | + heap->capacity = capacity; |
| 48 | + return heap; |
| 49 | +} |
| 50 | + |
| 51 | +/** |
| 52 | + * @brief Free the memory used by the heap |
| 53 | + * @param heap pointer to the heap |
| 54 | + */ |
| 55 | +void min_heap_destroy(struct min_binary_heap *heap) |
| 56 | +{ |
| 57 | + if (heap) |
| 58 | + { |
| 59 | + free(heap->arr); |
| 60 | + free(heap); |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +/** |
| 65 | + * @brief Swap two integers |
| 66 | + * @param a pointer to first integer |
| 67 | + * @param b pointer to second integer |
| 68 | + */ |
| 69 | +static void swap(int *a, int *b) |
| 70 | +{ |
| 71 | + int temp = *a; |
| 72 | + *a = *b; |
| 73 | + *b = temp; |
| 74 | +} |
| 75 | + |
| 76 | +/** |
| 77 | + * @brief Heapify up to maintain min-heap property after insertion |
| 78 | + * @param heap pointer to the heap |
| 79 | + * @param idx index of the newly inserted element |
| 80 | + */ |
| 81 | +static void heapify_up(struct min_binary_heap *heap, size_t idx) |
| 82 | +{ |
| 83 | + if (idx == 0) |
| 84 | + return; |
| 85 | + size_t parent = (idx - 1) / 2; |
| 86 | + if (heap->arr[parent] > heap->arr[idx]) |
| 87 | + { |
| 88 | + swap(&heap->arr[parent], &heap->arr[idx]); |
| 89 | + heapify_up(heap, parent); |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +/** |
| 94 | + * @brief Heapify down to maintain min-heap property after extraction |
| 95 | + * @param heap pointer to the heap |
| 96 | + * @param idx index to heapify down from |
| 97 | + */ |
| 98 | +static void heapify_down(struct min_binary_heap *heap, size_t idx) |
| 99 | +{ |
| 100 | + size_t left = 2 * idx + 1; |
| 101 | + size_t right = 2 * idx + 2; |
| 102 | + size_t smallest = idx; |
| 103 | + |
| 104 | + if (left < heap->size && heap->arr[left] < heap->arr[smallest]) |
| 105 | + smallest = left; |
| 106 | + if (right < heap->size && heap->arr[right] < heap->arr[smallest]) |
| 107 | + smallest = right; |
| 108 | + |
| 109 | + if (smallest != idx) |
| 110 | + { |
| 111 | + swap(&heap->arr[idx], &heap->arr[smallest]); |
| 112 | + heapify_down(heap, smallest); |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +/** |
| 117 | + * @brief Insert a value into the min binary heap |
| 118 | + * @param heap pointer to the heap |
| 119 | + * @param value value to insert |
| 120 | + * @returns true if insertion succeeded, false otherwise |
| 121 | + */ |
| 122 | +bool min_heap_insert(struct min_binary_heap *heap, int value) |
| 123 | +{ |
| 124 | + if (!heap) |
| 125 | + return false; |
| 126 | + if (heap->size == heap->capacity) |
| 127 | + { |
| 128 | + size_t new_capacity = heap->capacity * 2; |
| 129 | + int *new_arr = (int *)realloc(heap->arr, new_capacity * sizeof(int)); |
| 130 | + if (!new_arr) |
| 131 | + return false; |
| 132 | + heap->arr = new_arr; |
| 133 | + heap->capacity = new_capacity; |
| 134 | + } |
| 135 | + heap->arr[heap->size] = value; |
| 136 | + heapify_up(heap, heap->size); |
| 137 | + heap->size++; |
| 138 | + return true; |
| 139 | +} |
| 140 | + |
| 141 | +/** |
| 142 | + * @brief Extract the minimum value from the heap |
| 143 | + * @param heap pointer to the heap |
| 144 | + * @param out pointer to store the extracted value |
| 145 | + * @returns true if extraction succeeded, false if heap is empty |
| 146 | + */ |
| 147 | +bool min_heap_extract_min(struct min_binary_heap *heap, int *out) |
| 148 | +{ |
| 149 | + if (!heap || heap->size == 0) |
| 150 | + return false; |
| 151 | + if (out) |
| 152 | + *out = heap->arr[0]; |
| 153 | + heap->arr[0] = heap->arr[heap->size - 1]; |
| 154 | + heap->size--; |
| 155 | + heapify_down(heap, 0); |
| 156 | + return true; |
| 157 | +} |
| 158 | + |
| 159 | +/** |
| 160 | + * @brief Get the minimum value from the heap without removing it |
| 161 | + * @param heap pointer to the heap |
| 162 | + * @param out pointer to store the minimum value |
| 163 | + * @returns true if heap is not empty, false otherwise |
| 164 | + */ |
| 165 | +bool min_heap_peek(const struct min_binary_heap *heap, int *out) |
| 166 | +{ |
| 167 | + if (!heap || heap->size == 0) |
| 168 | + return false; |
| 169 | + if (out) |
| 170 | + *out = heap->arr[0]; |
| 171 | + return true; |
| 172 | +} |
| 173 | + |
| 174 | +/** |
| 175 | + * @brief Search for a value in the heap (linear search) |
| 176 | + * @param heap pointer to the heap |
| 177 | + * @param value value to search for |
| 178 | + * @returns true if value is found, false otherwise |
| 179 | + */ |
| 180 | +bool min_heap_search(const struct min_binary_heap *heap, int value) |
| 181 | +{ |
| 182 | + if (!heap) |
| 183 | + return false; |
| 184 | + for (size_t i = 0; i < heap->size; ++i) |
| 185 | + { |
| 186 | + if (heap->arr[i] == value) |
| 187 | + return true; |
| 188 | + } |
| 189 | + return false; |
| 190 | +} |
| 191 | + |
| 192 | +/** |
| 193 | + * @brief Display the heap elements in array order |
| 194 | + * @param heap pointer to the heap |
| 195 | + */ |
| 196 | +void min_heap_display(const struct min_binary_heap *heap) |
| 197 | +{ |
| 198 | + if (!heap) |
| 199 | + return; |
| 200 | + printf("Heap elements: "); |
| 201 | + for (size_t i = 0; i < heap->size; ++i) printf("%d ", heap->arr[i]); |
| 202 | + printf("\n"); |
| 203 | +} |
| 204 | + |
| 205 | +/** |
| 206 | + * @brief Self-test implementations for Min Binary Heap |
| 207 | + * @returns void |
| 208 | + */ |
| 209 | +static void test_min_binary_heap() |
| 210 | +{ |
| 211 | + struct min_binary_heap *heap = min_heap_create(4); |
| 212 | + assert(heap != NULL); |
| 213 | + |
| 214 | + // Test insertion |
| 215 | + assert(min_heap_insert(heap, 10)); |
| 216 | + assert(min_heap_insert(heap, 4)); |
| 217 | + assert(min_heap_insert(heap, 15)); |
| 218 | + assert(min_heap_insert(heap, 20)); |
| 219 | + assert(min_heap_insert(heap, 0)); // triggers resize |
| 220 | + |
| 221 | + // Test display (should be in heap order, not sorted) |
| 222 | + min_heap_display(heap); |
| 223 | + |
| 224 | + // Test search |
| 225 | + assert(min_heap_search(heap, 10) == true); |
| 226 | + assert(min_heap_search(heap, 99) == false); |
| 227 | + |
| 228 | + // Test peek |
| 229 | + int min_val = -1; |
| 230 | + assert(min_heap_peek(heap, &min_val)); |
| 231 | + assert(min_val == 0); |
| 232 | + |
| 233 | + // Test extract min |
| 234 | + int extracted = -1; |
| 235 | + assert(min_heap_extract_min(heap, &extracted)); |
| 236 | + assert(extracted == 0); |
| 237 | + |
| 238 | + assert(min_heap_peek(heap, &min_val)); |
| 239 | + assert(min_val == 4); |
| 240 | + |
| 241 | + // Extract all and check order |
| 242 | + int prev = -1; |
| 243 | + while (heap->size > 0) |
| 244 | + { |
| 245 | + assert(min_heap_extract_min(heap, &extracted)); |
| 246 | + if (prev != -1) |
| 247 | + assert(prev <= extracted); // Should be non-decreasing |
| 248 | + prev = extracted; |
| 249 | + } |
| 250 | + |
| 251 | + // Heap should be empty now |
| 252 | + assert(min_heap_peek(heap, &min_val) == false); |
| 253 | + |
| 254 | + min_heap_destroy(heap); |
| 255 | + |
| 256 | + printf("All Min Binary Heap tests have successfully passed!\n"); |
| 257 | +} |
| 258 | + |
| 259 | +/** |
| 260 | + * @brief Main function |
| 261 | + * @returns 0 on exit |
| 262 | + */ |
| 263 | +int main(void) |
| 264 | +{ |
| 265 | + test_min_binary_heap(); // run self-test implementations |
| 266 | + return 0; |
| 267 | +} |
0 commit comments