Heap Sort is an efficient, comparison-based sorting algorithm that uses a binary heap data structure to sort elements. It combines the speed of Quick Sort with the consistent performance of Merge Sort, making it an excellent choice for systems requiring guaranteed O(n log n) time complexity. In this guide, I’ll walk you through how Heap Sort works, where it shines, and provide code examples in Python and JavaScript to help you put theory into practice.
Before diving into Heap Sort, let's understand the heap data structure:
90 Max Heap Example
/ \
80 70
/ \ /
50 60 65
Heap Sort operates in two main phases:
Initial Array: [4, 10, 3, 5, 1]
Step 1 - Build Max Heap:
10
/ \
5 3
/ \
4 1
Step 2 - Extract Max:
1. [10, 5, 3, 4, 1] → [1, 5, 3, 4, |10]
2. [5, 4, 3, 1, |10] → [1, 4, 3, |5, 10]
3. [4, 1, 3, |5, 10] → [1, 3, |4, 5, 10]
4. [3, 1, |4, 5, 10] → [1, |3, 4, 5, 10]
Final Sorted Array: [1, 3, 4, 5, 10]
class HeapSort:
def __init__(self):
self.heap_size = 0
def heapify(self, arr, n, i):
"""
Maintain heap property for subtree rooted at index i.
Args:
arr: Array to heapify
n: Size of heap
i: Root index of subtree
"""
largest = i
left = 2 * i + 1
right = 2 * i + 2
# Compare with left child
if left < n and arr[left] > arr[largest]:
largest = left
# Compare with right child
if right < n and arr[right] > arr[largest]:
largest = right
# Swap if needed and recursively heapify
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
self.heapify(arr, n, largest)
def sort(self, arr):
"""
Sort array using Heap Sort algorithm.
Args:
arr: Array to sort
Returns:
Sorted array
"""
n = len(arr)
# Build max heap
for i in range(n // 2 - 1, -1, -1):
self.heapify(arr, n, i)
# Extract elements from heap
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
self.heapify(arr, i, 0)
return arr
class HeapSort {
constructor() {
this.heapSize = 0;
}
heapify(arr, n, i) {
let largest = i;
const left = 2 * i + 1;
const 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) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
this.heapify(arr, n, largest);
}
}
sort(arr) {
const n = arr.length;
// Build max heap
for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
this.heapify(arr, n, i);
}
// Extract elements from heap
for (let i = n - 1; i > 0; i--) {
[arr[0], arr[i]] = [arr[i], arr[0]];
this.heapify(arr, i, 0);
}
return arr;
}
}
Operation |
Time Complexity |
---|---|
Build Heap |
O(n) |
Heapify |
O(log n) |
Overall |
O(n log n) |
Algorithm |
Time (Avg) |
Time (Worst) |
Space |
Stable |
---|---|---|---|---|
Heap Sort |
O(n log n) |
O(n log n) |
O(1) |
No |
Quick Sort |
O(n log n) |
O(n²) |
O(log n) |
No |
Merge Sort |
O(n log n) |
O(n log n) |
O(n) |
Yes |
Bubble Sort |
O(n²) |
O(n²) |
O(1) |
Yes |
Priority Queues
class PriorityQueue(HeapSort):
def insert(self, item):
# Implementation details
Operating System Task Scheduling
External Sorting
def iterative_heapify(arr, n, i):
while True:
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest == i:
break
arr[i], arr[largest] = arr[largest], arr[i]
i = largest
Array Index Calculation
# Correct way
left = 2 * i + 1
right = 2 * i + 2
parent = (i - 1) // 2
Heap Size Management
Edge Cases
def handle_edge_cases(arr):
if not arr or len(arr) <= 1:
return arr
A: Heap Sort may change the relative order of equal elements due to the heap structure and extraction process.
A: Use Heap Sort when you need guaranteed O(n log n) performance and memory usage is a concern.
A: The heapify process can be partially parallelized, but the sequential nature of extraction limits full parallelization.