Senior 13 min · March 05, 2026

Bubble Sort — Why 50K Items Took 12 Minutes in Production

Bubble Sort on 50K transaction IDs triggered 1.25 billion comparisons and a 12-min timeout.

N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Written from production experience, not tutorials.

Follow
Production
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Bubble Sort repeatedly compares adjacent elements and swaps them if out of order
  • After each pass, the largest unsorted value "bubbles" to its final position at the end
  • Always use the swapped flag to break early on already-sorted arrays — O(n) best case instead of O(n²)
  • Space complexity is O(1); sorting happens in-place with one temp variable
  • Not suitable for large datasets — 50 million comparisons for 10k elements worst-case
  • The only real production use: tiny (≤20 items) or nearly-sorted lists where simplicity wins
✦ Definition~90s read
What is Bubble Sort?

Bubble Sort is a comparison-based sorting algorithm that repeatedly steps through a list, compares adjacent elements, and swaps them if they are in the wrong order. It gets its name because smaller elements 'bubble' to the top (front) of the list with each pass.

Imagine you have a row of kids lined up by height, but they're all jumbled up.

While conceptually simple and easy to implement, it is catastrophically inefficient for production use: its worst-case and average time complexity is O(n²), meaning the number of operations grows quadratically with input size. For 50,000 items, that’s roughly 1.25 billion comparisons—which explains the 12-minute runtime mentioned in the title.

In practice, Bubble Sort is only suitable for educational purposes or tiny datasets (under a few hundred items). For any real-world sorting, you should use O(n log n) algorithms like Timsort (Python’s default), Quicksort, or Merge Sort. Even insertion sort or selection sort outperform Bubble Sort in most scenarios.

The algorithm’s only redeeming quality is its ability to detect an already-sorted array in O(n) time with an optimization flag, but that doesn’t save it from being a poor choice for production code.

Plain-English First

Imagine you have a row of kids lined up by height, but they're all jumbled up. You walk along the line, and every time you spot two kids standing next to each other who are in the wrong order, you swap them. You keep doing this walk over and over until nobody needs to swap anymore — and voilà, the line is perfectly sorted. That's Bubble Sort. The tallest kids 'bubble up' to the end of the line, one pass at a time.

Bubble Sort is the algorithm everyone learns and no one should ship. It swaps adjacent elements until the list is sorted, and while it’s simple to explain, it’s dangerously slow on real-world data. Without understanding its quadratic cost, you’ll accidentally tank latency in production, turning a single sort into a performance incident.

Why Bubble Sort Is Dangerous in Production

Bubble sort is a comparison-based sorting algorithm that repeatedly steps through a list, compares adjacent elements, and swaps them if they are in the wrong order. The pass-through continues until no swaps are needed, meaning the list is sorted. Its core mechanic is simple: larger elements "bubble" to the end with each pass.

In practice, bubble sort has O(n²) average and worst-case time complexity. For a list of 50,000 items, that's roughly 1.25 billion comparisons — which explains why a production system processing that volume took 12 minutes. Its only redeeming property is O(1) space complexity, as it sorts in-place. However, insertion sort and even selection sort outperform it in nearly every real scenario.

