Skip to content

Heap Sort

Overview

Heap Sort is a comparison-based sorting algorithm that uses a binary heap data structure to efficiently sort elements in-place. It works by building a max heap from the input array, then repeatedly extracting the maximum element and placing it at the end of the sorted portion.

How It Works

The heap sort algorithm consists of two main phases:

Phase 1: Build Max Heap 1. Start with an unsorted array and treat it as a complete binary tree 2. Apply the heapify operation starting from the last non-leaf node up to the root 3. Heapify ensures that each parent node is greater than or equal to its children (max heap property) 4. After this phase, the largest element is at the root (index 0)

Phase 2: Extract Elements 1. Swap the root (maximum element) with the last element in the heap 2. Reduce the heap size by 1 (excluding the sorted element) 3. Heapify the root to restore the max heap property 4. Repeat steps 1-3 until the heap size is 1 5. The array is now sorted in ascending order

Complexities

Best Case - O(n log n) Average Case - O(n log n) Worst Case - O(n log n) Space - O(1) auxiliary space (in-place sorting)

When to Use

Advantages: - Guaranteed O(n log n) time complexity in all cases, making performance predictable - In-place sorting with O(1) auxiliary space complexity - No worst-case quadratic time behavior like Quick Sort - Useful for finding the k largest or smallest elements efficiently - Not affected by initial ordering of elements

Disadvantages: - Not stable (does not preserve relative order of equal elements) - Generally slower in practice than Quick Sort due to poor cache locality - More complex to implement than simpler algorithms like Insertion Sort - Not adaptive - doesn't take advantage of existing order in the data

Best suited for: - Systems with limited memory where in-place sorting is critical - Situations requiring guaranteed O(n log n) performance - Priority queue implementations - Finding top-k elements in a dataset - Embedded systems or real-time systems with strict performance guarantees

Example Walkthrough

Sorting the array [5, 2, 8, 1, 9] using Heap Sort:

Initial array: [5, 2, 8, 1, 9]

Phase 1: Build Max Heap
Array indices:  0  1  2  3  4
Tree structure:     5
                   / \
                  2   8
                 / \
                1   9

Step 1: Heapify subtree at index 1 (node 2)
  - Compare 2 with children 1 and 9
  - Swap 2 with 9 (larger child)
  - Array: [5, 9, 8, 1, 2]

Step 2: Heapify subtree at index 0 (node 5)
  - Compare 5 with children 9 and 8
  - Swap 5 with 9 (larger child)
  - Array: [9, 5, 8, 1, 2]
  - Heapify subtree at index 1 again
  - Compare 5 with children 1 and 2
  - No swap needed (5 > 1 and 5 > 2)

Max heap built: [9, 5, 8, 1, 2]
Tree:           9
               / \
              5   8
             / \
            1   2

Phase 2: Extract Elements and Sort
Step 1: Swap 9 with last element (2), reduce heap size
  - Array: [2, 5, 8, 1 | 9]
  - Heapify root: [8, 5, 2, 1 | 9]

Step 2: Swap 8 with last element (1), reduce heap size
  - Array: [1, 5, 2 | 8, 9]
  - Heapify root: [5, 1, 2 | 8, 9]

Step 3: Swap 5 with last element (2), reduce heap size
  - Array: [2, 1 | 5, 8, 9]
  - Heapify root: [2, 1 | 5, 8, 9]

Step 4: Swap 2 with last element (1), reduce heap size
  - Array: [1 | 2, 5, 8, 9]

Final sorted array: [1, 2, 5, 8, 9]

Implementation(s)

Python:

def heap_sort(arr):
    """
    Sorts an array in ascending order using heap sort algorithm.

    Args:
        arr: List of comparable elements to sort

    Returns:
        The sorted array (modifies in-place)
    """
    n = len(arr)

    # Build max heap (rearrange array)
    # Start from last non-leaf node and heapify each node
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # Extract elements from heap one by one
    for i in range(n - 1, 0, -1):
        # Move current root (maximum) to end
        arr[0], arr[i] = arr[i], arr[0]

        # Heapify the reduced heap
        heapify(arr, i, 0)

    return arr


def heapify(arr, n, i):
    """
    Heapifies a subtree rooted at index i.

    Args:
        arr: The array representing the heap
        n: Size of the heap
        i: Index of the root of the subtree to heapify
    """
    largest = i  # Initialize largest as root
    left = 2 * i + 1  # Left child
    right = 2 * i + 2  # Right child

    # Check if left child exists and is greater than root
    if left < n and arr[left] > arr[largest]:
        largest = left

    # Check if right child exists and is greater than current largest
    if right < n and arr[right] > arr[largest]:
        largest = right

    # If largest is not root, swap and continue heapifying
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]

        # Recursively heapify the affected subtree
        heapify(arr, n, largest)


# Example usage
if __name__ == "__main__":
    arr = [5, 2, 8, 1, 9]
    print(f"Original array: {arr}")
    heap_sort(arr)
    print(f"Sorted array: {arr}")


Up