AlgoMaster Logo

Heap Sort

Medium Priority11 min readUpdated July 10, 2026
Listen to this chapter
Unlock Audio

Heap Sort is a comparison-based sorting algorithm that uses the properties of a heap, a specialized binary tree structure. It first builds a heap from the input array, then repeatedly extracts the maximum (or minimum) element and places it at its correct position.

A heap allows efficient access to the largest or smallest element, so each extraction step runs in O(log n). This produces a consistent time complexity of O(n log n), regardless of the input.

Loading simulation...

Heap Sort is not stable, but it is in-place and does not require extra memory like Merge Sort, which makes it useful in memory-constrained environments.

This chapter covers how heaps work, how to build and maintain them, and how Heap Sort uses these operations to sort an array.

What Is Heap Sort?

The core idea: if the maximum element can be found and removed efficiently, the array can be sorted by repeatedly extracting the max and placing it at the end. This depends on the underlying data structure, the heap.

The Max-Heap Property

A max-heap is a complete binary tree where every parent node is greater than or equal to its children. The root of the tree always holds the largest element. This property applies recursively, so every subtree is also a valid max-heap.

Here is what a max-heap looks like:

The root (10) is larger than both children (5, 3). Node 5 is larger than both of its children (4, 1). Every parent dominates its children, which is exactly the max-heap property.

Array Representation

A binary heap does not need pointers or tree nodes. A simple array stores the tree level by level, left to right. For any element at index i:

  • Parent is at index (i - 1) / 2
  • Left child is at index 2 * i + 1
  • Right child is at index 2 * i + 2

The tree above maps to an array like this:

Index 0 holds the root (10). Its left child is at index 1 (value 5), and its right child is at index 2 (value 3). The node at index 1 has children at indices 3 and 4. The flat array encodes the tree structure implicitly, with no extra memory or pointer overhead.

This array-based representation is what makes heap sort an in-place algorithm. The input array itself is rearranged into a heap and then sorted, all without allocating additional storage.

How Heap Sort Works

The algorithm has two main phases:

  1. Build a max-heap from the unsorted array.
  2. Extract elements one by one from the heap to produce the sorted order.

Each phase in detail:

Phase 1: Build the Max-Heap

The input array must be rearranged to satisfy the max-heap property. The key operation is heapify (also called sift-down), which takes a node that might violate the heap property and pushes it down to its correct position.

How heapify works:

  1. Compare the node with its left and right children.
  2. If the largest value is not the node itself, swap the node with its largest child.
  3. Repeat from the new position until the node is larger than both children or reaches a leaf.

Building the entire heap calls heapify on every non-leaf node, starting from the bottom of the tree and working upward. Leaf nodes (the bottom half of the array) are already valid heaps because they have no children that could violate the heap property. The build phase starts from the last non-leaf node, which is at index (n / 2) - 1.

Why bottom-up and not top-down? Starting from the root and working down would require each heapify call to push elements through the entire height of the tree. Starting from the bottom means most nodes are near the leaves where the tree is short, which is why building a heap takes O(n) time instead of O(n log n). The Complexity Analysis section derives this in detail.

Phase 2: Extract Elements

Once the max-heap is built, the largest element sits at index 0 (the root). To sort the array:

  1. Swap the root (largest element) with the last element in the heap.
  2. Shrink the heap size by one (the last element is now in its final sorted position).
  3. Heapify the root to restore the max-heap property.
  4. Repeat until the heap has one element left.

Each extraction places the next-largest element at the end of the array. After all extractions, the array is sorted in ascending order.

Each swap moves the largest remaining element to the back of the array. The heap occupies the front portion, and the sorted section grows from the back. Eventually the heap shrinks to nothing and the entire array is sorted.

Code Implementation

Loading animation...

The heapify function does the core comparison-and-swap work: it compares a node with its children, swaps with the largest if needed, and recurses down the tree. The heapSort function orchestrates the build phase and the extraction phase.

Example Walkthrough

Trace heap sort on the array [4, 10, 3, 5, 1].

Phase 1: Building the Max-Heap

The array has 5 elements, so the last non-leaf node is at index 5 / 2 - 1 = 1.

Initial array: [4, 10, 3, 5, 1]

The initial tree looks like this:

Step 1: Heapify index 1 (value 10)

Node 10 has children 5 (index 3) and 1 (index 4). Since 10 > 5 and 10 > 1, no swap is needed.

Array after step 1: [4, 10, 3, 5, 1] (unchanged)

Step 2: Heapify index 0 (value 4)

Node 4 has children 10 (index 1) and 3 (index 2). The largest is 10, so swap 4 and 10.

Array becomes: [10, 4, 3, 5, 1]

Recurse on index 1 (where 4 landed). Node 4 has children 5 (index 3) and 1 (index 4). The largest is 5, so swap 4 and 5.