You should use bubble sort only for educational purposes or when sorting tiny datasets (under ~50 elements) where code simplicity outweighs performance. In production systems, never rely on it — the quadratic cost becomes catastrophic at scale, and modern languages provide O(n log n) alternatives like Timsort (Java's Arrays.sort) that are both faster and stable.

Don't Confuse Simplicity with Efficiency
Bubble sort's O(n²) complexity means doubling input size quadruples runtime — a 100K list takes ~48 minutes, not 24.
Production Insight
A Java microservice sorted 50K user records with bubble sort because a junior dev used it in a utility class.
The endpoint timed out after 12 minutes, causing cascading failures in dependent services and a P1 incident.
Never use bubble sort for any list that can grow beyond a few hundred items — always default to Arrays.sort() or Collections.sort().
Key Takeaway
Bubble sort is O(n²) — 50K items means billions of comparisons, not thousands.
It has no practical advantage over insertion sort for small lists and is catastrophically worse for large ones.
In production, always use built-in sorting (Timsort) — it's stable, O(n log n), and battle-tested.
Bubble Sort: Why 50K Items Took 12 Minutes THECODEFORGE.IO Bubble Sort: Why 50K Items Took 12 Minutes Visual pass-by-pass diagram of bubble sort's O(n²) behavior Unsorted Array (50K Items) Random order, large dataset First Pass: Compare Adjacent Swap if out of order, largest bubbles to end Repeated Passes Each pass reduces unsorted portion by 1 Early Stop Optimization If no swaps, array is sorted; break early Sorted Array O(n²) worst-case, O(n) best-case ⚠ Bubble sort on 50K items: 12 minutes in production Use O(n log n) sorts like quicksort or mergesort for large data THECODEFORGE.IO
thecodeforge.io
Bubble Sort: Why 50K Items Took 12 Minutes
Bubble Sort

How Bubble Sort Actually Works — One Pass at a Time

Let's use a concrete example. Say you have this array of five numbers: [5, 3, 8, 1, 4]. Your job is to sort it smallest to largest.

Bubble Sort works in rounds called 'passes'. During each pass, you walk through the array from left to right, look at every pair of neighboring elements side by side, and ask one question: 'Is the left one bigger than the right one?' If yes, swap them. If no, move on.

After Pass 1 on [5, 3, 8, 1, 4]
  • Compare 5 and 3 → 5 > 3, swap → [3, 5, 8, 1, 4]
  • Compare 5 and 8 → 5 < 8, no swap → [3, 5, 8, 1, 4]
  • Compare 8 and 1 → 8 > 1, swap → [3, 5, 1, 8, 4]
  • Compare 8 and 4 → 8 > 4, swap → [3, 5, 1, 4, 8]

Notice what happened: the largest number, 8, has 'bubbled up' all the way to its correct position at the end. That's the magic. Each pass guarantees the largest unsorted number finds its final home. You repeat this process, and each pass needs to go one element shorter because the last element is already locked in.

BubbleSortBasic.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class BubbleSortBasic {

    public static void main(String[] args) {

        // Our unsorted list of exam scores
        int[] scores = {5, 3, 8, 1, 4};

        int numberOfScores = scores.length;

        System.out.println("Before sorting:");
        printArray(scores);

        // Outer loop: controls how many passes we make.
        // After each pass, the largest unsorted element is in its final spot,
        // so we shrink the range by 1 each time (hence numberOfScores - pass - 1).
        for (int pass = 0; pass < numberOfScores - 1; pass++) {

            System.out.println("\n--- Pass " + (pass + 1) + " ---");

            // Inner loop: walks through neighboring pairs in the unsorted portion.
            // We stop earlier each pass because the tail is already sorted.
            for (int index = 0; index < numberOfScores - pass - 1; index++) {

                // Compare the current element with the one immediately to its right
                if (scores[index] > scores[index + 1]) {

                    // They're in the wrong order — swap them using a temp variable
                    int temp = scores[index];
                    scores[index] = scores[index + 1];
                    scores[index + 1] = temp;

                    System.out.println("  Swapped index " + index + " and " + (index + 1)
                            + " → " + java.util.Arrays.toString(scores));
                } else {
                    System.out.println("  No swap at index " + index
                            + " → " + java.util.Arrays.toString(scores));
                }
            }
        }

        System.out.println("\nAfter sorting:");
        printArray(scores);
    }

    // Helper method to print the array in a readable format
    static void printArray(int[] array) {
        System.out.println(java.util.Arrays.toString(array));
    }
}
Output
Before sorting:
[5, 3, 8, 1, 4]
--- Pass 1 ---
Swapped index 0 and 1 → [3, 5, 8, 1, 4]
No swap at index 1 → [3, 5, 8, 1, 4]
Swapped index 2 and 3 → [3, 5, 1, 8, 4]
Swapped index 3 and 4 → [3, 5, 1, 4, 8]
--- Pass 2 ---
No swap at index 0 → [3, 5, 1, 4, 8]
Swapped index 1 and 2 → [3, 1, 5, 4, 8]
Swapped index 2 and 3 → [3, 1, 4, 5, 8]
--- Pass 3 ---
Swapped index 0 and 1 → [1, 3, 4, 5, 8]
No swap at index 1 → [1, 3, 4, 5, 8]
--- Pass 4 ---
No swap at index 0 → [1, 3, 4, 5, 8]
After sorting:
[1, 3, 4, 5, 8]
Why does the inner loop shrink each pass?
After Pass 1, the largest element is guaranteed to be in its correct final position. After Pass 2, the two largest are locked in. So there's no point comparing those already-sorted elements again — shrinking the inner loop by 1 each time saves unnecessary work and is a key part of even the basic implementation.
Production Insight
In production, missing the $-pass$ leads to out-of-bounds crashes on the last compare.
Always use $size - pass - 1$ — that $-1$ is what prevents $arr[i+1]$ from going out of range.
The shrinking window is not an optimisation — it's a correctness requirement.
Key Takeaway
Each pass places one element correctly at the end.
Shrink the inner loop by the pass number to avoid touching sorted territory.
The algorithm name tells you what happens: largest values bubble to the surface.

Visual Pass-By-Pass Diagram

The diagram below tracks our example array [5, 3, 8, 1, 4] through each pass. Each row shows the state of the array after the row's pass. The highlighted element is the one that has 'bubbled' into its final sorted position. Notice how the largest element moves to the rightmost unsorted slot each pass. This visualisation helps cement the mental model of Bubble Sort as a series of sinking the largest remaining value.

bubble_sort_passes.txtTEXT
1
2
3
4
5
6
Initial: [5, 3, 8, 1, 4]

Pass 1: [3, 5, 1, 4, 8]   <- 8 is now sorted at end
Pass 2: [3, 1, 4, 5, 8]   <- 5 is sorted
Pass 3: [1, 3, 4, 5, 8]   <- 4 is sorted
Pass 4: [1, 3, 4, 5, 8]   <- no swap, done early
Key Takeaway
Visualising each pass helps internalise how Bubble Sort moves the largest element to the end.
Bubble Sort — Passes on [5, 3, 8, 1, 4]
Step 1
5
3
8
1
4
Compare 5 > 3, swap
Step 2
3
5
8
1
4
Compare 8 > 1, swap
Step 3
3
5
1
8
4
Compare 8 > 4, swap → 8 at end
Step 4
3
5
1
4
8
Pass 2: Compare 5 > 1, swap
Step 5
3
1
5
4
8
Compare 5 > 4, swap
Step 6
3
1
4
5
8
Pass 3: Compare 3 > 1, swap
Step 7
1
3
4
5
8
Pass 4: no swaps → sorted

The Optimized Version — Stop Early When the Array Is Already Sorted

The basic version has a silent problem. Imagine your array is [1, 2, 3, 4, 5] — already sorted. The basic algorithm still ploughs through all the passes anyway, making zero swaps but wasting time. With a large dataset, that's painfully inefficient.

The fix is elegant: use a flag called 'swapped'. At the start of each pass, set it to false. If you make even one swap during a pass, flip it to true. At the end of the pass, check the flag. If it's still false — meaning you walked through the entire array and didn't swap a single pair — the array is already sorted. Stop immediately.

This optimization doesn't change Bubble Sort's worst-case performance (we'll talk about that shortly), but it dramatically improves its best-case. On an already-sorted array, it now takes just one pass instead of n-1 passes. This is the version you should always write — it shows you understand the algorithm, not just the mechanics.

It also makes Bubble Sort one of the few simple algorithms that can detect a sorted array in O(n) time, which is occasionally useful in practice when you expect your data to be nearly sorted.

BubbleSortOptimized.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class BubbleSortOptimized {

    public static void main(String[] args) {

        // Test 1: A random unsorted list of temperatures
        int[] temperatures = {34, 12, 45, 7, 29};
        System.out.println("Test 1 — Unsorted input:");
        System.out.println("Before: " + java.util.Arrays.toString(temperatures));
        optimizedBubbleSort(temperatures);
        System.out.println("After:  " + java.util.Arrays.toString(temperatures));

        System.out.println();

        // Test 2: An already-sorted array — watch how few passes it takes
        int[] alreadySorted = {1, 2, 3, 4, 5};
        System.out.println("Test 2 — Already sorted input:");
        System.out.println("Before: " + java.util.Arrays.toString(alreadySorted));
        optimizedBubbleSort(alreadySorted);
        System.out.println("After:  " + java.util.Arrays.toString(alreadySorted));
    }

    static void optimizedBubbleSort(int[] array) {
        int size = array.length;
        int passCount = 0;

        for (int pass = 0; pass < size - 1; pass++) {

            // Assume no swaps have happened this pass
            boolean swappedThisPass = false;
            passCount++;

            for (int index = 0; index < size - pass - 1; index++) {

                if (array[index] > array[index + 1]) {

                    // Swap the two neighboring elements
                    int temp = array[index];
                    array[index] = array[index + 1];
                    array[index + 1] = temp;

                    // At least one swap happened, so the array wasn't fully sorted yet
                    swappedThisPass = true;
                }
            }

            // If we completed a full pass with zero swaps, the array is sorted.
            // No point continuing — exit early.
            if (!swappedThisPass) {
                System.out.println("Early exit after " + passCount + " pass(es) — array is sorted!");
                return;
            }
        }

        System.out.println("Completed in " + passCount + " pass(es).");
    }
}
Output
Test 1 — Unsorted input:
Before: [34, 12, 45, 7, 29]
Completed in 4 pass(es).
After: [7, 12, 29, 34, 45]
Test 2 — Already sorted input:
Before: [1, 2, 3, 4, 5]
Early exit after 1 pass(es) — array is sorted!
After: [1, 2, 3, 4, 5]
Always write the optimized version in interviews
If you hand an interviewer the basic version without the 'swapped' flag, expect the follow-up: 'What happens if the array is already sorted?' Show them you already thought of it by including the flag from the start. It signals you think about edge cases, not just happy paths.
Production Insight
If you run the basic version in production on an already-sorted file of 10k records, you burn ~50 million comparisons for no reason.
The swapped flag turns that into 10k comparisons — the difference between 5 seconds and 0.5 milliseconds.
Any sorting code in a hot path that doesn't early-exit is a performance bug waiting for a ticket.
Key Takeaway
Always include the swapped flag.
It does not hurt worst-case but cuts best-case from O(n²) to O(n).
Early exit is the sign of a thoughtful engineer.

Time and Space Complexity — What the Big-O Numbers Actually Mean

Big-O notation sounds intimidating but it's just a way of asking: 'How much slower does this algorithm get as the input gets bigger?' Let's work through Bubble Sort's numbers intuitively.

Imagine you have 10 elements. In the worst case (reverse-sorted order like [10, 9, 8, 7...]), Pass 1 does 9 comparisons, Pass 2 does 8, Pass 3 does 7... all the way down to 1. Total comparisons: 9+8+7+6+5+4+3+2+1 = 45. For 100 elements that's roughly 4,950 comparisons. For 1,000 elements, about 499,500. The number of comparisons grows with the square of the input size — that's O(n²).

Bubble Sort's three cases
  • Best Case O(n): Array is already sorted. With the optimized version, one pass, no swaps, done.
  • Average Case O(n²): Randomly ordered data. Lots of passes, lots of swaps.
  • Worst Case O(n²): Reverse-sorted data. Maximum comparisons and swaps every pass.

Space complexity is O(1) — constant. You're sorting the array in-place using only one temporary variable for swaps, regardless of how big the array is. That's actually a genuine strength of Bubble Sort.

For small arrays (say, fewer than 20 elements) or nearly-sorted data, Bubble Sort is perfectly fine. For large datasets, it's genuinely slow compared to Merge Sort O(n log n) or Quick Sort O(n log n) — and you'd never use it in production on big data.

BubbleSortComplexityDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class BubbleSortComplexityDemo {

    // We'll count actual comparisons to verify the O(n²) claim ourselves
    static int comparisonCount = 0;

    public static void main(String[] args) {

        System.out.println("Demonstrating how comparison count scales with input size:\n");
        System.out.printf("%-15s %-20s %-20s%n", "Array Size (n)", "Comparisons Made", "n² (theoretical)");
        System.out.println("-".repeat(55));

        // Test with different array sizes to show the quadratic growth
        int[] testSizes = {5, 10, 20, 50, 100};

        for (int size : testSizes) {

            // Build a worst-case (reverse-sorted) array of the given size
            int[] reverseArray = buildReverseSortedArray(size);

            comparisonCount = 0; // Reset counter before each sort
            bubbleSortWithCounter(reverseArray);

            System.out.printf("%-15d %-20d %-20d%n",
                    size, comparisonCount, (long) size * size);
        }

        System.out.println("\nNotice: actual comparisons ≈ n²/2, which is still O(n²).");
    }

    static void bubbleSortWithCounter(int[] array) {
        int size = array.length;

        for (int pass = 0; pass < size - 1; pass++) {
            boolean swappedThisPass = false;

            for (int index = 0; index < size - pass - 1; index++) {
                comparisonCount++; // Count every comparison we make

                if (array[index] > array[index + 1]) {
                    int temp = array[index];
                    array[index] = array[index + 1];
                    array[index + 1] = temp;
                    swappedThisPass = true;
                }
            }

            if (!swappedThisPass) break;
        }
    }

    // Builds an array [n, n-1, n-2, ..., 2, 1] — the worst case for Bubble Sort
    static int[] buildReverseSortedArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = size - i; // Fills from largest to smallest
        }
        return array;
    }
}
Output
Demonstrating how comparison count scales with input size:
Array Size (n) Comparisons Made n² (theoretical)
-------------------------------------------------------
5 10 25
10 45 100
20 190 400
50 1225 2500
100 4950 10000
Notice: actual comparisons ≈ n²/2, which is still O(n²).
Watch Out: Don't use Bubble Sort on large datasets
On an array of 10,000 elements, Bubble Sort makes ~50 million comparisons in the worst case. Merge Sort handles the same array in ~130,000 operations. That's not a small difference — it's the difference between instant and painfully slow. Use Bubble Sort to learn sorting concepts; use Merge Sort or Arrays.sort() in real code.
Production Insight
A 10x increase in input size leads to a 100x increase in comparisons for Bubble Sort.
If you accidentally ship this to sort a 50k-element CSV, your batch job will time out.
The O(n²) curve is not theoretical — it's the difference between 0.1s and 10 minutes.
Key Takeaway
Bubble Sort is O(n²) average/worst, O(n) best with early exit.
Space is O(1) — the only genuine strength.
Use built-in sorts for anything above ~100 elements.

