|
| 1 | +/** |
| 2 | + * @file Min Binary Heap.c |
| 3 | + * @brief Implementation of a Min Binary Heap using a dynamic array in C. |
| 4 | + * * A Min Heap is a complete binary tree where the value of each node is less |
| 5 | + * than or equal to the values of its children. The smallest element is always |
| 6 | + * at the root. This implementation supports: Insert, Extract Min, Peek Min, |
| 7 | + * Search, and Display. It uses dynamic memory management to create and destroy |
| 8 | + * the heap structure. |
| 9 | + */ |
| 10 | + |
| 11 | +#include <limits.h> // For INT_MAX (used for error checking/sentinel value) |
| 12 | +#include <stdio.h> |
| 13 | +#include <stdlib.h> |
| 14 | + |
| 15 | +// --- STRUCTURE DEFINITION --- |
| 16 | + |
| 17 | +/** |
| 18 | + * @brief Represents the Min Heap structure. |
| 19 | + * * The heap is stored in a 0-indexed array where: |
| 20 | + * Parent(i) = (i - 1) / 2 |
| 21 | + * LeftChild(i) = 2 * i + 1 |
| 22 | + * RightChild(i) = 2 * i + 2 |
| 23 | + */ |
| 24 | +typedef struct MinHeap |
| 25 | +{ |
| 26 | + int* arr; // Pointer to the dynamic array holding the heap elements |
| 27 | + int size; // Current number of elements in the heap |
| 28 | + int capacity; // Maximum number of elements the array can hold |
| 29 | +} MinHeap; |
| 30 | + |
| 31 | +// --- UTILITY FUNCTIONS --- |
| 32 | + |
| 33 | +/** |
| 34 | + * @brief Swaps two integer values. |
| 35 | + */ |
| 36 | +void swap(int* a, int* b) |
| 37 | +{ |
| 38 | + int temp = *a; |
| 39 | + *a = *b; |
| 40 | + *b = temp; |
| 41 | +} |
| 42 | + |
| 43 | +/** |
| 44 | + * @brief Calculates the index of the parent node. |
| 45 | + */ |
| 46 | +int parent(int i) { return (i - 1) / 2; } |
| 47 | + |
| 48 | +/** |
| 49 | + * @brief Calculates the index of the left child. |
| 50 | + */ |
| 51 | +int left_child(int i) { return 2 * i + 1; } |
| 52 | + |
| 53 | +/** |
| 54 | + * @brief Calculates the index of the right child. |
| 55 | + */ |
| 56 | +int right_child(int i) { return 2 * i + 2; } |
| 57 | + |
| 58 | +// --- HEAP LIFE CYCLE MANAGEMENT --- |
| 59 | + |
| 60 | +/** |
| 61 | + * @brief Creates a new MinHeap structure with a given capacity. |
| 62 | + * @param capacity The maximum number of elements the heap can hold. |
| 63 | + * @return Pointer to the newly created MinHeap. |
| 64 | + */ |
| 65 | +MinHeap* createMinHeap(int capacity) |
| 66 | +{ |
| 67 | + // Allocate memory for the structure itself |
| 68 | + MinHeap* h = (MinHeap*)malloc(sizeof(MinHeap)); |
| 69 | + if (h == NULL) |
| 70 | + { |
| 71 | + perror("Failed to allocate MinHeap structure"); |
| 72 | + exit(EXIT_FAILURE); |
| 73 | + } |
| 74 | + |
| 75 | + // Set properties |
| 76 | + h->capacity = capacity; |
| 77 | + h->size = 0; |
| 78 | + |
| 79 | + // Allocate memory for the underlying array |
| 80 | + h->arr = (int*)malloc(capacity * sizeof(int)); |
| 81 | + if (h->arr == NULL) |
| 82 | + { |
| 83 | + perror("Failed to allocate array memory"); |
| 84 | + free(h); // Clean up the structure memory |
| 85 | + exit(EXIT_FAILURE); |
| 86 | + } |
| 87 | + |
| 88 | + return h; |
| 89 | +} |
| 90 | + |
| 91 | +/** |
| 92 | + * @brief Frees the memory allocated for the MinHeap. |
| 93 | + * @param h Pointer to the MinHeap to be destroyed. |
| 94 | + */ |
| 95 | +void destroyMinHeap(MinHeap* h) |
| 96 | +{ |
| 97 | + if (h == NULL) |
| 98 | + return; |
| 99 | + free(h->arr); // Free the dynamic array first |
| 100 | + free(h); // Free the structure memory |
| 101 | + printf("\nMinHeap successfully destroyed. Memory freed.\n"); |
| 102 | +} |
| 103 | + |
| 104 | +// --- HEAP PROPERTY MAINTENANCE --- |
| 105 | + |
| 106 | +/** |
| 107 | + * @brief Corrects the Min Heap property by moving the element at index i DOWN |
| 108 | + * the tree. This is primarily used after Extract Min. Time Complexity: O(log n) |
| 109 | + * @param h Pointer to the MinHeap. |
| 110 | + * @param i The index of the element to heapify down. |
| 111 | + */ |
| 112 | +void heapify_down(MinHeap* h, int i) |
| 113 | +{ |
| 114 | + int l = left_child(i); |
| 115 | + int r = right_child(i); |
| 116 | + int smallest = i; // Assume current node is the smallest |
| 117 | + |
| 118 | + // Check if left child exists and is smaller than the current smallest |
| 119 | + if (l < h->size && h->arr[l] < h->arr[smallest]) |
| 120 | + { |
| 121 | + smallest = l; |
| 122 | + } |
| 123 | + |
| 124 | + // Check if right child exists and is smaller than the current smallest |
| 125 | + if (r < h->size && h->arr[r] < h->arr[smallest]) |
| 126 | + { |
| 127 | + smallest = r; |
| 128 | + } |
| 129 | + |
| 130 | + // If the smallest is not the current node, swap and recursively move down |
| 131 | + if (smallest != i) |
| 132 | + { |
| 133 | + swap(&h->arr[i], &h->arr[smallest]); |
| 134 | + heapify_down(h, smallest); |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +/** |
| 139 | + * @brief Corrects the Min Heap property by moving the element at index i UP the |
| 140 | + * tree. This is primarily used after Insert. Time Complexity: O(log n) |
| 141 | + * @param h Pointer to the MinHeap. |
| 142 | + * @param i The index of the element to heapify up. |
| 143 | + */ |
| 144 | +void heapify_up(MinHeap* h, int i) |
| 145 | +{ |
| 146 | + // Check if current node is not root AND if element is smaller than its |
| 147 | + // parent |
| 148 | + while (i > 0 && h->arr[parent(i)] > h->arr[i]) |
| 149 | + { |
| 150 | + // Swap the current element with its parent |
| 151 | + swap(&h->arr[parent(i)], &h->arr[i]); |
| 152 | + |
| 153 | + // Move up to the parent's index and repeat |
| 154 | + i = parent(i); |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +// --- CORE HEAP OPERATIONS --- |
| 159 | + |
| 160 | +/** |
| 161 | + * @brief Inserts a new key into the MinHeap. |
| 162 | + * Time Complexity: O(log n) |
| 163 | + * @param h Pointer to the MinHeap. |
| 164 | + * @param key The value to be inserted. |
| 165 | + */ |
| 166 | +void insert(MinHeap* h, int key) |
| 167 | +{ |
| 168 | + if (h->size == h->capacity) |
| 169 | + { |
| 170 | + printf("Error: Heap is full (Capacity: %d). Cannot insert %d.\n", |
| 171 | + h->capacity, key); |
| 172 | + return; |
| 173 | + } |
| 174 | + |
| 175 | + // 1. Place the new element at the next available spot (end of the array) |
| 176 | + h->size++; |
| 177 | + int i = h->size - 1; |
| 178 | + h->arr[i] = key; |
| 179 | + |
| 180 | + // 2. Restore the heap property by moving the element up |
| 181 | + heapify_up(h, i); |
| 182 | + printf("Inserted %d. Heap size: %d\n", key, h->size); |
| 183 | +} |
| 184 | + |
| 185 | +/** |
| 186 | + * @brief Removes and returns the minimum element (root) from the MinHeap. |
| 187 | + * Time Complexity: O(log n) |
| 188 | + * @param h Pointer to the MinHeap. |
| 189 | + * @return The minimum element, or INT_MAX if the heap is empty. |
| 190 | + */ |
| 191 | +int extract_min(MinHeap* h) |
| 192 | +{ |
| 193 | + if (h->size <= 0) |
| 194 | + { |
| 195 | + printf("Error: Heap is empty. Cannot extract.\n"); |
| 196 | + return INT_MAX; |
| 197 | + } |
| 198 | + |
| 199 | + // 1. Store the minimum element (root) |
| 200 | + int root = h->arr[0]; |
| 201 | + |
| 202 | + // 2. Replace the root with the last element |
| 203 | + h->arr[0] = h->arr[h->size - 1]; |
| 204 | + |
| 205 | + // 3. Decrease the size |
| 206 | + h->size--; |
| 207 | + |
| 208 | + // 4. Restore the heap property by moving the new root down |
| 209 | + heapify_down(h, 0); |
| 210 | + |
| 211 | + return root; |
| 212 | +} |
| 213 | + |
| 214 | +/** |
| 215 | + * @brief Returns the minimum element (root) without removing it. |
| 216 | + * Time Complexity: O(1) |
| 217 | + * @param h Pointer to the MinHeap. |
| 218 | + * @return The minimum element, or INT_MAX if the heap is empty. |
| 219 | + */ |
| 220 | +int peek_min(MinHeap* h) |
| 221 | +{ |
| 222 | + if (h->size <= 0) |
| 223 | + { |
| 224 | + printf("Error: Heap is empty.\n"); |
| 225 | + return INT_MAX; |
| 226 | + } |
| 227 | + return h->arr[0]; // Simply return the root element |
| 228 | +} |
| 229 | + |
| 230 | +/** |
| 231 | + * @brief Performs a linear search for a key in the heap. |
| 232 | + * Time Complexity: O(n) |
| 233 | + * @param h Pointer to the MinHeap. |
| 234 | + * @param key The value to search for. |
| 235 | + * @return The array index of the key if found, or -1 otherwise. |
| 236 | + */ |
| 237 | +int search(MinHeap* h, int key) |
| 238 | +{ |
| 239 | + // Linear search through the underlying array |
| 240 | + for (int i = 0; i < h->size; i++) |
| 241 | + { |
| 242 | + if (h->arr[i] == key) |
| 243 | + { |
| 244 | + return i; // Found at index i |
| 245 | + } |
| 246 | + } |
| 247 | + return -1; // Not found |
| 248 | +} |
| 249 | + |
| 250 | +/** |
| 251 | + * @brief Prints all elements of the heap in array order (not tree order). |
| 252 | + * Time Complexity: O(n) |
| 253 | + * @param h Pointer to the MinHeap. |
| 254 | + */ |
| 255 | +void display(MinHeap* h) |
| 256 | +{ |
| 257 | + if (h->size == 0) |
| 258 | + { |
| 259 | + printf("Heap is empty.\n"); |
| 260 | + return; |
| 261 | + } |
| 262 | + printf("Current Heap elements (Array Order, size=%d): ", h->size); |
| 263 | + for (int i = 0; i < h->size; i++) |
| 264 | + { |
| 265 | + printf("%d ", h->arr[i]); |
| 266 | + } |
| 267 | + printf("\n"); |
| 268 | +} |
| 269 | + |
| 270 | +// --- MAIN FUNCTION FOR DEMONSTRATION --- |
| 271 | + |
| 272 | +int main() |
| 273 | +{ |
| 274 | + // Define the initial capacity |
| 275 | + int capacity = 10; |
| 276 | + MinHeap* heap = createMinHeap(capacity); |
| 277 | + |
| 278 | + printf("--- Min Binary Heap Demonstration ---\n"); |
| 279 | + printf("1. Initializing Heap with Capacity: %d\n", capacity); |
| 280 | + |
| 281 | + // 2. Insert Operations |
| 282 | + printf("\n2. Inserting elements: 10, 5, 20, 2, 4, 8\n"); |
| 283 | + insert(heap, 10); |
| 284 | + insert(heap, 5); |
| 285 | + insert(heap, 20); |
| 286 | + insert(heap, 2); |
| 287 | + insert(heap, 4); |
| 288 | + insert(heap, 8); |
| 289 | + display(heap); |
| 290 | + // Expected Array Order: [2, 4, 8, 10, 5, 20] (Min Heap Property satisfied) |
| 291 | + |
| 292 | + // 3. Peek Min Operation (O(1)) |
| 293 | + printf("\n3. Peek Min (O(1)): %d\n", peek_min(heap)); |
| 294 | + display(heap); |
| 295 | + |
| 296 | + // 4. Extract Min Operations (O(log n)) |
| 297 | + int min1 = extract_min(heap); |
| 298 | + printf("\n4. Extracted Min (O(log n)): %d\n", min1); |
| 299 | + display(heap); |
| 300 | + |
| 301 | + int min2 = extract_min(heap); |
| 302 | + printf("Extracted Min: %d\n", min2); |
| 303 | + display(heap); |
| 304 | + |
| 305 | + // 5. Search Operation (O(n)) |
| 306 | + int search_val = 10; |
| 307 | + int index = search(heap, search_val); |
| 308 | + if (index != -1) |
| 309 | + { |
| 310 | + printf("5. Search: Value %d found at array index %d.\n", search_val, |
| 311 | + index); |
| 312 | + } |
| 313 | + else |
| 314 | + { |
| 315 | + printf("5. Search: Value %d not found.\n", search_val); |
| 316 | + } |
| 317 | + |
| 318 | + search_val = 99; |
| 319 | + index = search(heap, search_val); |
| 320 | + if (index != -1) |
| 321 | + { |
| 322 | + printf("5. Search: Value %d found at array index %d.\n", search_val, |
| 323 | + index); |
| 324 | + } |
| 325 | + else |
| 326 | + { |
| 327 | + printf("5. Search: Value %d not found.\n", search_val); |
| 328 | + } |
| 329 | + |
| 330 | + // 6. Final cleanup (Crucial for memory management) |
| 331 | + destroyMinHeap(heap); |
| 332 | + |
| 333 | + return 0; |
| 334 | +} |
0 commit comments