Shreyansh Jain.

Software engineer and IIT Roorkee alumnus. I write about programming, computer science, and the things I learn while building software.

Shreyansh Jain
Data Structures & Algorithms Jul 19, 2026 5 min read

Insertion Sort

Insertion Sort is one of the first sorting algorithms most people learn, and despite being decades old and theoretically "slow," it remains genuinely useful in modern software. It mirrors how many of us sort a hand of playing cards: pick up one card at a time and slide it into its correct position among the cards already in your hand.
This article explains how the algorithm works, analyzes its time and space complexity, and lays out the specific situations where it is the right tool for the job.

How Insertion Sort Works


The algorithm divides the array into two conceptual regions: a sorted region on the left and an unsorted region on the right. It starts by treating the first element as a trivially sorted region of size one, then repeatedly takes the next unsorted element and inserts it into its correct place within the sorted region, shifting larger elements one position to the right to make room.
Consider sorting the array [5, 2, 4, 6, 1, 3]:
1. Start with 5 as the sorted region: [5 | 2, 4, 6, 1, 3]
2. Insert 2 → shift 5 right: [2, 5 | 4, 6, 1, 3]
3. Insert 4 → goes between 2 and 5: [2, 4, 5 | 6, 1, 3]
4. Insert 6 → already in place: [2, 4, 5, 6 | 1, 3]
5. Insert 1 → shifts to the front: [1, 2, 4, 5, 6 | 3]
6. Insert 3 → goes between 2 and 4: [1, 2, 3, 4, 5, 6]
Each pass grows the sorted region by one until the whole array is ordered.
!Insertion Sort Step 1
!Insertion Sort Step 2
!Insertion Sort Step 3
!Insertion Sort Step 4
!Insertion Sort Step 5
!Insertion Sort Step 6

Implementation


Here is a clean and efficient implementation in C++:
#include <vector>
void insertionSort(std::vector<int>& arr) {
for (int i = 1; i < arr.size(); i++) {
int key = arr[i];
int j = i - 1;

// Shift elements greater than key one position to the right
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j -= 1;
}

// Insert the key into its correct position
arr[j + 1] = key;
}
}

!Element Shifting in Insertion Sort

Time Complexity


The performance of Insertion Sort depends heavily on how sorted the input already is, which is one of its most important characteristics.
| Case | Time Complexity | Scenario |

























CaseTime ComplexityScenario
BestO(n)Array is already sorted
AverageO(n²)Elements in random order
WorstO(n²)Array sorted in reverse order

!Time Complexity Graph
In the best case, when the array is already sorted, the inner while loop never executes a shift, so the algorithm makes a single pass with n - 1 comparisons, giving linear time. This adaptivity is a defining feature: the closer the input is to being sorted, the faster it runs.
In the worst case, a reverse-sorted array forces every new element to travel all the way to the front. The number of shifts grows as roughly 1 + 2 + 3 + ... + (n-1), which sums to n(n-1)/2, hence O(n²).
The average case for random data is also O(n²), because on average each element must shift past about half of the already-sorted elements.

Space Complexity


Insertion Sort runs in place, requiring only a constant amount of extra memory for the key and loop variables regardless of input size. Its space complexity is therefore O(1).

Key Properties


Two properties beyond raw speed make Insertion Sort attractive in specific contexts:
Stable. Equal elements retain their original relative order, because the algorithm only shifts an element when it is strictly greater than the key. Stability matters when sorting records by one field while preserving an existing order on another.
Adaptive. Runtime scales with how disordered the input is. On nearly-sorted data, performance approaches O(n) rather than O(n²), which is why it outperforms many "faster" algorithms on this kind of input.
Online. It can sort a list as elements arrive one at a time, without needing the entire dataset up front. Each new element is simply inserted into the already-sorted portion.

When Insertion Sort Is Best Used


Despite its O(n²) average complexity, Insertion Sort is the right choice in several practical situations:
Small datasets. For small arrays (often cited as fewer than about 10 to 50 elements), the low constant-factor overhead of Insertion Sort beats the bookkeeping cost of more complex algorithms like Quicksort or Merge Sort. The asymptotic disadvantage simply does not have enough elements to matter.
Nearly-sorted data. When the input is already mostly ordered — for example, a sorted list with a few new items appended, or data that drifts only slightly out of order — the adaptive O(n) behavior makes Insertion Sort extremely efficient.
As a subroutine in hybrid algorithms. This is where Insertion Sort quietly powers real-world systems. High-performance sorts like Timsort (used in Python and Java) and Introsort (used in many C++ standard libraries) switch to Insertion Sort once the array or sub-partition they are working on becomes small enough. The recursive "divide" algorithms handle the large-scale structure, then hand off small chunks to Insertion Sort for the finish.
Streaming or online input. When data arrives incrementally and you need to maintain a sorted collection at all times, Insertion Sort's online property lets you insert each arrival directly.
Memory-constrained environments. Its O(1) space usage makes it suitable for embedded systems or situations where allocating extra buffers (as Merge Sort requires) is undesirable.
When simplicity and stability matter. The implementation is short, easy to reason about, and hard to get wrong — valuable when a stable sort is needed and the dataset is not large enough to justify anything more elaborate.

When to Avoid It


Insertion Sort is a poor choice for large, randomly-ordered datasets, where its O(n²) growth becomes prohibitively slow. A list of one million random elements would require on the order of a trillion operations in the worst case. For such workloads, O(n log n) algorithms like Merge Sort, Heapsort, or Quicksort are far more appropriate.

Summary


Insertion Sort trades asymptotic efficiency for simplicity, low overhead, and adaptivity. It shines on small or nearly-sorted inputs, serves as the workhorse "base case" inside the fastest hybrid sorting algorithms, and handles streaming data gracefully — all while using constant extra memory and preserving stability. Knowing when *not* to reach for it (large random datasets) is just as important as knowing its strengths. Far from being merely a teaching example, it remains a practical and widely-deployed algorithm.

Enjoyed this essay?

Support my writing by buying me a coffee.