Sorting Strings and Real Objects — Bubble Sort Isn't Just for Numbers

Everything we've done so far sorted integers, but in the real world you'll sort names, products, grades — anything. Bubble Sort's comparison step is the only thing that changes. For strings, Java's compareTo() method does the heavy lifting: it returns a negative number if the first string comes before the second alphabetically, zero if they're equal, and a positive number if it comes after.

This is a great moment to understand what 'sorting' really means. The algorithm itself — the passes, the comparisons, the swaps — stays identical. Only the definition of 'which one is bigger' changes. This is why sorting algorithms are often taught with Comparators in production code: you separate the sorting logic from the comparison logic cleanly.

Sorting strings alphabetically is also a great way to cement your understanding because you can verify the output easily in your head. Try tracing through the passes yourself on paper before running the code — that's genuinely the fastest way to make this algorithm stick in your memory.

BubbleSortStrings.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class BubbleSortStrings {

    public static void main(String[] args) {

        // A list of student names that need to be sorted alphabetically
        String[] studentNames = {"Zara", "Ahmed", "Maya", "Liam", "Sofia", "Ben"};

        System.out.println("Student names before sorting:");
        printNames(studentNames);

        alphabeticalBubbleSort(studentNames);

        System.out.println("\nStudent names after sorting:");
        printNames(studentNames);
    }

    static void alphabeticalBubbleSort(String[] names) {
        int size = names.length;

        for (int pass = 0; pass < size - 1; pass++) {
            boolean swappedThisPass = false;

            for (int index = 0; index < size - pass - 1; index++) {

                // compareTo() returns a positive number when names[index]
                // comes AFTER names[index+1] alphabetically.
                // That means they're in the wrong order — swap them.
                if (names[index].compareTo(names[index + 1]) > 0) {

                    String temp = names[index];
                    names[index] = names[index + 1];
                    names[index + 1] = temp;

                    swappedThisPass = true;
                }
            }

            if (!swappedThisPass) {
                break; // Early exit if already sorted
            }
        }
    }

    static void printNames(String[] names) {
        for (String name : names) {
            System.out.print(name + "  ");
        }
        System.out.println();
    }
}
Output
Student names before sorting:
Zara Ahmed Maya Liam Sofia Ben
Student names after sorting:
Ahmed Ben Liam Maya Sofia Zara
compareTo() is case-sensitive — uppercase comes before lowercase in Java
"Apple".compareTo("banana") will put Apple before banana, but "apple".compareTo("Banana") will put Banana first. That's because uppercase letters have lower ASCII values. To sort case-insensitively, use compareToIgnoreCase() instead — a small change that avoids a confusing bug.
Production Insight
Case-sensitivity in string comparison leads to hard-to-spot bugs in customer-facing lists.
If you sort "Bob", "alice", "Charlie" alphabetically with default compareTo, you'll get "Bob", "Charlie", "alice" — not what users expect.
Always ask: should this sort be case-insensitive? Use a Comparator or compareToIgnoreCase accordingly.
Key Takeaway
Only the comparison logic changes when sorting non-numeric types.
Use Comparable or Comparator to separate algorithm from comparison.
Watch out for case sensitivity — it's the #1 string sorting bug.

