Insertion Sort - Algorithms in 60 Seconds
Channel: OpenAMind
Watch on YouTube →Algorithm • medium
Insertion sort keeps a growing sorted prefix and inserts each new value into its correct position.
It is especially strong for tiny datasets or nearly sorted input where each insertion shifts very little.
Many high-performance sort implementations still use insertion sort for small partitions.
Typical Complexity Baseline
| Metric | Value |
|---|---|
| Complexity Note 1 | Average/Worst O(n^2) |
| Best | O(n) |
| Space | O(1) |
See It
A small animated SVG that illustrates the core idea the moving parts you need to keep in your head when you read the rest of the guide.
Take the next element and shift the sorted prefix right until its slot opens up.
Watch First
A quick visual walkthrough before the detailed sections pick the format that helps you learn fastest.
Channel: OpenAMind
Watch on YouTube →Mechanics
The building blocks and terminology you need before everything else clicks. Skim or deep-read.
What it is Left side is maintained in sorted order.
Why it matters Sorted prefix is a required building block for understanding how Insertion Sort stays correct and performant on large inputs.
What it is Value selected for insertion into sorted prefix.
Why it matters Current key is a required building block for understanding how Insertion Sort stays correct and performant on large inputs.
What it is Moves larger values right to make room.
Why it matters Shift loop is a required building block for understanding how Insertion Sort stays correct and performant on large inputs.
What it is Final slot where the key is placed.
Why it matters Insert position is a required building block for understanding how Insertion Sort stays correct and performant on large inputs.
What it is Advances to next unsorted value.
Why it matters Outer pointer is a required building block for understanding how Insertion Sort stays correct and performant on large inputs.
What it is Index where current value belongs in sorted prefix.
Why it matters Index where current value belongs in sorted prefix. In Insertion Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Equal values preserve original relative order.
Why it matters Equal values preserve original relative order. In Insertion Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Runs faster when input is partially sorted.
Why it matters Runs faster when input is partially sorted. In Insertion Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Sorts by mutating original array with O(1) extra space.
Why it matters Sorts by mutating original array with O(1) extra space. In Insertion Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Move an element one slot right to open insertion space.
Why it matters Move an element one slot right to open insertion space. In Insertion Sort, this definition helps you reason about correctness and complexity when inputs scale.
Walkthrough
Every frame of the concept diagram, laid out top-to-bottom so you can scroll through the algorithm at your own pace.
Sorted prefix is just [4]. Pick the next element and slide it left until it lands in place.
Pick arr[1]=7. Compare with arr[0]=4.
7 dropped into slot 1. Sorted prefix is now [4, 7].
Pick arr[2]=2. Compare with arr[1]=7.
2 < 7 → shift right. Now compare with arr[0]=4.
2 reached the start → it's the new minimum.
2 dropped into slot 0. Sorted prefix is now [2, 4, 7].
Pick arr[3]=5. Compare with arr[2]=7.
5 < 7 → shift right. Now compare with arr[1]=4.
5 dropped into slot 2. Sorted prefix is now [2, 4, 5, 7].
Pick arr[4]=1. Compare with arr[3]=7.
1 < 7 → shift right. Now compare with arr[2]=5.
1 < 5 → shift right. Now compare with arr[1]=4.
1 < 4 → shift right. Now compare with arr[0]=2.
1 reached the start → it's the new minimum.
1 dropped into slot 0. Sorted prefix is now [1, 2, 4, 5, 7].
Pick arr[5]=6. Compare with arr[4]=7.
6 < 7 → shift right. Now compare with arr[3]=5.
6 dropped into slot 4. Sorted prefix is now [1, 2, 4, 5, 6, 7].
Pick arr[6]=3. Compare with arr[5]=7.
3 < 7 → shift right. Now compare with arr[4]=6.
3 < 6 → shift right. Now compare with arr[3]=5.
3 < 5 → shift right. Now compare with arr[2]=4.
3 < 4 → shift right. Now compare with arr[1]=2.
3 dropped into slot 2. Sorted prefix is now [1, 2, 3, 4, 5, 6, 7].
Tradeoffs
When this technique wins, when it loses, and what to reach for instead.
Choose this when Choose insertion sort for fewer writes on nearly sorted input.
Tradeoff Both are O(n^2) worst-case on random/reversed arrays.
Choose this when Choose insertion sort for small arrays where low overhead matters.
Tradeoff Merge sort scales better for large input sizes.
Choose this when Choose insertion sort for tiny partitions in hybrid approaches.
Tradeoff Quick sort dominates on larger random datasets.
In Production
Where this shows up at real companies and what the on-call engineer learned the hard way.
Standard library sort implementations often switch to insertion sort on very small partitions.
Takeaway Simple algorithms can be optimal in specific ranges.
Small row groups and incremental updates benefit from insertion-style behavior.
Takeaway Nearly sorted data changes are often cheaper than full resorting.
Firmware code paths with tiny arrays choose insertion sort for minimal implementation overhead.
Takeaway Operational constraints can favor simplicity and predictability.
Code
A clean reference implementation in TypeScript, Python, and Go. Switch languages with the toggle.
Take each value, shift larger values right, and insert into the gap.
Complexity: Average/Worst O(n^2), Best O(n), Space O(1)
Insertion sort with shifting
function insertionSort(values: number[]): number[] {
const sortedValues = [...values]
for (let insertionIndex = 1; insertionIndex < sortedValues.length; insertionIndex += 1) {
const currentValue = sortedValues[insertionIndex]
let compareIndex = insertionIndex - 1
while (compareIndex >= 0 && sortedValues[compareIndex] > currentValue) {
sortedValues[compareIndex + 1] = sortedValues[compareIndex]
compareIndex -= 1
}
sortedValues[compareIndex + 1] = currentValue
}
return sortedValues
}
Watch Out
The bugs and edge cases that bite engineers most often. Skim before you ship.
Pro Tips
Small habits that pay off every time you reach for this pattern.
Pattern Recognition
Concrete signals that tell you this is the right pattern both at work and on LeetCode.
Practice
A curated easy-to-hard problem ladder. Each one reinforces a specific aspect of the pattern.
| # | Problem | Difficulty | Typical Complexity |
|---|---|---|---|
| 1 | Relative Sort Array | Easy | O(n log n) |
| 2 | Sort an Array | Medium | O(n^2) insertion approach |
| 3 | Insertion Sort List | Medium | O(n^2) |
| 4 | Sort Colors | Medium | O(n) optimal, O(n^2) insertion naive |
| 5 | Largest Number | Medium | O(n log n) |
| 6 | Wiggle Sort II | Medium | O(n log n) |
| 7 | Sort List | Medium | O(n log n) target |
| 8 | Count of Smaller Numbers After Self | Hard | O(n log n) |
| 9 | Reverse Pairs | Hard | O(n log n) |
| 10 | Median of Two Sorted Arrays | Hard | O(log(min(m,n))) |