Insertion Sort

Build a sorted array one element at a time by inserting each into its correct position.

O(n²)Sorting
Phase 1f(x)

The Mathematics

Loop invariant, stability, and case analysis

Loop Invariant

At the start of each outer loop iteration ii, the subarray A[0..i1]A[0..i-1] consists of the elements originally in A[0..i1]A[0..i-1] but in sorted order:

Invariant: A[0]A[1]A[i1]\text{Invariant: } A[0] \leq A[1] \leq \cdots \leq A[i-1]

Each iteration takes element A[i]A[i] (the key) and inserts it into the correct position within the sorted prefix, extending the sorted region by one.

Complexity Analysis

The number of comparisons depends on the input order:

Best case (sorted): T(n)=O(n)\text{Best case (sorted): } T(n) = O(n)

Each key is already in place — inner loop never executes.

Worst case (reverse sorted): T(n)=O(n2)\text{Worst case (reverse sorted): } T(n) = O(n^2)

Each key shifts all the way to position 0: i=1n1i=n(n1)2\sum_{i=1}^{n-1} i = \frac{n(n-1)}{2}.

Average case: T(n)=O(n2)\text{Average case: } T(n) = O(n^2)

Expected comparisons: i=1n1i2=n(n1)4\sum_{i=1}^{n-1} \frac{i}{2} = \frac{n(n-1)}{4}.

Properties

Insertion sort has several useful properties:

\bullet Stable: equal elements maintain their relative order (compare with >>, not \geq)

\bullet In-place: uses only O(1)O(1) extra space

\bullet Adaptive: runs in O(n+d)O(n + d) where dd is the number of inversions

\bullet Online: can sort elements as they arrive

When to Use Insertion Sort

Optimal for small arrays (n20n \leq 20) or nearly-sorted data. Many hybrid algorithms (Timsort, introsort) use insertion sort as a subroutine for small partitions.

Phase 2

See It Work

Sorting [5, 2, 8, 1, 9, 3] by inserting each element into the sorted prefix

50key2182139435
Sorted Key Comparing
Invariant: A[0..0] is sorted\text{Invariant: } A[0..0] \text{ is sorted}
Step 1 of 11

Initialize: first element [5] is trivially sorted. Start from index 1.

Phase 3</>

The Code

Bridge from loop invariant to Python implementation

Mathematical Formulation

i=1,2,,n1i = 1, 2, \ldots, n-1

Outer loop extends the sorted region one element at a time

key=A[i]\text{key} = A[i]

Save the current element to insert into the sorted prefix

j0    A[j]>keyj \geq 0 \;\land\; A[j] > \text{key}

Inner loop finds where key belongs by scanning right to left

A[j+1]A[j]A[j+1] \leftarrow A[j]

Shift larger elements one position to the right

A[j+1]keyA[j+1] \leftarrow \text{key}

Place the key at its correct sorted position

Invariant: A[0..i] sorted after iteration i\text{Invariant: } A[0..i] \text{ sorted after iteration } i

Loop invariant: after each outer iteration, A[0..i] is sorted

Python Implementation

def insertion_sort(A):
    n = len(A)
    for i in range(1, n):             # Outer: extend sorted region
        key = A[i]                    # Element to insert
        j = i - 1
        while j >= 0 and A[j] > key: # Inner: find insertion point
            A[j + 1] = A[j]          # Shift element right
        A[j + 1] = key               # Insert key at correct position
    return A