What is Bubble Sort?
Bubble sort is a sorting algorithm with exactly one move: compare each pair of neighbours and swap them if they are out of order. Sweep the list again and again; on every pass, the largest un-placed value "bubbles" to its final spot at the end. When a whole pass makes no swaps, the list is sorted.
In this lesson you'll learn the compare-and-swap move, trace it pass by pass on
[5, 2, 4, 1], and see exactly why this simplest of sorts is also the slowest.Picture a shelf of books you tidy by only ever comparing two neighbouring spines: wherever the left one is taller than the right one, swap them, and keep sweeping the shelf until a full sweep finds nothing to fix. That's the whole algorithm — which is why bubble sort is every programmer's first sort: not because it's good, but because it makes the idea of sorting completely visible.
Tidy it in words, with book heights 5, 2, 4, 1: compare the first pair — 5 and 2, wrong order, swap. Now 5 meets 4 — swap. 5 meets 1 — swap. The 5 has bubbled all the way to the end, its final home. Sweep again: the 4 bubbles into place. One more sweep finishes the shelf: 1, 2, 4, 5. Watch the sweeps below. (The coded version with live counters lives in the See it step.)
This section has a step-by-step animation in the interactive lesson.
Quick check
Bubble sort's single repeated move is to…
Answer it in the interactive lesson to keep your progress.
How it works, step by step
Let's sort
[5, 2, 4, 1] from scratch:Compare and swap. For every adjacent pair, check if the left is bigger than the right:
arr[j] > arr[j+1]. If so, swap them using JavaScript's destructuring: [arr[j], arr[j+1]] = [arr[j+1], arr[j]].One pass. Walk through the array comparing neighbours:
5 > 2→ swap →[2, 5, 4, 1]5 > 4→ swap →[2, 4, 5, 1]5 > 1→ swap →[2, 4, 1, 5]
At the end of this first pass, the largest value (
5) has bubbled to the end. That tail element is now locked into place.Repeat passes. Keep running passes on the remaining unsorted part. Each pass places the next largest value, so the inner loop gets shorter by
i on each pass. We nest a loop to bubble each remaining element. (The See it step animates every comparison and swap — watch one value lock into place at the right end after each pass.)Bubble Sort in JavaScript
function bubbleSort(list) {
const arr = [...list]; // copy so we don't mutate the caller's array
for (let i = 0; i < arr.length - 1; i++) { // one pass per element
for (let j = 0; j < arr.length - 1 - i; j++) { // ...ignoring the sorted tail
if (arr[j] > arr[j + 1]) { // neighbours out of order?
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // swap them
}
}
}
return arr;
}
console.log(bubbleSort([5, 2, 4, 1])); // [1, 2, 4, 5]Quick check
After the FIRST full pass of bubble sort on [5, 2, 4, 1], predict which value is guaranteed in place.
Answer it in the interactive lesson to keep your progress.
Where it breaks (and when to use it)
Bubble sort is almost never used in production because it is the slowest of the common sorts. Its value is teaching (the mechanics are dead simple) and sorting tiny or nearly-sorted inputs where an early-exit check makes it fast.
Watch out for:
- Skipping the early-exit check. Without checking if any swaps occurred, bubble sort does the full
O(n²)work even on a sorted list. - Shrinking the range wrong. After pass
k, the lastkelements are already sorted. Re-scanning them is redundant. - Scale issues. On large datasets, its quadratic time complexity makes it far too slow.
Take it further — optimized bubble sort
We can speed up Bubble Sort significantly on nearly-sorted data by adding an early-exit flag. If a full sweep over the array does not perform a single swap, it means the list is already sorted! We can break out of the loop immediately, bringing the runtime down to
O(n) on sorted inputs.Optimized Bubble Sort in JavaScript
function bubbleSortOptimized(list) {
const arr = [...list];
for (let i = 0; i < arr.length - 1; i++) {
let swapped = false;
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
if (!swapped) break; // exit early if no swaps occurred
}
return arr;
}
console.log(bubbleSortOptimized([1, 2, 3, 4])); // [1, 2, 3, 4] (stops after 1 pass)Quick check
With the early-exit flag, predict the cost of bubble-sorting an ALREADY sorted array.
Answer it in the interactive lesson to keep your progress.
How fast is it? (complexity)
Time complexity is
O(n²) in the worst and average cases (a pass per element, a scan per pass). Space is O(1) since it sorts in place. With the early-exit flag, it is O(n) on sorted data. It is stable (equal elements keep their order).At a glance:
| Case | Time |
|---|---|
| worst / average | O(n²) |
| already sorted (with early exit) | O(n) |
| space | O(1) in place |
| stable? | yes |
Speaking of built-ins — one JavaScript trap to know before you ever call one:
Array.prototype.sort() with no arguments compares as strings, so [10, 9, 2].sort() returns [10, 2, 9] ("10" < "2" alphabetically!). Sorting numbers always needs a comparator: arr.sort((a, b) => a - b).Key takeaways:
- One move: compare adjacent elements, swap if out of order; largest bubbles to the end.
O(n²)worst/avg,O(1)space, stable. Early-exit makes sorted dataO(n).- Use for learning, not production — reach for quick/merge sort or built-ins at scale (with a numeric comparator!).
Compare it against its neighbours: insertion sort (also simple, but genuinely good on small/nearly-sorted data), merge sort (guaranteed
O(n log n)), and quick sort (fast in-place average-case champion). Use the switcher at the top to open another strategy, and the See it step to watch it sort.