Card 03/ 11

CodeDifficulty: Intermediate4 min

Bubble Sort in Python, Java and TypeScript

Bubble sort with the early exit, printing its comparisons and swaps.

Bubble sort takes about a dozen lines in each language, with a swapped flag that ends the sort after a pass that changed nothing. The listings count comparisons and swaps so the figures can be checked against a hand trace, and run on two inputs: the seven numbers 6 2 9 4 1 7 3, and 1 to 7 already sorted. Each one also calls its language's built-in sort on 10 9 1.

Bubble sort with the early exit, in each language

bubble_sort_code.pypy
def bubble_sort(items: list[int]) -> tuple[int, int]:
    comparisons = swaps = 0
    for end in range(len(items) - 1, 0, -1):
        swapped = False
        for j in range(end):
            comparisons += 1
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                swaps += 1
                swapped = True
        if not swapped:
            break
    return comparisons, swaps


for numbers in ([6, 2, 9, 4, 1, 7, 3], [1, 2, 3, 4, 5, 6, 7]):
    before = " ".join(map(str, numbers))
    comparisons, swaps = bubble_sort(numbers)
    after = " ".join(map(str, numbers))
    print(f"{before} -> {after}: {comparisons} comparisons, {swaps} swaps")
print("built-in sorted:", " ".join(map(str, sorted([10, 9, 1]))))
OutputRan with python:3.14.8-slim-trixie (Python 3.14.8)
6 2 9 4 1 7 3 -> 1 2 3 4 6 7 9: 20 comparisons, 12 swaps
1 2 3 4 5 6 7 -> 1 2 3 4 5 6 7: 6 comparisons, 0 swaps
built-in sorted: 1 9 10
BubbleSortCode.javajava
import java.util.Arrays;
import java.util.stream.Collectors;

public class BubbleSortCode {
    record Counts(int comparisons, int swaps) {}

    static Counts bubbleSort(int[] items) {
        int comparisons = 0;
        int swaps = 0;
        for (int end = items.length - 1; end > 0; end--) {
            boolean swapped = false;
            for (int j = 0; j < end; j++) {
                comparisons++;
                if (items[j] > items[j + 1]) {
                    int held = items[j];
                    items[j] = items[j + 1];
                    items[j + 1] = held;
                    swaps++;
                    swapped = true;
                }
            }
            if (!swapped) {
                break;
            }
        }
        return new Counts(comparisons, swaps);
    }

    static String joined(int[] items) {
        return Arrays.stream(items).mapToObj(String::valueOf).collect(Collectors.joining(" "));
    }

    public static void main(String[] args) {
        int[][] inputs = {{6, 2, 9, 4, 1, 7, 3}, {1, 2, 3, 4, 5, 6, 7}};
        for (int[] numbers : inputs) {
            String before = joined(numbers);
            Counts counts = bubbleSort(numbers);
            System.out.println(before + " -> " + joined(numbers) + ": "
                    + counts.comparisons() + " comparisons, " + counts.swaps() + " swaps");
        }
        int[] small = {10, 9, 1};
        Arrays.sort(small);
        System.out.println("built-in Arrays.sort: " + joined(small));
    }
}
OutputRan with eclipse-temurin:25.0.4.1_1-jdk-noble (Java 25.0.4.1)
6 2 9 4 1 7 3 -> 1 2 3 4 6 7 9: 20 comparisons, 12 swaps
1 2 3 4 5 6 7 -> 1 2 3 4 5 6 7: 6 comparisons, 0 swaps
built-in Arrays.sort: 1 9 10
bubble_sort_code.tsts
interface Counts {
  comparisons: number;
  swaps: number;
}

function bubbleSort(items: number[]): Counts {
  let comparisons = 0;
  let swaps = 0;
  for (let end = items.length - 1; end > 0; end--) {
    let swapped = false;
    for (let j = 0; j < end; j++) {
      comparisons++;
      if (items[j] > items[j + 1]) {
        [items[j], items[j + 1]] = [items[j + 1], items[j]];
        swaps++;
        swapped = true;
      }
    }
    if (!swapped) {
      break;
    }
  }
  return { comparisons, swaps };
}

const inputs: number[][] = [[6, 2, 9, 4, 1, 7, 3], [1, 2, 3, 4, 5, 6, 7]];
for (const numbers of inputs) {
  const before = numbers.join(" ");
  const { comparisons, swaps } = bubbleSort(numbers);
  console.log(`${before} -> ${numbers.join(" ")}: ${comparisons} comparisons, ${swaps} swaps`);
}
console.log(`built-in sort(): ${[10, 9, 1].sort().join(" ")}`);
console.log(`built-in sort with a comparator: ${[10, 9, 1].sort((a, b) => a - b).join(" ")}`);
OutputRan with node:24.22.0-trixie-slim (Node 24.22.0), TypeScript 5.9.3
6 2 9 4 1 7 3 -> 1 2 3 4 6 7 9: 20 comparisons, 12 swaps
1 2 3 4 5 6 7 -> 1 2 3 4 5 6 7: 6 comparisons, 0 swaps
built-in sort(): 1 10 9
built-in sort with a comparator: 1 9 10

All three printed 20 comparisons and 12 swaps on the seven numbers, the figures a hand trace gives, and 6 comparisons with no swaps on sorted input: one pass of n − 1 comparisons, then the early exit. The highlighted lines are that exit. The flag is reset to false at the start of every pass, set to true by any swap, and tested after the inner loop; a pass that leaves it false ends the sort. The outer loop counts end down from the last index, so each pass stops one place before the item the previous pass settled. Python and TypeScript swap two items in one statement, and Java holds one item in a temporary variable while it moves the other.

No standard library ships a bubble sort, so in real code you call the built-in: Python's sorted or list.sort, Java's Arrays.sort, and TypeScript's sort on an array. The last of these has a trap the run caught. Called with no argument, [10, 9, 1].sort() printed 1 10 9, because JavaScript converts each item to a string and compares the strings as text, and "10" comes before "9". Pass a comparator, (a, b) => a - b, whenever you sort numbers.