Chapter 17: Elementary Sorting Algorithms
17.04Beginner / Intermediate5 topics16 min3 interactive animations

Insertion sort

Insertion sort takes elements one at a time and inserts each into its place within an already sorted prefix, the way you sort a hand of cards. It is stable, adaptive and the fastest elementary sort on small or nearly sorted input.

Learning goals

  • Trace insertion sort and state its loop invariant
  • Explain why shifting beats swapping
  • Relate its running time to the number of inversions
  • Use binary search to reduce comparisons

Prerequisites

Arrayswhile loopsBinary search (for the last topic)
17.04.1

Sorted prefix invariant

Invariant: at the start of iteration i, arr[0..i-1] is sorted (it holds the original first i elements in order). Inserting arr[i] into that prefix extends the invariant to arr[0..i].

When i reaches n, the whole array is sorted. This is a textbook example of proving correctness with a loop invariant: it holds at initialisation, each iteration maintains it, and it gives the result at termination.

Insertion sort

Interactive · edit the input

Your input

Try

int[] arr · length 7

38
27
43
3
9
82
10
0123456
Key in handBeing comparedMovedSorted
Setup

Invariant: arr[0..i-1] is always sorted. A single element is trivially sorted.

Step 1 / 48
Java
1public static void insertionSort(int[] arr) {
2 for (int i = 1; i < arr.length; i++) {
3 int key = arr[i];
4 int j = i - 1;
5 while (j >= 0 && arr[j] > key) {
6 arr[j + 1] = arr[j]; // shift right
7 j--;
8 }
9 arr[j + 1] = key;
10 }
11}

Live state

0 comparisons0 shifts

n

7

No condition evaluated on this step
Execution trace (dry run table)Show 48 steps
StepLineStateWhat happens
1L2n=7Invariant: arr[0..i-1] is always sorted. A single element is trivially sorted.
2L3i=1 key=27Pick up key = 27. It must be inserted into the sorted prefix [0..0].
3L4i=1 key=27 j=0j = 0, the last index of the sorted prefix.
4L5i=1 key=27 j=038 is larger, so it must move right.
5L6i=1 key=27 j=0arr[1] = arr[0]: 38 shifts right. One write, not a full swap.
6L5i=1 key=27 j=-1Reached the front of the array.
7L9i=1 key=27 j=-1arr[0] = 27. Prefix [0..1] is sorted.
8L3i=2 key=43Pick up key = 43. It must be inserted into the sorted prefix [0..1].
9L4i=2 key=43 j=1j = 1, the last index of the sorted prefix.
10L5i=2 key=43 j=138 <= 43. Stop here; using > (not >=) keeps equal keys in order, so the sort is stable.
11L9i=2 key=43 j=1arr[2] = 43. Prefix [0..2] is sorted.
12L3i=3 key=3Pick up key = 3. It must be inserted into the sorted prefix [0..2].
13L4i=3 key=3 j=2j = 2, the last index of the sorted prefix.
14L5i=3 key=3 j=243 is larger, so it must move right.
15L6i=3 key=3 j=2arr[3] = arr[2]: 43 shifts right. One write, not a full swap.
16L5i=3 key=3 j=138 is larger, so it must move right.
17L6i=3 key=3 j=1arr[2] = arr[1]: 38 shifts right. One write, not a full swap.
18L5i=3 key=3 j=027 is larger, so it must move right.
19L6i=3 key=3 j=0arr[1] = arr[0]: 27 shifts right. One write, not a full swap.
20L5i=3 key=3 j=-1Reached the front of the array.
21L9i=3 key=3 j=-1arr[0] = 3. Prefix [0..3] is sorted.
22L3i=4 key=9Pick up key = 9. It must be inserted into the sorted prefix [0..3].
23L4i=4 key=9 j=3j = 3, the last index of the sorted prefix.
24L5i=4 key=9 j=343 is larger, so it must move right.
25L6i=4 key=9 j=3arr[4] = arr[3]: 43 shifts right. One write, not a full swap.
26L5i=4 key=9 j=238 is larger, so it must move right.
27L6i=4 key=9 j=2arr[3] = arr[2]: 38 shifts right. One write, not a full swap.
28L5i=4 key=9 j=127 is larger, so it must move right.
29L6i=4 key=9 j=1arr[2] = arr[1]: 27 shifts right. One write, not a full swap.
30L5i=4 key=9 j=03 <= 9. Stop here; using > (not >=) keeps equal keys in order, so the sort is stable.
31L9i=4 key=9 j=0arr[1] = 9. Prefix [0..4] is sorted.
32L3i=5 key=82Pick up key = 82. It must be inserted into the sorted prefix [0..4].
33L4i=5 key=82 j=4j = 4, the last index of the sorted prefix.
34L5i=5 key=82 j=443 <= 82. Stop here; using > (not >=) keeps equal keys in order, so the sort is stable.
35L9i=5 key=82 j=4arr[5] = 82. Prefix [0..5] is sorted.
36L3i=6 key=10Pick up key = 10. It must be inserted into the sorted prefix [0..5].
37L4i=6 key=10 j=5j = 5, the last index of the sorted prefix.
38L5i=6 key=10 j=582 is larger, so it must move right.
39L6i=6 key=10 j=5arr[6] = arr[5]: 82 shifts right. One write, not a full swap.
40L5i=6 key=10 j=443 is larger, so it must move right.
41L6i=6 key=10 j=4arr[5] = arr[4]: 43 shifts right. One write, not a full swap.
42L5i=6 key=10 j=338 is larger, so it must move right.
43L6i=6 key=10 j=3arr[4] = arr[3]: 38 shifts right. One write, not a full swap.
44L5i=6 key=10 j=227 is larger, so it must move right.
45L6i=6 key=10 j=2arr[3] = arr[2]: 27 shifts right. One write, not a full swap.
46L5i=6 key=10 j=19 <= 10. Stop here; using > (not >=) keeps equal keys in order, so the sort is stable.
47L9i=6 key=10 j=1arr[2] = 10. Prefix [0..6] is sorted.
48L11Sorted with 15 comparisons, 11 shifts. Shifts equal the number of inversions in the input.
17.04.2