Python and C++ Implementations

Bubble Sort is language-agnostic — the same logic translates directly to Python and C++. Below is a Python implementation with the swapped flag. In C++, the syntax changes slightly: use std::vector or arrays, and the swap can be done with std::swap or a manual temp. The key differences: Python uses range and list indexing, while C++ uses for loops and std::swap. Both exhibit O(n²) worst-case and O(n) best-case with early exit.

A C++ version would look similar: iterate over indices, compare arr[i] > arr[i+1], and use std::swap(arr[i], arr[i+1]). The early-exit flag works identically.

bubble_sort.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def optimized_bubble_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        swapped = False
        for j in range(n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        if not swapped:
            break
    return arr

# Example usage
scores = [5, 3, 8, 1, 4]
print("Before:", scores)
optimized_bubble_sort(scores)
print("After:", scores)
Output
Before: [5, 3, 8, 1, 4]
After: [1, 3, 4, 5, 8]
Key Takeaway
The algorithm is identical across languages — only syntax changes. Python's swap syntax is especially clean.

C++ Implementation

Below is a C++ implementation of Bubble Sort with early exit. The logic mirrors the Java and Python versions: outer loop for passes, inner loop for comparisons, swapped flag for early termination. This version sorts an array of integers in ascending order.

bubble_sort.cppCPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>
using namespace std;

void bubbleSort(vector<int>& arr) {
    int n = arr.size();
    for (int pass = 0; pass < n - 1; ++pass) {
        bool swapped = false;
        for (int i = 0; i < n - pass - 1; ++i) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                swapped = true;
            }
        }
        if (!swapped) break;
    }
}

int main() {
    vector<int> data = {5, 3, 8, 1, 4};
    bubbleSort(data);
    for (int x : data) cout << x << " ";
    return 0;
}
Output
1 3 4 5 8
C++ swap() is efficient
Using std::swap() avoids manual temp variable and may use move semantics for complex types.
Key Takeaway
C++ implementation is nearly identical to Java/Python; the early exit flag works the same way.

Recursive Bubble Sort and Cocktail Sort — Variations That Expand Your Understanding

Bubble Sort is almost always implemented iteratively, but it can also be written recursively. The recursive version reduces the problem size by one each call — the largest element bubbles to the end, then you call recursively on the rest of the array. It's not more efficient, but it's a great exercise in thinking recursively about algorithms.

Another practical variant is Cocktail Sort (a.k.a. Shaker Sort). Instead of always moving left to right, Cocktail Sort alternates direction — it goes left to right, then right to left, then left to right again. This helps when the smallest elements are near the end of the array. In standard Bubble Sort, a small value at the end takes many passes to move all the way left. Cocktail Sort handles that in one back-and-forth sweep.

