Skip to content

Free Practice Lab · no sign-up needed

Bubble sort visualizer

Sorting is easier to follow when the values move one comparison at a time. This visualizer links each comparison to a small Python implementation. Try duplicate and negative numbers, step backwards, or pause the animation to predict the next state.

Beginner → intermediateAbout 9 minutes to read · practise at your own pace
Read the full lesson ↓

The interactive controls are loading. The explanation and worked examples below are available to read now.

Understand. Try. Explain.

What you will learn

Learn what a comparison changes, why a pass is useful, and how to explain the cost of the algorithm. Read the examples alongside the animation; predict a step before revealing it.

  • Trace comparisons and swaps without losing track of a value.
  • Explain why the right-hand sorted region grows after each pass.
  • Distinguish comparisons, swaps and the extra memory used by the visualizer.

How to use this lesson: read one section, predict what the example will do, then compare your reasoning with the explanation. Try the self-check questions before opening their answers.

1. Understand the mental model

Imagine a row of numbered cards that should read from smallest to largest. Look only at two neighbouring cards. If the left card is larger, exchange the pair. Otherwise, keep both where they are. Then move one position to the right. This local rule is the whole comparison step; the repeated passes turn it into a sorting algorithm.

A comparison asks a question; a swap changes the list. These are different operations. Comparing 1 and 4 does not move anything. Comparing 5 and 2 produces 2 and 5. In the animation, pause on the highlighted pair and say which operation should happen before pressing Next.

During a left-to-right pass, the largest value seen so far keeps moving to the right when necessary. By the end of that pass, the largest value in the active region has reached its final position. The region to its left may still be unsorted. This is why one pass is usually not enough.

A useful invariant: after each completed pass, the right-hand settled region is sorted and contains the largest values. Later passes do not need to visit it.

2. Connect the animation to Python

Here is an in-place implementation: it changes the supplied list and returns that same list for convenience. The variable end is the last index in the active region. range(end) stops before end, so i + 1 stays within that region.

The swapped flag begins as False for every new pass. A swap changes it to True. If an entire pass makes no swaps, every adjacent pair in the active region is already in order, and the algorithm can stop. Resetting this flag inside the outer loop is essential.

Python 3 example
def bubble_sort(values): for end in range(len(values) - 1, 0, -1): swapped = False for i in range(end): if values[i] > values[i + 1]: values[i], values[i + 1] = values[i + 1], values[i] swapped = True if not swapped: break return values numbers = [5, 1, 4, 2] print(bubble_sort(numbers))
Expected output
[1, 2, 4, 5]

The animation separates comparison and swap into teaching frames. Counting frames is not the same as counting comparisons or measuring runtime.

3. Explain the cost and the trade-off

For four values, a full set of passes makes at most 3 + 2 + 1 = 6 comparisons. For n values, the worst-case comparison count is n(n − 1) / 2. Doubling n therefore makes the leading amount of work roughly four times as large. That growth is called quadratic, or O(n²).

Reverse-sorted distinct values require a swap at every comparison. Already sorted input needs only one pass with this early-exit implementation: n − 1 comparisons and no swaps, giving O(n) best-case time. A first pass that makes swaps cannot stop immediately, even if it happens to leave the whole list sorted; the next pass checks that.

The sorting operation itself needs O(1) auxiliary space: a fixed number of variables, with the list modified in place. Our teaching interface also stores animation snapshots so you can step backwards. Those snapshots consume additional memory and are not part of the usual space analysis of bubble sort.

Bubble sort is useful for learning invariants and tracing loops. For ordinary Python application code, use sorted(values) when you want a new sorted list, or values.sort() when you want to modify the existing list. Choose an algorithm by requirements and data size rather than by how memorable its animation is.

Follow the reasoning

A worked example

Trace every comparison in the first pass over [5, 1, 4, 2]. Indices begin at zero. Notice that the largest value moves repeatedly while the smaller values still need later comparisons.

A worked example · step-by-step trace
ComparisonDecisionList afterwards
Indices 0 and 1: 5 > 1Swap[1, 5, 4, 2]
Indices 1 and 2: 5 > 4Swap[1, 4, 5, 2]
Indices 2 and 3: 5 > 2Swap[1, 4, 2, 5]

Why this matters: The first pass has put 5 in its final position, but the middle values still need work. The second pass keeps 1 and 4, then swaps 4 and 2, leaving [1, 2, 4, 5]. The third pass compares 1 and 2, makes no swap and stops. Across the run there are six comparisons and four swaps.

Example 2: negative numbers and equal values

Try [3, -1, 3, 0] in the tool. A negative value is still compared numerically; it belongs before zero and the positive values.

Example 2: negative numbers and equal values · step-by-step trace
StageValuesWhat to notice
Start[3, -1, 3, 0]Two separate items have value 3.
After pass 1[-1, 3, 0, 3]Equal neighbours are kept in place.
After pass 2[-1, 0, 3, 3]Zero moves before the remaining 3.
After pass 3[-1, 0, 3, 3]No swap: stop.

Why this matters: To reason about stability, label the equal values 3A and 3B on paper. Because the condition uses > rather than >=, the algorithm never swaps equal items with each other. Their original order is preserved. Changing to >= removes that stability guarantee and performs unnecessary swaps.

