datarekha

Bubble, Insertion & Selection Sort

The three elementary O(n²) sorts every programmer should understand — they teach the cost model that underpins every more efficient algorithm you'll ever use.

8 min read Beginner Data Structures & Algorithms Lesson 8 of 32

What you'll learn

  • The mental model for each of the three elementary sorts in one sentence
  • Why all three are O(n²) in comparisons yet differ sharply in swap count
  • When insertion sort beats its O(n²) label — and why it lives inside Timsort
  • How to instrument a sort with a comparison counter to measure cost directly

Before you start

Pick up a hand of playing cards and sort them without thinking about it. You probably pluck each new card from the right, scan left until you find where it belongs, and slide it in. That is insertion sort — the most natural sorting algorithm humans use, and one of the three O(n²) classics worth knowing cold.

None of these algorithms will appear in your production code for sorting large data. But they are the clearest possible demonstration of the cost model: how many comparisons does it take to find the right order, and how many swaps does it take to achieve it? Every efficient sort you ever encounter — merge sort, quicksort, Timsort — is designed to reduce those two numbers.

The mental model for each

Bubble sort — repeatedly walk the array and swap any adjacent pair that is out of order. Each full pass “bubbles” the largest unsorted element to its final position. One pass = one element settled.

Insertion sort — treat the left portion as a growing sorted hand. For each new element, walk left and swap it down until it finds its place. The hand stays sorted at all times.

Selection sort — find the smallest unsorted element, then swap it to the front. One scan = one element settled, but always with exactly one swap per pass (even when nothing needs moving, a no-op swap still costs a comparison scan).

The race makes the difference concrete. Insertion sort accumulates swaps only when elements are far from their final position; on a nearly-sorted array it barely moves anything. Selection sort’s swap count is always at most n−1, but its comparison count is identical to bubble sort. Bubble sort is the worst of both worlds — many comparisons and many swaps — yet it is the most commonly taught because the code is two nested loops and nothing else.

Why they are all O(n²)

Each algorithm has an outer loop that runs n times and an inner loop that, on average, also runs proportional to n times. The comparison count grows as the area of a triangle under the line n — roughly n²/2 comparisons for n elements.

AlgorithmComparisons (worst)Swaps (worst)Best case
BubbleO(n²)O(n²)O(n) — already sorted
InsertionO(n²)O(n²)O(n) — already sorted
SelectionO(n²)O(n)O(n²) — always scans fully

The big-O class is the same for all three. The constant matters in practice, which is why insertion sort is the one that survives in real-world code while bubble and selection are teaching tools.

Live code: insertion sort with a counter

Run this to see the comparison count printed alongside the sorted result. The counter makes the cost visible rather than theoretical.

Notice the comparison counts: 11 for the already-sorted case (one per element, each breaks immediately), 66 for the reverse-sorted case (1 + 2 + … + 11). That is the O(n) best case vs. the O(n²) worst case in action for n = 12.

You rarely write these — but you read their fingerprint everywhere

When you call sorted() on a 10-element list, Timsort is invoking insertion sort internally. When you see a nested loop scanning an array, your first instinct should be “that is probably O(n²) — is there a sort or a hash map that eliminates the inner loop?” That instinct is built by understanding why these three algorithms look the way they do.

The broader lesson: every algorithm has a cost model — the dominant operation (comparisons, memory reads, cache misses) and how many times it executes. Elementary sorts make that model transparent because there is nowhere to hide.

Quick check

Quick check

0/4
Q1An array is already in sorted order. Which algorithm finishes in O(n) time?
Q2Selection sort's worst-case swap count is O(n), while bubble sort's is O(n²). Why does this not make selection sort faster in practice?
Q3Why does Timsort use insertion sort for small sub-arrays rather than always using merge sort?
Q4A data pipeline receives sensor readings that arrive almost in time order, with occasional late entries displaced by at most a few positions. Which sorting algorithm handles this most efficiently, and why?

Practice this in an interview

All questions

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Explore further

Related lessons

Skip to content