Cocktail Sort is still O(n²) worst-case, but it can cut the number of passes in half on certain inputs (e.g., an array where the first half is sorted descending and the second half is sorted ascending). It's worth knowing about because interviewers sometimes ask: 'How would you improve Bubble Sort without changing the fundamental approach?'

RecursiveAndCocktailSort.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class RecursiveAndCocktailSort {

    // Recursive Bubble Sort
    public static void recursiveBubbleSort(int[] arr, int n) {
        if (n <= 1) return;
        boolean swapped = false;
        for (int i = 0; i < n - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                int temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
                swapped = true;
            }
        }
        if (!swapped) return; // already sorted
        recursiveBubbleSort(arr, n - 1);
    }

    // Cocktail Shaker Sort
    public static void cocktailSort(int[] arr) {
        boolean swapped = true;
        int start = 0;
        int end = arr.length - 1;

        while (swapped) {
            swapped = false;

            // Left to right
            for (int i = start; i < end; i++) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                    swapped = true;
                }
            }
            if (!swapped) break;
            end--;
            swapped = false;

            // Right to left
            for (int i = end - 1; i >= start; i--) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                    swapped = true;
                }
            }
            start++;
        }
    }

    public static void main(String[] args) {
        int[] test1 = {5, 1, 4, 2, 8};
        recursiveBubbleSort(test1, test1.length);
        System.out.println("Recursive: " + java.util.Arrays.toString(test1));

        int[] test2 = {5, 1, 4, 2, 8};
        cocktailSort(test2);
        System.out.println("Cocktail:   " + java.util.Arrays.toString(test2));
    }
}
Output
Recursive: [1, 2, 4, 5, 8]
Cocktail: [1, 2, 4, 5, 8]
Why Cocktail Sort Moves Two Ways
  • Standard Bubble Sort only moves large elements right; small elements crawl left one step per pass.
  • Cocktail Sort alternates passes left-to-right, then right-to-left, moving large and small simultaneously.
  • It reduces passes when the array has a 'rabbit' (small value near the end) or 'turtle' (large value near the start).
  • Worst-case remains O(n²), but average comparisons can be ~25% fewer on random data.
  • Interviewers love this variant as a way to discuss trade-offs without changing data structure.
Production Insight
Cocktail Sort introduces a second direction which can cause off-by-one errors in the inner loop bounds.
In production sorting code, you never roll your own — but understanding variants helps you appreciate why library sorts like TimSort use a hybrid approach.
If you ever need a simple sort for tiny data with known direction biases, Cocktail Sort is a safe bet.
Key Takeaway
Recursive versions reduce problem size by one each call — good for learning recursion.
Cocktail Sort alternates direction to handle small values near the end faster.
Variants don't change Big-O but show deeper understanding of the algorithm.

Advantages and Disadvantages of Bubble Sort

Bubble Sort, despite its poor large-scale performance, has specific strengths that make it useful in limited contexts.

Advantages: - Simplicity: The algorithm is easy to understand, implement, and debug. It's often the first sorting algorithm taught. - In-place: Uses O(1) extra space — only a single temp variable for swapping. - Stable: Preserves the relative order of equal elements. Important for multi-key sorts. - Adaptive with optimization: The swapped flag makes it O(n) on already-sorted data. - Detects sorted arrays: It can stop early, which no comparably simple sort like Selection Sort can do.

Disadvantages: - Slow on large data: O(n²) time complexity makes it impractical for arrays beyond a few hundred elements. - Many swaps: Even when elements are only slightly out of place, many swaps occur, increasing overhead. - Rarely used in practice: Production systems rely on O(n log n) algorithms (Quick Sort, Merge Sort, TimSort). - Not efficient for modern hardware: Cache-unfriendly due to many traversals of the entire array.

bubble_sort_simple.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
// Minimal Bubble Sort without early exit (for demonstration only)
function bubbleSort(arr) {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // swap
      }
    }
  }
  return arr;
}

console.log(bubbleSort([4, 2, 9, 1])); // [1, 2, 4, 9]
Output
[1, 2, 4, 9]
Key Takeaway
Bubble Sort's strengths are simplicity, stability, and low space — its weakness is quadratic time. Use it only for learning or tiny datasets.

Advantages and Disadvantages Table

Here is a concise table summarizing the pros and cons of Bubble Sort:

AdvantageDescription
SimplicityEasy to understand and implement.
In-place sortingO(1) extra space.
StabilityMaintains relative order of equal elements.
AdaptiveO(n) best case with early exit flag.
DisadvantageDescription
Slow on large dataO(n²) time complexity.
Many swapsInefficient on modern hardware.
Rarely usedBuilt-in sorts are preferred.
bubble_sort_pros_cons.txtTEXT
1
2
3
4
5
6
7
8
9
10
Advantages:
- Simplicity: Easy to understand and implement.
- In-place: O(1) space.
- Stable: Preserves equal element order.
- Adaptive: O(n) with early exit.

Disadvantages:
- Slow: O(n²) time.
- Many swaps: Inefficient.
- Rarely used: Not practical for large datasets.
Key Takeaway
Bubble Sort's main advantages are simplicity and stability; its main disadvantage is quadratic time complexity.

Applications — When to Accept O(n²)

Bubble Sort's O(n²) complexity is a dealbreaker for large datasets, but there are specific scenarios where its simplicity outweighs the cost:

  • Very small n (≤20 elements): The absolute runtime for O(n²) on 20 elements is negligible (≈190 comparisons). The simplicity and low overhead justify using it.
  • Nearly sorted data: If you know the data is almost in order (e.g., a list that had a few insertions), bubble sort with early exit runs in roughly O(n) because few swaps are needed.
  • Educational purposes: Teaching the concept of sorting, pass-by-pass visualisation, and algorithm analysis. No other sort illustrates the mechanics as cleanly.
  • Embedded systems: When code size is constrained and you need a simple, small sort routine for tiny arrays.

In all other cases, use a built-in sort (O(n log n)). A good rule of thumb: if the array fits on one line of code (say, under 30 elements), Bubble Sort is acceptable. Otherwise, reach for Arrays.sort(), sorted(), or similar.