Example 3: test more than the happy path

The Python function can handle empty and single-item lists even though the visualizer deliberately accepts only 3–8 values. A small display limit is different from an algorithm limitation.

Python 3 example
cases = [[], [7], [2, 2, 2], [-2, 0, 4], [4, 3, 2, 1]] for case in cases: original = case.copy() result = bubble_sort(case) assert result == sorted(original) assert result is case print(result)
Expected output
[] [7] [2, 2, 2] [-2, 0, 4] [1, 2, 3, 4]

Why this matters: These cases check no work, minimal work, equality, already ordered input and reversed input. Comparing with sorted(original) also checks that values and duplicates were preserved; merely checking that the result is ascending could miss a lost value.

Common mistakes and how to avoid them

Stopping after a swap-free comparison

One ordered pair says nothing about the rest of the list. Stop only after a complete active pass has made no swaps.

Comparing past the last valid index

The final pair is values[end - 1] and values[end]. Letting i reach end would make i + 1 leave the active region, and on the first pass it would leave the list.

Treating a settled value as the next minimum

In this left-to-right version, each pass settles the largest remaining value at the right. A different traversal direction would need a different explanation.

Claiming animation speed proves performance

The interface adds deliberate delays and stores frames. Explain complexity from operations in the algorithm, not the time spent watching the animation.

Explain it in your own words

10 self-check questions

Pause before revealing each answer. These questions are unscored, so you can revisit them as often as you need.

01What happens when the highlighted pair is [2, 7]?

No swap. The left value is already less than the right value. The algorithm still made one comparison.

02After the first pass over [4, 1, 3, 2], which value is settled?

4 is at the right-hand end. The intermediate result is [1, 3, 2, 4], so another pass is needed.

03Why can the next pass ignore the last position?

It contains the largest remaining value, which is in its final position. The same reasoning grows the settled region after each pass.

04Why reset swapped to False on each pass?

Each pass needs its own record of whether anything moved. Leaving it True from an earlier pass prevents the early-exit check from recognising a later swap-free pass.

05How many comparisons does [1, 2, 3, 4] need here?

Three. The first pass makes no swaps, so the algorithm stops before starting another pass.

06How many comparisons does [4, 3, 2, 1] need?

Six: 3 + 2 + 1. Every comparison also requires a swap for this reversed input with distinct values.

07Does an equal pair need to be swapped?

No. Using strict > keeps equal items in their original relative order and avoids needless swaps.

08Does in place mean the visualizer uses no extra memory?

No. The sorting implementation uses constant auxiliary space, but the interface stores frames and other state for teaching controls.

09What is the difference between sorted(values) and values.sort()?

sorted(values) creates a new sorted list. values.sort() changes the existing list and returns None.

10Is an ascending result enough to prove the algorithm is correct?

No. Also check that the output contains exactly the original values with the same multiplicities. A broader correctness argument must cover all valid inputs, beyond the examples tested.

Try it yourself

Use these exercises after the examples. Make a prediction or write your own answer before checking the suggested approach.

Practice 1

Predict before you play

Use [4, 2, 3, 1]. Write down the list after each comparison in the first pass, then check your prediction with Next.

Show a hint

The value 4 keeps moving right because it is larger than every neighbour it meets.

Check the explanation

The states are [2, 4, 3, 1], [2, 3, 4, 1] and [2, 3, 1, 4]. Only the final 4 is guaranteed settled after that pass.

Practice 2

Find a case that needs a checking pass

Try [2, 1, 3]. Why does the implementation make a second pass after the first pass has already sorted the list?

Show a hint

Ask what the swapped flag says at the end of pass one.

Check the explanation

The first pass swaps 2 and 1, then keeps 2 and 3. Because swapped is True, it cannot early-exit. The second pass compares 1 and 2, makes no swap and stops: three comparisons in total.

Practice 3

Explain it without the animation

Describe the algorithm to a friend in four sentences: local rule, pass guarantee, stopping rule and cost. Then check a duplicate-value example.

Show a hint

Use the words adjacent, largest remaining, no swaps and quadratic.

Check the explanation

Compare adjacent values and swap when the left value is larger. Each pass moves the largest remaining value to the end of the active region. Repeat over the smaller region, stopping early after a pass with no swaps. Worst-case time is O(n²), and the in-place sorting operation uses O(1) auxiliary space.

Before you begin

Clear answers. A clear next step.

Can I try it without signing up?

Yes. The Practice Lab visualizer, debugging exercises and interview story builder are open to everyone. An account is needed to save course progress, play scored games and use a private job workspace.

What is free, and what uses AI?

Guides, Practice Lab exercises and question-bank practice do not require AI generation. Personalised job analysis and Coach or Mock answer feedback use AI and have availability and plan limits.

Does completing a practice plan make me interview-ready?

A plan helps you practise consistently. It is not a certification, skills assessment or guarantee of an interview or offer. Use it to identify useful next steps and get feedback on your explanations.

Where are my Practice Lab answers stored?

The story builder keeps text only in the current tab until you copy or download it. Starter-plan checkmarks are stored on this browser when storage is available. They are separate from signed-in course progress.