Shift vs swap

Hold the key in a variable and shift larger elements one slot right with a single write each, then drop the key into the gap. That is one write per moved element plus one for the key.

The swap version (gnome sort, in 17.05) does three writes per step. The comparisons are the same, but shifting moves less data.

Java
1// swap version: three writes per step
2for (int j = i; j > 0 && arr[j - 1] > arr[j]; j--) {
3 int tmp = arr[j]; arr[j] = arr[j - 1]; arr[j - 1] = tmp;
4}
5
6// shift version: one write per step
7int key = arr[i], j = i - 1;
8while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j--; }
9arr[j + 1] = key;
17.04.3

Adaptive best case

Each shift fixes exactly one inversion, so the total work is O(n + I), where I is the number of inversions. Sorted input has I = 0 and needs n - 1 comparisons. Reverse sorted input has I = n(n-1)/2.

This is why TimSort and introsort hand small or nearly sorted runs to insertion sort.

Best

O(n)

Average

O(n²)

Worst

O(n²)

Space

O(1)

17.04.4

Stability

The loop condition arr[j] > key stops at an equal element, so the key is placed after existing equal keys and their order is preserved. Using >= would move the key past its equals and break stability.

Stability: what happens to equal keys?

Interactive

Your input

Try

Input · letters show original order of equal keys

3a3b2a2b2c1

Insertion sort

12a2b2c3a3b
a before b

Bubble sort

12a2b2c3a3b
a before b

Selection sort

12a2b2c3b3a
Order broken

Shell sort

12b2c2a3a3b
Order broken
17.04.5

Binary insertion sort

Since the prefix is sorted, binary search can find the insert position in O(log i) comparisons. Use the upper-bound form (<=) so equal keys stay stable.

Comparisons fall to O(n log n) overall, but shifting is still O(n²) in the worst case. It helps when comparisons are expensive, for example comparing long strings or objects.

Best

O(n log n) comparisons

Worst

O(n²) moves

Space

O(1)

Binary insertion sort

Interactive · edit the input

Your input

Try

int[] arr · length 7

38
27
43
3
9
82
10
0123456
Key in handBeing comparedDiscardedSorted
Setup

Same idea as insertion sort, but find the insert position with binary search.