BubbleSortGuard.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class BubbleSortGuard {
    public static void safeSort(int[] arr) {
        // Only use Bubble Sort for very small arrays
        if (arr.length <= 20) {
            optimizedBubbleSort(arr);
        } else {
            // Fall back to built-in Quicksort for larger data
            java.util.Arrays.sort(arr);
        }
    }

    static void optimizedBubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    swapped = true;
                }
            }
            if (!swapped) break;
        }
    }
}
Key Takeaway
Accept O(n²) only when n is tiny, data is nearly sorted, or the goal is learning. For everything else, use a production-grade sort.

The Idea: Swapping Neighbors Until Order Emerges

Bubble Sort’s entire existence is built on one brute‑force principle: walk the array, compare each pair of adjacent items, and if they’re out of order, swap them. Repeat until a full pass produces zero swaps. That’s it. No clever divide‑and‑conquer, no insertion of holes.

Why does that work? After the first pass, the single largest element has “bubbled” all the way to the end. After the second, the second‑largest is in its final position. Every pass locks down one more element on the right. This is why the inner loop can shrink by i each time — you don’t need to touch already‑sorted tail. The algorithm is O(n²) because you’re essentially doing n passes of length roughly n/2 on average. Production teams avoid it for anything over a few hundred elements, but its relentless simplicity makes it the ideal teaching tool: you can see every decision, every swap, and every wasted comparison with your own eyes.

BubbleSortBaseline.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// io.thecodeforge — dsa tutorial

public class BubbleSortBaseline {
    public static void bubbleSort(int[] inventory) {
        int n = inventory.length;
        for (int pass = 0; pass < n - 1; pass++) {
            for (int j = 0; j < n - pass - 1; j++) {
                if (inventory[j] > inventory[j + 1]) {
                    int temp = inventory[j];
                    inventory[j] = inventory[j + 1];
                    inventory[j + 1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] inventory = {5, 3, 8, 2};
        bubbleSort(inventory);
        for (int id : inventory) {
            System.out.print(id + " ");
        }
    }
}
Output
2 3 5 8
Senior Shortcut:
Bubble Sort is the only sorting algorithm where the main loop index has no significance beyond counting passes. Compare that with selection sort (which finds the minimum) or insertion sort (which builds a sorted prefix).
Key Takeaway
Bubble Sort is the sorting algorithm you write because you want to watch the largest element 'bubble' to the end, one swap at a time.

Step-by-Step: What Actually Happens Inside the Array

Words are cheap. Let’s walk the array [5, 3, 8, 2] and see the blood and guts.

Pass 1: compare 5 and 3 — 5 > 3, swap. Array becomes [3, 5, 8, 2]. Next compare 5 and 8 — no swap. Then compare 8 and 2 — 8 > 2, swap. End of pass 1: [3, 5, 2, 8]. The 8 is locked.

Pass 2: compare 3 and 5 — no swap. Compare 5 and 2 — 5 > 2, swap. End of pass 2: [3, 2, 5, 8]. The 5 is locked.

Pass 3: compare 3 and 2 — 3 > 2, swap. End of pass 3: [2, 3, 5, 8]. All locked. With an early‑exit flag, you would break after this pass because no swaps happened in pass 4 (checking 2 and 3). Every comparison is explicit. Every swap is visible. That transparency is why Bubble Sort is the worst for performance but the best for learning how sorting really works.

BubbleSortTrace.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// io.thecodeforge — dsa tutorial

public class BubbleSortTrace {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int pass = 1; pass <= n - 1; pass++) {
            System.out.print("Pass " + pass + ": ");
            for (int j = 0; j < n - pass; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            for (int val : arr) System.out.print(val + " ");
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[] data = {5, 3, 8, 2};
        bubbleSort(data);
    }
}
Output
Pass 1: 3 5 2 8
Pass 2: 3 2 5 8
Pass 3: 2 3 5 8
Production Trap:
Don’t use the fully unoptimized version that always runs n-1 passes — it will scan already‑sorted arrays O(n²). Always include the swapped flag; it drops best case to O(n).
Key Takeaway
Trace every swap. Watching the array stabilize one element at a time is the fastest path to understanding how sorting algorithms build order step by step.

Pseudocode First — Why You Should Sketch Before You Code

You wouldn't weld a chassis without a blueprint. So why do juniors open an IDE and start thrashing? Bubble sort is simple, but the discipline of writing pseudocode first saves you from off-by-one errors and infinite loops. It forces you to think in logic, not syntax.

The core loop is embarrassingly simple: march through the array, compare each element with its neighbor, swap if the left is bigger. Repeat until no swaps happen in a full pass. That's it.

What pseudocode reveals: the swap flag. That tiny boolean is the difference between O(n²) every time and O(n) when the array is already sorted. Without pseudocode you miss optimizations. With it, you see the structure before you write a single line of Java. Ship less broken code.

BubbleSortPseudocode.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// io.thecodeforge — dsa tutorial

public class BubbleSortPseudocode {
    // Translating the pseudocode:
    // procedure bubbleSort(A: list of sortable items)
    //     n = length(A)
    //     repeat
    //         swapped = false
    //         for i = 1 to n-1 inclusive do
    //             if A[i-1] > A[i] then
    //                 swap(A[i-1], A[i])
    //                 swapped = true
    //             end if
    //         end for
    //         n = n - 1
    //     until not swapped
    // end procedure

    public static void main(String[] args) {
        int[] arr = {5, 1, 4, 2, 8};
        bubbleSort(arr);
        for (int v : arr)
            System.out.print(v + " ");
    }

    static void bubbleSort(int[] a) {
        int n = a.length;
        boolean swapped;
        do {
            swapped = false;
            for (int i = 1; i < n; i++) {
                if (a[i - 1] > a[i]) {
                    int t = a[i - 1];
                    a[i - 1] = a[i];
                    a[i] = t;
                    swapped = true;
                }
            }
            n--;
        } while (swapped);
    }
}
Output
1 2 4 5 8
Senior Shortcut:
Write the swap flag first. If you start coding without it, you're signing up for wasted CPU cycles on sorted data.
Key Takeaway
Pseudocode exposes algorithm structure before syntax hides it — always sketch the loop and the exit condition first.

Stability Explained — Why Order Matters for Non-Primitives

Bubble sort is stable. That's a fancy way of saying identical elements keep their original relative order after sorting. For integers it doesn't matter. For a list of users sorted by registration date, then bubble sorted by name — stability means the earlier registrant stays first among same names.

Why you should care: unstable sorts reshuffle your data. If you sorted by city then by name, an unstable sort loses your city order. Bubble sort preserves it. That's a feature, not a bug.

In production you rarely use bubble sort for large data — but when you need stability on tiny arrays or near-sorted lists, this matters. Java's Collections.sort() is stable too, but bubble sort is embarrassingly simple to audit. Know what your sort does to your data's history.

StableBubble.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// io.thecodeforge — dsa tutorial

class User {
    String name;
    int regDay;
    User(String n, int d) { name = n; regDay = d; }
    public String toString() { return name + ":" + regDay; }
}

public class StableBubble {
    public static void main(String[] args) {
        User[] users = {
            new User("Alice", 1),
            new User("Bob", 2),
            new User("Alice", 3)
        };
        // Bubble sort by name (ascending)
        for (int i = 0; i < users.length - 1; i++)
            for (int j = 0; j < users.length - 1 - i; j++)
                if (users[j].name.compareTo(users[j+1].name) > 0) {
                    User t = users[j];
                    users[j] = users[j+1];
                    users[j+1] = t;
                }
        for (User u : users)
            System.out.print(u + " ");
    }
}
Output
Alice:1 Alice:3 Bob:2
Production Trap:
If you switch to an unstable sort like quicksort, you'll silently corrupt multi-key ordering. Bubble sort's stability keeps your data's timeline intact.
Key Takeaway
Stability preserves original order of equal elements — bubble sort is stable, so it's safe for compound sort keys.

BubbleSortDemo — Interactive Visualization Changes Everything

Most explanations of Bubble Sort show static diagrams, but real understanding comes from watching the algorithm fight against unsorted data. A BubbleSortDemo tool lets you step through each comparison and swap, revealing exactly why O(n²) performance hurts. When you run the demo on a reversed array, you see every element dragged across the entire array one position at a time—that's the worst-case scenario in action. The demo also highlights the optimized early-stop condition: if a full pass completes with zero swaps, the algorithm halts immediately. This visual feedback teaches you more than a textbook ever will: Bubble Sort is only fast when the array is nearly sorted. For any random or reversed dataset, you watch the loop count explode. The demo reinforces one brutal truth—never let Bubble Sort near production code unless you absolutely know the input size is tiny and stays that way.

BubbleSortDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// io.thecodeforge — dsa tutorial

public class BubbleSortDemo {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        boolean swapped;
        for (int i = 0; i < n - 1; i++) {
            swapped = false;
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    swapped = true;
                }
            }
            if (!swapped) break;
        }
    }

