"Everyone learns bubble sort and then learns to sneer at it. But one of these 'slow' O(n²) sorts is quietly inside the fast sorts you actually use — because on small or nearly-sorted data, simple beats clever."
The Three Teaching Sorts
All three are O(n²) — they compare pairs in nested loops — but each illustrates a different idea:
- Bubble sort: repeatedly swap adjacent out-of-order pairs; the largest 'bubbles' to the end each pass. The simplest to picture, almost never the right choice in practice — its main job is being the first sort everyone meets.
- Selection sort: each pass finds the minimum of the unsorted region and places it. Minimizes the number of swaps (useful if writes are expensive) but always O(n²) comparisons.
- Insertion sort: builds a sorted prefix one element at a time, inserting each new element into its place — exactly how most people sort a hand of cards.
Why Insertion Sort Earns Its Keep
Insertion sort is the one that matters, because it has two real virtues the others lack. First, it's adaptive: on already-sorted or nearly-sorted data, each new element is already (almost) in place, so it does only O(n) work — not O(n²). Second, it has tiny constant overhead: no recursion, no extra memory, great cache behavior. That combination makes it the fastest sort for small arrays. So the world's best sorts — Python's Timsort, C++'s introsort — divide big data with merge/quicksort but switch to insertion sort for the small subarrays at the bottom. The 'slow' sort is a component of the fast ones.
When Simple Is Right
The judgment: for large, random data, never reach for these — O(n²) on a million items is a trillion operations. But for small arrays (say under ~50 elements), nearly-sorted data, or when code simplicity and low memory matter more than asymptotics, insertion sort can genuinely win. This is the recurring quest theme one more time: the 'best' algorithm depends on the data and the scale, and dismissing a simple tool wholesale is as much an error as over-engineering with a fancy one.