Step 1 / 32
Java
1public static void binaryInsertionSort(int[] arr) {
2 for (int i = 1; i < arr.length; i++) {
3 int key = arr[i];
4 int lo = 0, hi = i;
5 while (lo < hi) { // upper bound in arr[0..i)
6 int mid = (lo + hi) >>> 1;
7 if (arr[mid] <= key) lo = mid + 1;
8 else hi = mid;
9 }
10 System.arraycopy(arr, lo, arr, lo + 1, i - lo);
11 arr[lo] = key;
12 }
13}

Live state

0 comparisons0 shifts

n

7

No condition evaluated on this step
Execution trace (dry run table)Show 32 steps
StepLineStateWhat happens
1L2n=7Same idea as insertion sort, but find the insert position with binary search.
2L4i=1 key=27 lo=0 hi=1key = 27. Search the sorted prefix [0..0].
3L7i=1 key=27 lo=0 hi=1 mid=0Insert at or before mid.
4L9i=1 key=27 lo=0Insert position is 0.
5L10i=1 key=27 lo=0 moved=1Shift 1 element right in one block copy and drop 27 at index 0.
6L4i=2 key=43 lo=0 hi=2key = 43. Search the sorted prefix [0..1].
7L7i=2 key=43 lo=0 hi=2 mid=1Insert after mid (<= keeps equal keys stable).
8L9i=2 key=43 lo=2Insert position is 2.
9L10i=2 key=43 lo=2 moved=0Shift 0 elements right in one block copy and drop 43 at index 2.
10L4i=3 key=3 lo=0 hi=3key = 3. Search the sorted prefix [0..2].
11L7i=3 key=3 lo=0 hi=3 mid=1Insert at or before mid.
12L7i=3 key=3 lo=0 hi=1 mid=0Insert at or before mid.
13L9i=3 key=3 lo=0Insert position is 0.
14L10i=3 key=3 lo=0 moved=3Shift 3 elements right in one block copy and drop 3 at index 0.
15L4i=4 key=9 lo=0 hi=4key = 9. Search the sorted prefix [0..3].
16L7i=4 key=9 lo=0 hi=4 mid=2Insert at or before mid.
17L7i=4 key=9 lo=0 hi=2 mid=1Insert at or before mid.
18L7i=4 key=9 lo=0 hi=1 mid=0Insert after mid (<= keeps equal keys stable).
19L9i=4 key=9 lo=1Insert position is 1.
20L10i=4 key=9 lo=1 moved=3Shift 3 elements right in one block copy and drop 9 at index 1.
21L4i=5 key=82 lo=0 hi=5key = 82. Search the sorted prefix [0..4].
22L7i=5 key=82 lo=0 hi=5 mid=2Insert after mid (<= keeps equal keys stable).
23L7i=5 key=82 lo=3 hi=5 mid=4Insert after mid (<= keeps equal keys stable).
24L9i=5 key=82 lo=5Insert position is 5.
25L10i=5 key=82 lo=5 moved=0Shift 0 elements right in one block copy and drop 82 at index 5.
26L4i=6 key=10 lo=0 hi=6key = 10. Search the sorted prefix [0..5].
27L7i=6 key=10 lo=0 hi=6 mid=3Insert at or before mid.
28L7i=6 key=10 lo=0 hi=3 mid=1Insert after mid (<= keeps equal keys stable).
29L7i=6 key=10 lo=2 hi=3 mid=2Insert at or before mid.
30L9i=6 key=10 lo=2Insert position is 2.
31L10i=6 key=10 lo=2 moved=4Shift 4 elements right in one block copy and drop 10 at index 2.
32L13Sorted with 12 comparisons, 11 shifts. Comparisons drop to O(n log n), but shifts are still O(n²).

Practice ladder

Now try it yourself

Easy

  • Insertion sort descending
  • Insert one value into an already sorted array

Medium

  • Insertion sort a linked list
  • Sort an array where each element is at most k positions from its target in O(n k)

Advanced

  • Count inversions and verify they equal insertion sort's shifts
  • Library sort (gapped insertion sort) analysis

Key takeaways

  • Insertion sort maintains a sorted prefix and inserts each new element by shifting.
  • Work is O(n + inversions): linear on nearly sorted data, quadratic on reverse data.
  • It is stable, in-place and the standard choice for small subarrays.