10.2.4 Ordering Values with Bubble Sort
Bubble sort orders the values in a one-dimensional array by comparing neighbouring elements. When a pair is in the wrong order, the algorithm swaps the two values. Repeated passes gradually move values into their final positions.
By the end of this section, you should be able to:
- Explain how adjacent comparisons and swaps produce an ordered array.
- Trace the state of an array after individual comparisons and complete passes.
- Write pseudocode that sorts a 1D array into ascending order.
- Use a temporary variable to swap two array elements safely.
- Explain why the unsorted range becomes shorter after each pass.
- Use a Boolean flag to stop early when a pass makes no swaps.
- Adapt the comparison condition to produce descending order.
The Main Idea
A delivery company stores six route durations, in minutes, using indexes 3 to 8. The values need to be arranged from shortest to longest.
| Index | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|
| RouteDuration | 42 | 17 | 29 | 11 | 35 | 24 |
For ascending order, compare each adjacent pair. Swap the pair whenever the value on the left is greater than the value on the right.
Tracing One Complete Pass
During the first pass, the comparison moves from the lower bound towards the upper bound. The table shows the array after each decision.
| Comparison | Pair checked | Decision | Array after the decision |
|---|---|---|---|
| 1 | 42 and 17 | Swap | 17, 42, 29, 11, 35, 24 |
| 2 | 42 and 29 | Swap | 17, 29, 42, 11, 35, 24 |
| 3 | 42 and 11 | Swap | 17, 29, 11, 42, 35, 24 |
| 4 | 42 and 35 | Swap | 17, 29, 11, 35, 42, 24 |
| 5 | 42 and 24 | Swap | 17, 29, 11, 35, 24, 42 |
42, has reached
the upper-bound position. The other values are not necessarily sorted yet.
Swapping Two Array Elements
Assigning the right value directly to the left element would overwrite data that is still needed. A temporary variable protects the first value while the swap takes place.
Temporary β RouteDuration[Index]
RouteDuration[Index] β RouteDuration[Index + 1]
RouteDuration[Index + 1] β Temporary
| Stage | Left element | Right element | Temporary |
|---|---|---|---|
| Before the swap | 42 | 17 | Not set |
| Save the left value | 42 | 17 | 42 |
| Copy right to left | 17 | 17 | 42 |
| Restore the saved value | 17 | 42 | 42 |
RouteDuration[Index] β RouteDuration[Index + 1]
RouteDuration[Index + 1] β RouteDuration[Index]
The original left value has already been lost before the second statement runs.
Repeated Passes and the Shrinking Range
Each completed pass places the largest remaining unsorted value at the end of the unsorted region. The next pass can therefore stop one position earlier.
| Stage | Array state | Newly fixed value |
|---|---|---|
| Initial | 42, 17, 29, 11, 35, 24 | None |
| After pass 1 | 17, 29, 11, 35, 24, 42 | 42 |
| After pass 2 | 17, 11, 29, 24, 35, 42 | 35 |
| After pass 3 | 11, 17, 24, 29, 35, 42 | 29 |
| Pass 4 | 11, 17, 24, 29, 35, 42 | No swaps: the array is already sorted |
Bubble Sort Pseudocode
This version works with a non-zero lower bound and uses LastUnsorted to mark the final
position that still needs comparing.
DECLARE RouteDuration : ARRAY[3:8] OF INTEGER
DECLARE LowerBound : INTEGER
DECLARE UpperBound : INTEGER
DECLARE LastUnsorted : INTEGER
DECLARE Index : INTEGER
DECLARE Temporary : INTEGER
DECLARE SwapMade : BOOLEAN
LowerBound β 3
UpperBound β 8
LastUnsorted β UpperBound
REPEAT
SwapMade β FALSE
FOR Index β LowerBound TO LastUnsorted - 1
IF RouteDuration[Index] > RouteDuration[Index + 1]
THEN
Temporary β RouteDuration[Index]
RouteDuration[Index] β RouteDuration[Index + 1]
RouteDuration[Index + 1] β Temporary
SwapMade β TRUE
ENDIF
NEXT Index
LastUnsorted β LastUnsorted - 1
UNTIL SwapMade = FALSE OR LastUnsorted = LowerBound
Purpose of the main identifiers
| Identifier | Purpose |
|---|---|
Index |
Selects the left element of the adjacent pair. |
Index + 1 |
Selects the right-hand neighbour. |
Temporary |
Protects one value during a swap. |
LastUnsorted |
Shortens the comparison range after each pass. |
SwapMade |
Records whether the current pass changed the array. |
LastUnsorted - 1 because it also accesses
Index + 1. Allowing Index to equal LastUnsorted would read beyond
the current comparison range.
Stopping Early When No Swaps Occur
At the start of each pass, SwapMade is reset to FALSE. Any swap changes it to
TRUE. If the complete pass finishes and it is still FALSE, every adjacent pair
was already in the required order.
| Array before the pass | Swaps in the pass | Conclusion |
|---|---|---|
| 8, 13, 17, 19, 26, 31 | 0 | Already sorted; stop immediately. |
| 8, 13, 19, 17, 26, 31 | 1 | A change occurred; another pass is needed to confirm the order. |
SwapMade only once before all passes. It must be reset at the beginning
of every new pass so that the algorithm measures changes in that pass alone.
Adapting the Sort for Descending Order
The loop structure and swap statements stay the same. Only the comparison condition changes.
| Required order | Swap condition | Effect |
|---|---|---|
| Ascending | Array[Index] > Array[Index + 1] |
Larger values move towards the upper bound. |
| Descending | Array[Index] < Array[Index + 1] |
Smaller values move towards the upper bound. |
Interactive: Bubble Sort Animator
Select a data set and sorting direction. Step through one adjacent comparison at a time, complete a whole pass, or let the animation run automatically. The widget also shows the shrinking unsorted range.
Common Mistakes and Misconceptions
- Comparing non-adjacent elements instead of neighbours.
- Assuming one pass completely sorts the array.
- Overwriting one value because no temporary variable is used.
- Using an inner-loop upper limit that makes
Index + 1invalid. - Continuing to compare the values already fixed at the upper end.
- Forgetting to reset the swap flag before each pass.
- Stopping after a pass that did make a swap.
- Changing the swap statements instead of the comparison when descending order is required.
- Ignoring the declared lower bound and assuming the first index is 0.
Practice
Task 1: Trace a complete first pass
QueueTime : ARRAY[5:10] OF INTEGER contains:
31, 14, 26, 9, 22, 18
- Show the array after each adjacent comparison in the first ascending pass.
- State which value reaches its final position.
- State the last index that needs checking in pass 2.
Task 2: Complete the swap
Complete the missing pseudocode:
IF Score[Index] > Score[Index + 1]
THEN
Temporary β ____________________
Score[Index] β ____________________
Score[Index + 1] β ____________________
SwapMade β TRUE
ENDIF
Task 3: Write and adapt an algorithm
- Write bubble-sort pseudocode for
ARRAY[2:9] OF INTEGER. - Use a shrinking unsorted boundary.
- Add early termination using a Boolean flag.
- State the one comparison change needed for descending order.
Review
| Question | Strong answer should include |
|---|---|
| What does bubble sort compare? | Adjacent elements in the current unsorted region. |
| When is a pair swapped for ascending order? | When the left value is greater than the right value. |
| Why is a temporary variable used? | To preserve one value while the two array elements exchange positions. |
| What is guaranteed after one pass? | The largest value in the unsorted region reaches its final upper-end position. |
| Why can the range shrink? | Values already fixed at the end do not need comparing again. |
| When can the algorithm stop early? | When a complete pass finishes without any swaps. |