Bubble / Insertion / Selection
Bubble sort: simple, slow, and the algorithm that teaches you why we use better ones.
DSA — bubble sort
EXAMPLE
// ===== Pseudo-code =====
// For each pass through the array:
// For each adjacent pair (i, i+1):
// If a[i] > a[i+1], swap them
// Repeat until no swaps happen in a pass.
function bubbleSort(arr) {
const a = [...arr];
let n = a.length;
let swapped;
do {
swapped = false;
for (let i = 0; i < n - 1; i++) {
if (a[i] > a[i + 1]) {
[a[i], a[i + 1]] = [a[i + 1], a[i]];
swapped = true;
}
}
n--; // largest element is at the end now
} while (swapped);
return a;
}
console.log(bubbleSort([5, 2, 9, 1, 7])); // [1, 2, 5, 7, 9]
// ===== Complexity =====
// Time:
// Best O(n) already sorted; one pass with no swaps
// Avg O(n^2)
// Worst O(n^2) reverse sorted
// Space: O(1) extra (in place)
// Stable: YES (equal elements keep order)
// ===== Why we don't use it =====
// O(n^2) makes it unusable at scale.
// Even on n=10_000 it does ~50 million comparisons.
// ===== Variants =====
// Cocktail sort: alternates direction each pass (slightly better)
// Comb sort: skips by a 'gap' shrunk over passes (much better in practice)
// Optimized bubble: shrink the inner-loop bound each pass
// ===== When it is OK =====
// - Teaching / interview warmup
// - Tiny arrays (< 30 items) where overhead beats fancy algorithms
// - Specific 'few wrong' near-sorted data (still O(n) best case)
// ===== Comparison with neighbours =====
// Insertion sort: O(n^2) worst, but ~2x faster than bubble in practice + better best case
// Selection sort: O(n^2), unstable, fewer swaps but more comparisons
// Quick / merge / heap: O(n log n) — what you actually use
// ===== Better real-world options =====
// JS: Array.prototype.sort() uses TimSort (O(n log n)) — used in V8, Python, Java.
// C: qsort uses introsort variant.
// Rust: Vec::sort uses TimSort-derived.
// Use the built-in sort unless writing the algorithm is the assignment.
// ===== Patterns to internalise =====
// - Bubble sort is a teaching algorithm, not a production tool
// - Recognise stable vs unstable sorts (bubble + merge + Tim ARE stable)
// - Best-case detection (no swaps in a pass = sorted)
// - Switch to insertion sort for n < 30 if you must roll your own
// ===== Pitfalls =====
// - Using bubble sort in production code
// - Forgetting the early-exit when no swap occurs
// - Off-by-one on the inner loop bound (i < n - 1)
// - Treating sort comparator as ordered when it must be transitive + total
Why it matters
Bubble sort is the introduction, not the conclusion. O(n^2), in place, stable, easy to reason about. Use it to understand swap-based sorts and the role of stability; reach for built-in TimSort or quicksort for actual sorting. The teaching value is the algorithm; the production value is "do not write this".
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Useful only for tiny inputs. Insertion sort wins for small N + nearly sorted.
function bubbleSort(a) {
for (let i = a.length - 1; i > 0; i--)
for (let j = 0; j < i; j++)
if (a[j] > a[j+1]) [a[j], a[j+1]] = [a[j+1], a[j]];
return a;
}
Try it Yourself »
Discussion
Loading…