Bubble sort
On This Lesson 11 topics
Lesson Overview
Binary search needs sorted data, so now we learn how to sort. Bubble sort is the easiest sorting algorithm to understand: compare two neighbours, swap them if they are in the wrong order, and sweep along the array. After one sweep, the largest value has "bubbled" to the end. Repeat the sweeps and the whole array ends up sorted.
Bubble sort is slow on big arrays and real programs rarely use it. We study it because it is small, it shows how nested loops do real work, and it is the best practice for tracing an algorithm by hand, which is exactly what the assessment for this module asks you to do.
Why this matters: sorting questions are standard in junior interviews, and being able to trace a sort pass by pass shows that you understand loops and arrays rather than memorising code.
This lesson builds on binary search, nested loops, arrays, and swapping two values with a temporary variable.
Learning Objectives
By the end of this lesson you will be able to:
- Describe bubble sort as repeated passes that swap out-of-order neighbours.
- Explain what one pass guarantees about the largest value.
- Implement bubble sort for an
int[]with two nested loops. - Trace bubble sort on a small array, showing the array after each pass.
- Explain why the inner loop gets shorter on every pass.
- Add an early exit using a
swappedflag. - State roughly how many comparisons bubble sort makes and why it is slow.
Written Explanation
The idea
Stand five people in a line and ask each neighbouring pair, from left to right: "If the person on the left is taller, swap places." After one sweep the tallest person has been carried all the way to the right end, because every time they met someone shorter, they swapped forward. Repeat the sweep, and the second tallest settles next to the end, and so on.
For {4, 2, 3}:
- Compare 4 and 2: out of order, swap, giving
{2, 4, 3}. - Compare 4 and 3: out of order, swap, giving
{2, 3, 4}.
One pass has moved 4, the largest, to the end. Here the array happens to be sorted already, but the algorithm does not know that yet.
The swap
Swapping two array positions needs a temporary variable. Writing a[i] = a[i + 1]; a[i + 1] = a[i]; would lose the original a[i]. The correct pattern:
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;The code
static void bubbleSort(int[] a) {
for (int pass = 0; pass < a.length - 1; pass++) {
for (int i = 0; i < a.length - 1 - pass; i++) {
if (a[i] > a[i + 1]) {
int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t;
}
}
}
}The method returns void because it changes the array it is given. The method receives the same array the caller has, not a copy, so the caller sees the sorted array. If you need the original order kept, copy the array first.
Why these bounds?
- The inner loop compares
a[i]witha[i + 1], soimust stop ata.length - 2, hencei < a.length - 1for the first pass. Without that limit the code would read past the end. - After each pass the last
pass + 1positions already hold the largest values in their final places. The- passmakes the inner loop skip them, so it gets shorter each time. - The outer loop needs at most
a.length - 1passes: once all but one element are in place, the last one must be in place too.
Tracing it
To trace {7, 3, 9, 1, 5}, write the array after each pass. A version of the method that prints the array and a swapped flag after each pass gives:
after pass 1: [3, 7, 1, 5, 9] swapped=true
after pass 2: [3, 1, 5, 7, 9] swapped=true
after pass 3: [1, 3, 5, 7, 9] swapped=true
after pass 4: [1, 3, 5, 7, 9] swapped=falseReading pass 1 in detail:
| compare | action | array |
|---|---|---|
| 7 and 3 | swap | 3 7 9 1 5 |
| 7 and 9 | no swap | 3 7 9 1 5 |
| 9 and 1 | swap | 3 7 1 9 5 |
| 9 and 5 | swap | 3 7 1 5 9 |
The 9, the largest, is now at the end, as promised. Pass 2 does the same for the rest (excluding the last place), and so on.
Stopping early
If a whole pass makes no swaps, every neighbour pair is in order, so the array is sorted and we can stop. A boolean flag does this:
for (int pass = 0; pass < a.length - 1; pass++) {
boolean swapped = false;
for (int i = 0; i < a.length - 1 - pass; i++) {
if (a[i] > a[i + 1]) {
int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t;
swapped = true;
}
}
if (!swapped) return;
}On an array that is already sorted this finishes after a single pass.
How slow is it?
With the shrinking inner loop, the passes compare n - 1, then n - 2, and so on down to 1 pair. For 5 elements that is 4 + 3 + 2 + 1 = 10 comparisons; for 40 elements it is 780. The total grows roughly like n × n: double the data and the work about quadruples. A thousand elements already means about half a million comparisons. This is why bubble sort is a teaching tool and not a production choice.
Examples
Example 1: tracing a tiny array (simple)
{4, 2, 3} with the flag version:
after pass 1: [2, 3, 4] swapped=true
after pass 2: [2, 3, 4] swapped=falsePass 1 compares 4 > 2 (swap) and then 4 > 3 (swap), so the 4 travels to the end. Pass 2 compares only the first pair, 2 > 3, finds nothing to swap, and the flag tells us we are done.
Example 2: sorting exam scores and checking the result (practical)
int[] sc = {88, 61, 95, 70, 61};
bubbleSort(sc);
System.out.println(Arrays.toString(sc));Output:
[61, 61, 70, 88, 95]Repeated values (61 twice) are no problem: the test a[i] > a[i + 1] is false for equal neighbours, so they are not swapped. Edge cases also work, with no special code. For {} and {9} the outer loop does not run, since a.length - 1 is -1 and 0, and the arrays are printed unchanged: [] [9]. A good habit is to call isSorted from the first lesson on the result in a test.
Example 3: sorting in the other direction (realistic)
A leaderboard needs the highest score first. The only change is the comparison:
if (a[i] < a[i + 1]) { // was >
int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t;
}Run on {2, 9, 4, 7} this prints:
[9, 7, 4, 2]Now the smallest value bubbles to the end of each pass. Changing which direction counts as "out of order" is the usual way to flip a sort. (In real code you would normally use Arrays.sort and then deal with the order, which you will meet in later modules.)
Backend Insight
You will almost never write bubble sort in a service. The Java library's Arrays.sort is tested and fast; its documentation describes a Dual-Pivot Quicksort for int[], advertised as O(n log(n)) on all data sets, and notes that this is an implementation note and may change. What you do take from bubble sort is the cost model: nested loops over the same data mean work that grows like n × n. That pattern is a classic cause of slow endpoints, for example when code compares every order with every other order for 50,000 orders. Spotting a loop inside a loop over the same data is a basic review skill.
Also remember the contract: sorting methods that change the array in place change it for every part of the program that holds a reference to it. Copy first when others depend on the original order.
Common Mistakes
Mistake 1: Swapping without a temporary variable
Assigning a[i] = a[i + 1]; a[i + 1] = a[i]; leaves both positions with the same value. Use t.
Mistake 2: Off-by-one in the inner loop
i < a.lengthmakesa[i + 1]read past the end and throwsArrayIndexOutOfBoundsExceptionon the last pair.i < a.length - 1 - passis correct. Forgetting- passstill gives the right answer, but does wasted comparisons.
Mistake 3: Using >= for the comparison
a[i] >= a[i + 1] swaps equal neighbours. The result is still sorted, but equal values are swapped for no reason, and the swapped flag is set even when nothing really changed, so the early exit can stop working on arrays with duplicates.
Mistake 4: Thinking one pass sorts everything
One pass only fixes one value, the largest of the unsorted part. Several passes are needed. Tracing a short array shows this immediately.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. After the first pass of bubble sort, where is the largest value?
Show solution A1
A1. At the end (the last position of the array).
A2. Write the three lines that swap a[i] and a[i + 1].
Show solution A2
A2.
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;A3. How many comparisons does bubble sort (with the shrinking inner loop and no early exit) make on 5 elements?
Show solution A3
A3. 4 + 3 + 2 + 1 = 10.
Level B: Application
B1. Trace bubble sort on {6, 2, 5, 1} and write the array after each pass.
Show solution B1
B1.
after pass 1: [2, 5, 1, 6]
after pass 2: [2, 1, 5, 6]
after pass 3: [1, 2, 5, 6]In pass 1 the 6 moves right past 2, 5 and 1 (it swaps with each). In pass 2 the 5 settles, and in pass 3 the pair 2, 1 is swapped. After three passes (n - 1) the array is sorted.
B2. Trace {2, 1, 3, 4} using the early-exit version. After which pass does it stop?
Show solution B2
B2. The array after pass 1 is [1, 2, 3, 4], with a swap (2 and 1). Pass 2 makes no swap, so swapped is false and the method stops after pass 2.
B3. What should the code print for bubbleSort on an empty array followed by Arrays.toString? Explain why no exception occurs.
Show solution B3
B3. It prints []. For an empty array a.length - 1 is -1, so the outer loop condition pass < -1 is false at once and nothing runs.
Level C: Challenge
C1. Add counters for comparisons and swaps to the version without the early exit, and report them for {5, 1, 4, 2, 8}, for the already sorted {1, 2, 3, 4, 5}, and for the reversed {5, 4, 3, 2, 1}.
Show solution C1
C1. Results from running the code on JDK 21:
| Input | Comparisons | Swaps |
|---|---|---|
{5, 1, 4, 2, 8} | 10 | 4 |
{1, 2, 3, 4, 5} | 10 | 0 |
{5, 4, 3, 2, 1} | 10 | 10 |
Without the early exit every case makes 10 comparisons, so the number of comparisons does not depend on the data, while the number of swaps does. With the early exit the sorted array would need only 4 comparisons (one pass, as C2 explains).
C2. Explain why the early-exit version needs only n - 1 comparisons for an already sorted array of n elements.
Show solution C2
C2. The first pass compares all n - 1 neighbour pairs and finds nothing out of order, so swapped stays false and the method returns right away.
Mini Challenge
Take the array {9, 4, 7, 1, 8, 3}. Without running code, write the array after each pass of bubble sort and count the comparisons and swaps. Then write the program, add counters, and check that your hand trace matches the output. Finally change the comparison to sort descending and predict the first pass before running it.
Check your work: your hand trace and the program agree on every pass, and isSorted confirms the result.
Summary & Next Lesson
Key takeaways
- Bubble sort repeatedly compares neighbours and swaps them if they are out of order.
- After one pass the largest remaining value sits at the end, so the inner loop can shrink by one each pass.
- Swapping needs a temporary variable.
- A pass with no swaps means the array is sorted, so a
swappedflag allows an early exit. - It makes about
n × n / 2comparisons: double the data, about four times the work. Easy to understand, slow for large data.
Next lesson
The next lesson, "Selection sort", sorts a different way: instead of swapping neighbours many times, it finds the smallest remaining value and places it directly in its final position.
Self-check
- What does one pass of bubble sort guarantee?
- Why does the inner loop stop at
a.length - 1 - pass? - How do you swap two array elements?
- What does a pass with no swaps tell you?
- If the array doubles in size, about how does the work change?
Show answers
- The largest value of the unsorted part is now at the end of it.
- The last
passpositions are already in their final places, anda[i + 1]must not go past the end. - Save one value in a temporary variable, copy the other over it, then copy the temporary into the other position.
- The array is sorted, so the sort can stop.
- It roughly quadruples.
References
- Oracle, Arrays (Java SE 21 API).
Arrays.sort(int[])sorts into ascending order, and the implementation note names a Dual-Pivot Quicksort withO(n log(n))performance, while stating that implementation notes are not part of the specification. - The pass-by-pass traces, counts, and outputs in this lesson come from compiling and running the code on JDK 21. The comparison count
n(n - 1) / 2follows from addingn - 1down to 1.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.