    public static void main(String[] args) {
        int[] data = {5, 1, 4, 2, 8};
        bubbleSort(data);
        for (int v : data) System.out.print(v + " ");
    }
}
Output
1 2 4 5 8
Production Trap:
Running BubbleSortDemo on a 10,000-element array will make your laptop fan spin. The demo exposes why n² algorithms are a liability at scale.
Key Takeaway
Always visualize Bubble Sort before trusting it. The demo proves early-stop optimization is useless when data is random.

What We'll Cover — Setting the Agenda Before You Code

Before writing a single line of Bubble Sort, you need a roadmap. The "What We'll Cover" section defines the scope: we start with why bubble sort is a cautionary tale for production engineers, then dissect the neighbor-swapping mechanism, walk through one full pass with a small array, introduce the optimization that detects sorted arrays early, and finally analyze time and space complexity with concrete Big-O reasoning. We also cover stability—why the algorithm preserves the relative order of equal elements—and practical applications like sorting tiny datasets or nearly-sorted lists where the overhead of quicksort doesn't pay off. By the end, you will know exactly when to use Bubble Sort (almost never) and when to walk away (almost always). This agenda prevents scope creep: no recursive variations, no cocktail sort, just the core algorithm and its real-world trade-offs. The goal is decision confidence, not code memorization.

BubbleSortAgenda.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — dsa tutorial

public class BubbleSortAgenda {
    // 1. Why Bubble Sort fails at scale
    // 2. Neighbor-swapping passes
    // 3. Early-stop optimization
    // 4. Stability for object sorting
    // 5. When O(n²) is acceptable
    public static void main(String[] args) {
        int[] arr = {3, 0, 2, 1};
        boolean swapped;
        for (int i = 0; i < arr.length - 1; i++) {
            swapped = false;
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int t = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = t;
                    swapped = true;
                }
            }
            if (!swapped) break;
        }
    }
}
Output
(no output — demonstration skeleton)
Why This Matters:
Skipping the roadmap leads to off-topic tangents. This section keeps you focused on Bubble Sort's single merit: simplicity, not speed.
Key Takeaway
Know what you're learning and why before you code. Bubble Sort teaches debugging instincts, not performance patterns.
● Production incidentPOST-MORTEMseverity: high

The Time Bubble Sort Slowed a Payment Batch to a Crawl

Symptom
Payment reconciliation batch job suddenly times out after an hour. No error logs, no GC pressure, just unresponsive process.
Assumption
The database query was slow — added more indexes but no improvement.
Root cause
A new developer implemented Bubble Sort (basic version, no early exit) to sort a list of 50,000 integer transaction IDs before inserting them into a batch. The algorithm performed ~1.25 billion comparisons (n²/2), taking 12 minutes instead of the expected 0.3 seconds with Arrays.sort().
Fix
Replaced Bubble Sort with Java's built-in Dual-Pivot Quicksort (Arrays.sort()). The sorting step dropped from 12 minutes to under 50 milliseconds.
Key lesson
  • Never use Bubble Sort on arrays larger than a few dozen elements in production code.
  • Always rely on language-built-in sorting utilities for real-world data.
  • A performance test on a small sample (50 items) would have caught this before production.