Array becomes: [10, 5, 3, 4, 1]

Node 4 is now at index 3, which is a leaf. Done.

The max-heap is built:

Every parent is now greater than or equal to its children. The max-heap property is satisfied.

Phase 2: Extracting Elements

Extraction 1: Swap root (10) with last element (1). Reduce heap size to 4. Heapify root.

Extraction 2: Swap root (5) with last heap element (1). Reduce heap size to 3. Heapify root.

Extraction 3: Swap root (4) with last heap element (3). Reduce heap size to 2. Heapify root.

Extraction 4: Swap root (3) with last heap element (1). Reduce heap size to 1. Done.

Final sorted array: [1, 3, 4, 5, 10]

The pipe character | in the traces above separates the active heap (left) from the sorted portion (right). With each extraction, the heap shrinks and the sorted section grows until the entire array is in order.

Complexity Analysis

CaseTime ComplexityExplanation
BestO(n log n)Even if the array is already sorted, heap sort builds the heap and extracts all elements
AverageO(n log n)Each of the n extractions requires a heapify that takes O(log n)
WorstO(n log n)No input causes degradation; performance is the same for every input
SpaceO(1)In-place. Only a constant number of variables beyond the input array
StableNoEqual elements may change their relative order during swaps

Why Building a Heap Takes O(n)

A naive analysis counts n/2 heapify calls, each O(log n), giving O(n log n). That bound is loose because it ignores where the calls happen in the tree.

Most nodes are near the bottom of the tree, where heapify does little work. In a complete binary tree with n nodes:

  • About n/2 nodes are leaves (heapify does 0 work)
  • About n/4 nodes are one level above leaves (heapify does at most 1 swap)
  • About n/8 nodes are two levels above (at most 2 swaps)
  • The root is the only node that might need log(n) swaps

The total work is:

This series converges to a constant (approximately 2), so the total work is O(n).

Why the Extraction Phase Takes O(n log n)

The extraction phase performs n - 1 extractions. Each extraction involves a swap (O(1)) and a heapify from the root (O(log n)). Unlike the build phase, every heapify during extraction starts from the root and can travel all the way down to the leaves. The total is O(n log n).

Stability

Heap sort is not stable. Both phases swap elements across long distances. During the build phase, sift-down moves a node down through several levels, jumping past unrelated elements. During the extraction phase, the root swaps with the last heap element before re-heapifying, which can leap one equal element over another.

For example, with the input [2, 5a, 5b, 1], after building the max-heap the structure becomes something like [5a, 2, 5b, 1] or [5b, 5a, 2, 1] depending on the heapify path. Subsequent extractions place the values back into the array in the order they exit the heap, which is not guaranteed to match the original 5a, 5b order.

A stable variant is possible by tagging each element with its original index and using that as a tiebreaker in the heap comparison, but this adds O(n) auxiliary space and forfeits heap sort's main advantage over merge sort.

When to Use Heap Sort

Good for

  • Guaranteed O(n log n) worst case. Unlike quick sort, heap sort never degrades. For workloads that cannot tolerate O(n^2) on adversarial inputs, heap sort is a safe choice.
  • O(1) extra space. Unlike merge sort, heap sort does not need auxiliary arrays. When memory is tight, this matters.
  • Partial sorting. If only the k largest or smallest elements are needed, the extraction phase can stop early after k iterations, giving O(n + k log n) time. Priority queues use this property for top-k selection.
  • Embedded systems or real-time constraints. Predictable performance with minimal memory fits resource-constrained environments.

Not ideal for

  • General-purpose sorting. In practice, quick sort is faster due to better cache locality. Heap sort jumps around the array (parent to child indices), which causes frequent cache misses on modern hardware. Quick sort's partition scans access elements sequentially, which fits CPU cache prefetch behavior.
  • Stable sorting. Heap sort is not stable. Merge sort or Timsort is a better choice when equal elements must retain their original order.
  • Nearly sorted data. Insertion sort runs in O(n) on nearly sorted arrays. Heap sort does not benefit from existing order and always takes O(n log n).
  • Small arrays. The overhead of heap construction is not worth it for small inputs. Simple algorithms like insertion sort are faster for arrays under 20-30 elements.

Comparison with Other O(n log n) Sorts

PropertyHeap SortMerge SortQuick Sort
Worst-case timeO(n log n)O(n log n)O(n^2)
Average timeO(n log n)O(n log n)O(n log n)
Extra spaceO(1)O(n)O(log n) stack
StableNoYesNo (typically)
Cache-friendlyNoModerateYes
AdaptiveNoNoSomewhat
In practiceSlowest of the threeGood for linked listsFastest on average

Heap sort occupies a unique niche: it is the only comparison-based sort that offers both O(n log n) worst-case time and O(1) extra space. When both of those constraints matter simultaneously, heap sort fits.

Quiz

Heap Sort Quiz

10 quizzes