Heap Sort Algorithm in DSA C++ - Time & Space Complexity
We want to understand how the time taken by heap sort changes as the input size grows.
Specifically, how the number of steps increases when sorting more items.
Analyze the time complexity of the following heap sort code snippet.
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i) {
std::swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n - 1; i > 0; i--) {
std::swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
This code builds a max heap from the array, then repeatedly extracts the largest element to sort the array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The
heapifyfunction called multiple times to maintain the heap property. - How many times: First,
heapifyis called for each non-leaf node once (about n/2 times). Then, it is called once per element during sorting (n times), each possibly recursing down the tree.
As the input size grows, the number of operations grows roughly proportional to n times the height of the heap.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 30 to 40 heapify steps |
| 100 | About 700 to 800 heapify steps |
| 1000 | About 10,000 to 12,000 heapify steps |
Pattern observation: Operations grow a bit faster than linearly but much slower than quadratically, roughly like n times log n.
Time Complexity: O(n log n)
This means the time to sort grows a little more than linearly, multiplying the number of items by the height of the heap.
[X] Wrong: "Heap sort is just like bubble sort and takes O(n²) time because of nested loops."
[OK] Correct: Heap sort uses a tree structure and heapify steps that take logarithmic time, so it is much faster than simple nested loops.
Understanding heap sort's time complexity shows you can analyze algorithms that combine loops and recursion, a key skill in many coding challenges.
"What if we changed the heap from a max heap to a min heap? How would the time complexity change?"
Practice
Heap Sort Algorithm?Solution
Step 1: Understand heapify's role
Heapify rearranges elements to satisfy the heap property, making the array a max heap or min heap.Step 2: Connect heapify to heap sort
Heap sort uses heapify to build the heap before sorting by repeatedly extracting the root.Final Answer:
To build a max heap or min heap from an unordered array -> Option DQuick Check:
Heapify builds heap = A [OK]
- Thinking heapify sorts the array directly
- Confusing heapify with swapping elements
- Assuming heapify reverses the array
arr[i] and arr[j] in C++ during heap sort?Solution
Step 1: Recall C++ swap syntax
The standard way to swap two elements is using theswap()function with parentheses and commas.Step 2: Check each option
swap(arr[i], arr[j]); uses correct syntax. arr[i] = arr[j]; arr[j] = arr[i]; overwrites values incorrectly. swap arr[i], arr[j]; misses parentheses. arr.swap(i, j); is invalid method call.Final Answer:
swap(arr[i], arr[j]); -> Option CQuick Check:
Correct swap syntax = D [OK]
- Assigning values instead of swapping
- Missing parentheses in swap function
- Using non-existent swap methods
arr = [4, 10, 3, 5, 1]? Print the sorted array.Solution
Step 1: Build max heap from array
Max heap of [4,10,3,5,1] rearranges to [10,5,3,4,1].Step 2: Extract max and heapify repeatedly
Extract 10, heapify remaining; then 5, then 4, then 3, then 1 results in sorted ascending array [1,3,4,5,10].Final Answer:
[1, 3, 4, 5, 10] -> Option AQuick Check:
Heap sort ascending = [1,3,4,5,10] [OK]
- Confusing max heap with sorted array
- Reading heap array as sorted directly
- Outputting descending order instead
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2*i;
int right = 2*i + 1;
if (left < n && arr[left] > arr[largest]) largest = left;
if (right < n && arr[right] > arr[largest]) largest = right;
if (largest != i) {
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}Solution
Step 1: Check child index calculation
In 0-based arrays, left child = 2*i + 1, right child = 2*i + 2. Current code uses 2*i and 2*i + 1 which is incorrect.Step 2: Fix child indices
Changing left and right to 2*i + 1 and 2*i + 2 fixes indexing and prevents out-of-bound errors.Final Answer:
Change left and right to 2*i + 1 and 2*i + 2 respectively -> Option BQuick Check:
Child indices = 2*i+1, 2*i+2 [OK]
- Using 1-based indexing formulas in 0-based arrays
- Removing recursion breaks heapify
- Incorrect swap assignment instead of swap function
arr = [12, 11, 13, 5, 6, 7], how many times will the heapify function be called during the build heap phase of heap sort?Solution
Step 1: Understand build heap calls
Build heap calls heapify from last non-leaf node down to root. For array size 6, last non-leaf node is at index 2 (0-based).Step 2: Count heapify calls
Heapify called at indices 2, 1, 0 during build heap phase, totaling 3 calls. However, heapify may call itself recursively inside these calls. Counting only initial calls, it's 3.Step 3: Clarify question intent
If question means initial calls only, answer is 3. If counting recursive calls inside heapify, index 1 and 0 calls may cause extra heapify calls. For this array, heapify at index 1 calls heapify at index 4 (leaf, no call), index 0 calls heapify at index 1 again, so total calls are 4.Final Answer:
4 times -> Option AQuick Check:
Build heap calls heapify 3 + 1 recursive = 4 [OK]
- Counting only initial calls, ignoring recursion
- Confusing build heap with sorting phase calls
- Misidentifying last non-leaf node index
Ready to prove it?
Pass the test and this pattern moves unknown