Production debug guideTrace through common bugs that turn up in code reviews and interviews3 entries
Symptom · 01
Sort puts largest element at start instead of end (ascending order)
Fix
Check comparison operator: use > to swap when left > right. Using < reverses the order. This is the most common single-line bug.
Symptom · 02
Sorted array has one element out of place after all passes
Fix
Verify inner loop bound: use size - pass - 1 not size - 1. The $-pass$ shrinks the window, but if you forget the $-1$ you go one index beyond the array and get an ArrayIndexOutOfBoundsException or undefined behavior.
Symptom · 03
Algorithm never terminates or runs too many passes
Fix
Add the swapped flag. If it's missing, code loops n-1 times even when sorted. Check that swapped resets to false at start of each outer pass and breaks correctly.
★ Bubble Sort Quick Debug Cheat SheetBuilt for code reviews and interview debugging — fix the 3 most common Bubble Sort issues instantly.
Output is reverse sorted (ascending expected)
Immediate action
Flip the comparison operator: `>` for ascending, `<` for descending.
Commands
Assume `int[] arr = {5,3,8,1,4};` After first pass with `>` you get `[3,5,1,4,8]` (largest at end). If you get `[4,1,3,5,8]` your operator is wrong.
Add `System.out.println("Comparing " + a[i] + " and " + a[i+1]);` inside inner loop to trace logic.
Fix now
Change if (arr[i] > arr[i+1]) to correct direction.
ArrayIndexOutOfBoundsException at line with swap+
Immediate action
Check inner loop condition — must be `j < size - pass - 1`.
Commands
Print `size - pass - 1` at start of each pass. If it is negative or zero, the outer loop bound is wrong.
Log `pass` and `size` values — ensure `pass < size - 1` in outer loop.
Fix now
Correct the inner loop: for (int j = 0; j < size - pass - 1; j++).
Already-sorted array runs all passes (no early exit)+
Immediate action
Add a boolean flag `swapped` that resets to false each pass and breaks outer loop if no swap occurred.
Commands
Add `boolean swapped = false;` before inner loop. Set to `true` on swap. After inner loop, if `!swapped` break.
Print `swapped` value at end of each pass to verify.
Fix now
Implement the flag and early break as shown in Optimized Bubble Sort.
Bubble Sort vs Selection Sort
AspectBubble SortSelection Sort
Best-case timeO(n) — with early exit flagO(n²) — always scans full array
Worst-case timeO(n²)O(n²)
Space complexityO(1) — in-placeO(1) — in-place
Number of swapsHigh — swaps at every out-of-order pairLow — at most one swap per pass
Stable sort?Yes — equal elements keep original orderNo — can swap equal elements past each other
Detects sorted array?Yes — with the swapped flag optimizationNo — always runs all passes
Best real-world useNearly sorted small arraysWhen minimising writes/swaps matters most

Key takeaways

1
Bubble Sort repeatedly compares adjacent pairs and swaps them if out of order
the largest unsorted element 'bubbles' to its correct position at the end of each pass.
2
Always include the 'swapped' early-exit flag. Without it, you have O(n²) best case. With it, you have O(n) best case
a critical difference on nearly-sorted data.
3
Bubble Sort is O(n²) in the average and worst case, making it impractical for large datasets
but its O(1) space complexity and simplicity make it a perfect teaching algorithm and fine for tiny arrays.
4
Bubble Sort is stable
equal elements never swap past each other, which means their original relative order is preserved — a property that matters when sorting objects by multiple fields.
5
Cocktail Sort (shaker sort) is a variant that alternates direction, reducing passes on certain inputs while remaining O(n²).
6
In production, never use Bubble Sort for arrays greater than about 20 elements
use Arrays.sort() or a proper O(n log n) algorithm.

Common mistakes to avoid

4 patterns
×

Forgetting to shrink the inner loop each pass

Symptom
The algorithm still works, but you're wastefully re-comparing elements already in their final sorted positions — much slower on large arrays, and can even cause out-of-bounds on the last index because you compare arr[last] with arr[last+1].
Fix
Make the inner loop condition index < size - pass - 1. The - pass shrinks the window each round. The -1 prevents accessing arr[index+1] past the end.
×

Skipping the 'swapped' early-exit flag

Symptom
On an already-sorted or nearly-sorted array, the algorithm runs all n-1 passes anyway — showing your interviewer you haven't thought through the best case.
Fix
Add a boolean swappedThisPass = false before the inner loop, set it to true on any swap, and break out of the outer loop immediately if it's still false after a full pass.
×

Using the wrong comparison operator for descending order

Symptom
You change > to < and expect it to sort largest-to-smallest, but you get confused when the logic feels backwards.
Fix
Think of it as 'if the left element is smaller than the right, they're in the wrong order for descending sort' — so array[index] < array[index + 1] is correct for descending. Rename your variable to make the intent clear: boolean wantDescending = true; and comment the comparison direction.
×

Not understanding stable sort implications

Symptom
When sorting objects by multiple fields (e.g., first by grade, then by name), Bubble Sort's stability preserves the order of equal elements, but if you write an unstable sort manually, you'll scramble secondary sorts.
Fix
Recognise that Bubble Sort's stability is a feature: it only swaps when left > right. If left == right, no swap, so original order is kept. Use this property when writing multi-key sorts.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the time complexity of Bubble Sort in the best, average, and wor...
Q02JUNIOR
How would you modify Bubble Sort to stop early if the array is already s...
Q03SENIOR
Is Bubble Sort a stable sorting algorithm? What does 'stable' mean, and ...
Q04SENIOR
Can you implement Bubble Sort recursively? How does the approach compare...
Q01 of 04JUNIOR

What is the time complexity of Bubble Sort in the best, average, and worst case — and what input triggers each?

ANSWER
Best case: O(n) when the array is already sorted and you use the swapped flag (one pass, zero swaps). Average case: O(n²) for random data. Worst case: O(n²) when the array is reverse-sorted (maximum comparisons and swaps every pass). The comparison count is roughly n²/2 in the worst case. Interview tip: Always mention the swapped flag when discussing best case — it shows you know the optimisation, not just the textbook number.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Is bubble sort ever actually used in real software?
02
Why is it called Bubble Sort?
03
What's the difference between a pass and a comparison in Bubble Sort?
04
Can Bubble Sort be made adaptive to nearly-sorted data?
05
How does Bubble Sort compare to Insertion Sort for small arrays?
N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Written from production experience, not tutorials.

Follow
Verified
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
🔥

That's Sorting. Mark it forged?

13 min read · try the examples if you haven't

Previous
A* Search Algorithm
1 / 8 · Sorting
Next
Selection Sort