Min Heap
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LEN 10 // 9 chars + 1 null terminator
typedef struct Student {
int ID;
char name[MAX_NAME_LEN];
} Student;
typedef struct Heap {
Student **students;
int capacity;
int size;
} Heap;
// Function prototypes
Student *initStudent(char *name, int ID);
Heap *initHeap(Student **students, int size);
Heap *heapify(Student **students, int size);
void percolateDown(Student **students, int size, int idx);
void percolateUp(Student **students, int idx);
void swap(Student **stud1, Student **stud2);
int doubleCapacity(Heap *heap);
void insert(Heap *heap, Student *newStudent);
Student *removeMin(Heap *heap);
void printStudents(Student **students, int size);
void freeHeap(Heap *heap);
// Initializes and returns new student
Student *initStudent(char *name, int ID) {
Student *student = malloc(sizeof(Student));
strcpy(student->name, name);
student->ID = ID;
return student;
}
// Helper function for Heapify
// Takes in heap formatted array and heap data and returns initialized heap
Heap *initHeap(Student **students, int size) {
Heap *heap = malloc(sizeof(Heap));
heap->size = size;
Student **temp = realloc(students, sizeof(Student *) * (2 * size + 1));
heap->capacity = size;
if (temp) {
students = temp;
heap->capacity *= 2;
}
heap->students = students;
return heap;
}
// Takes an existing array of students and converts/ returns heap
// Initializes heap->capacity with current size * 2 if realloc is successful
// Assumes existing array holds garbage value at 0 (1-based array / heap)
Heap *heapify(Student **students, int size) {
if (!students)
return NULL;
for (int i = size / 2; i > 0; i--) {
percolateDown(students, size, i);
}
return initHeap(students, size);
}
// Keeps swapping nodes downwards to enforce min-heap constraints
// Finds child with smallest ID, swaps if that childs ID is less than ID at
// current node Recursively calls downwards after swap
void percolateDown(Student **students, int size, int idx) {
if (idx > size)
return;
if (idx * 2 + 1 <= size) {
int smallerIDIdx = (students[idx * 2]->ID < students[idx * 2 + 1]->ID)
? (idx * 2)
: (idx * 2 + 1);
if (students[smallerIDIdx]->ID < students[idx]->ID) {
swap(students + idx, students + smallerIDIdx);
percolateDown(students, size, smallerIDIdx);
}
} else if ((idx * 2 <= size)) {
if (students[idx * 2]->ID < students[idx]->ID) {
swap(students + idx, students + idx * 2);
percolateDown(students, size, idx * 2);
}
}
}
// Keeps swapping nodes upwards to enforce min-heap constraints
// swaps if ID at current node is less than the parent node's ID
// Recursively calls upwards after swap
void percolateUp(Student **students, int idx) {
if (idx / 2 <= 0)
return;
if (students[idx]->ID < students[idx / 2]->ID) {
swap(students + idx, students + (idx / 2));
percolateUp(students, (idx / 2));
}
}
// Swap two students in Student pointer array
void swap(Student **stud1, Student **stud2) {
Student *temp = *stud1;
*stud1 = *stud2;
*stud2 = temp;
}
// Attempts to double capacity of heap
// Updates heap->capacity if successful and returns 1
// Returns 0 if realloc fails
int doubleCapacity(Heap *heap) {
Student **temp =
realloc(heap->students, sizeof(Student *) * (heap->capacity * 2 + 1));
if (!temp)
return 0;
heap->students = temp;
heap->capacity *= 2;
return 1;
}
// Resizes heap->students if heap is full
// Increments heap->size
// Adds student to end next available array index
// NOTE: By doing this, heap maintains property of a complete tree
// Calls percolate up at newly added node
void insert(Heap *heap, Student *newStudent) {
if (heap->size == heap->capacity) {
if (!doubleCapacity(heap)) {
printf("\nFailed to add student to heap.\n");
return;
}
}
heap->students[++heap->size] = newStudent;
percolateUp(heap->students, heap->size);
printf("\nAdded %s to the heap.\n", newStudent->name);
}
// Stores the first student from the first index
// Moves last student in array to the front
// Decrement heap->size
// Call percolate down from the first node in heap
// Return stored student
Student *removeMin(Heap *heap) {
if (heap->size == 0)
return NULL;
Student *minStudent = heap->students[1];
heap->students[1] = heap->students[heap->size];
heap->students[heap->size] = NULL;
heap->size--;
percolateDown(heap->students, heap->size, 1);
return minStudent;
}
// Prints all students in a heap with corresponding index
void printStudents(Student **students, int size) {
for (int i = 1; i <= size; i++)
printf("%2d) %-9s - %-3d\n", i, students[i]->name, students[i]->ID);
printf("\n");
}
// Frees all memory associated with heap
void freeHeap(Heap *heap) {
for (int i = 1; i <= heap->size; i++) {
free(heap->students[i]);
}
free(heap->students);
free(heap);
}
int main() {
/*
The following code does the following:
Creates an array of students with assigned names and IDs
Creates a min-heap that calls heapify on this array
NOTE: Purpose of heapify
Inserting each element of array into an empty heap directly
would be an O(nlogn). By using heapify on an existing array,
converting to a heap turns into an O(n) operation.
Adds a new student is inserted into the heap
Removes the minimum student from the heap
Then frees all allocated memory
Time complexity:
- heapify : O(n)
- insert : O(logn)
- removeMin : O(logn)
*/
int numStudents = 10;
Student **students = malloc(sizeof(Student *) * (numStudents + 1));
students[0] = NULL; // 1-based array | idx 0 is not used
char *names[] = {"Bobby", "Billy", "Jamie", "Oliver", "Rebecca",
"Julia", "Jared", "Ralph", "Hannah", "Natasha"};
for (int i = 1; i <= numStudents; i++) {
int ID = rand() % 255 + 1; // Random ID in inclusive range [1,255]
students[i] = initStudent(names[i - 1], ID);
}
printf("STUDENTS BEFORE HEAPIFY:\n");
printStudents(students, numStudents);
Heap *heap = heapify(students, numStudents);
printf("STUDENTS AFTER HEAPIFY:\n");
printStudents(heap->students, heap->size);
printf("NOTE:\nHeapify does not sort the array.\n"
"It restructures the array with binary min-heap properties.\n"
"i.e. Each parent has an ID less than or equal to its children.\n");
printf("\nTRACE EXAMPLE:\nID at index 1 less than ID at index 2 and 3\n"
"ID at index 2 less than ID at index 4 and 5\n"
"ID at index 3 less than ID at index 6 and 7\n"
"And so on...\nRemember children of index i are found at\n"
"indexes (2 * i) and (2 * i + 1)\n");
printf("\nAttempting to add student:\n"
"Name: Johnny\nID: 98\n");
Student *newStudent = initStudent("Johnny", 98);
insert(heap, newStudent);
printf("\nSTUDENTS AFTER ADDING JOHNNY:\n");
printStudents(heap->students, heap->size);
printf("\nRemoving student with smallest ID:\n");
Student *minStudent = removeMin(heap);
if (!minStudent)
printf("\nHeap is empty\n");
else {
printf("\n%s has been removed from the heap\n", minStudent->name);
printf("\nSTUDENTS AFTER REMOVING MIN:\n");
printStudents(heap->students, heap->size);
free(minStudent);
}
freeHeap(heap);
return 0;
}
Academic Notice: The code shown here is provided solely as a learning reference. Copying and pasting is intentionally disabled to encourage independent practice. Students should implement solutions on their own to demonstrate understanding. This material is not intended for direct submission in assignments.
Additionally: This code was written by a former CS1 student and may not reflect your professor’s intended solution or instructional approach. For coursework, students are expected to follow examples, conventions, and requirements presented in class and in professor-assigned materials.