Bubble Sort: Algorithm, Dry Run, Code & Complexity Explained
What is Bubble Sort?
Bubble Sort repeatedly compares adjacent elements and swaps them if they are in the wrong order. With each pass, the largest unsorted element bubbles up to its correct position at the end of the array.
Algorithm Steps
- Start from index 0, compare arr[j] and arr[j+1]
- If arr[j] > arr[j+1], swap them
- After one full pass, the largest element reaches its final position
- Repeat for n-1 passes, reducing inner range by 1 each time
Code Implementation
š Python
def bubble_sort(arr):
n = len(arr)
for i in range(n - 1): # n-1 passes
for j in range(n - i - 1): # shrink inner range each pass
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
# Optimized version
def bubble_sort_optimized(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
ā Java
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) { // n-1 passes
for (int j = 0; j < n - i - 1; j++) { // shrink each pass
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// Optimized version
public static void bubbleSortOptimized(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 temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) break; // already sorted
}
}
}
āļø C++
#include <iostream>
#include <vector>
using namespace std;
void bubbleSort(vector& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i++) { // n-1 passes
for (int j = 0; j < n - i - 1; j++) { // shrink each pass
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
}
}
}
}
// Optimized version
void bubbleSortOptimized(vector& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
swapped = true;
}
}
if (!swapped) break; // already sorted
}
}
š” JavaScript
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) { // n-1 passes
for (let j = 0; j < n - i - 1; j++) { // shrink each pass
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // swap
}
}
}
return arr;
}
// Optimized version
function bubbleSortOptimized(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
let swapped = false;
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
if (!swapped) break; // already sorted
}
return arr;
}
// Test
console.log(bubbleSort([20, 15, 10, 35, 30, 2]));
// Output: [2, 10, 15, 20, 30, 35]
Dry Run ā arr = [20, 15, 10, 35, 30, 2]
Comparing
Swapped
Sorted (final)
Pass 0 ā 5 comparisons
Initial array:
20
idx 0
15
idx 1
10
idx 2
35
idx 3
30
idx 4
2
idx 5
| j | Compare | Action | Array after |
|---|---|---|---|
| 0 | 20 vs 15 | ā Swap | [15, 20, 10, 35, 30, 2] |
| 1 | 20 vs 10 | ā Swap | [15, 10, 20, 35, 30, 2] |
| 2 | 20 vs 35 | ā No swap | [15, 10, 20, 35, 30, 2] |
| 3 | 35 vs 30 | ā Swap | [15, 10, 20, 30, 35, 2] |
| 4 | 35 vs 2 | ā Swap | [15, 10, 20, 30, 2, 35] |
After pass 0:
15
idx 0
10
idx 1
20
idx 2
30
idx 3
2
idx 4
35
idx 5 ā
ā 35 is in its final position!
Pass 1 ā 4 comparisons
| j | Compare | Action | Array after |
|---|---|---|---|
| 0 | 15 vs 10 | ā Swap | [10, 15, 20, 30, 2, 35] |
| 1 | 15 vs 20 | ā No swap | [10, 15, 20, 30, 2, 35] |
| 2 | 20 vs 30 | ā No swap | [10, 15, 20, 30, 2, 35] |
| 3 | 30 vs 2 | ā Swap | [10, 15, 20, 2, 30, 35] |
10
idx 0
15
idx 1
20
idx 2
2
idx 3
30
idx 4 ā
35
idx 5 ā
Pass 2 ā 3 comparisons
| j | Compare | Action | Array after |
|---|---|---|---|
| 0 | 10 vs 15 | ā No swap | [10, 15, 20, 2, 30, 35] |
| 1 | 15 vs 20 | ā No swap | [10, 15, 20, 2, 30, 35] |
| 2 | 20 vs 2 | ā Swap | [10, 15, 2, 20, 30, 35] |
10
idx 0
15
idx 1
2
idx 2
20
idx 3 ā
30
idx 4 ā
35
idx 5 ā
Pass 3 ā 2 comparisons
| j | Compare | Action | Array after |
|---|---|---|---|
| 0 | 10 vs 15 | ā No swap | [10, 15, 2, 20, 30, 35] |
| 1 | 15 vs 2 | ā Swap | [10, 2, 15, 20, 30, 35] |
10
idx 0
2
idx 1
15
idx 2 ā
20
idx 3 ā
30
idx 4 ā
35
idx 5 ā
Pass 4 ā 1 comparison
| j | Compare | Action | Array after |
|---|---|---|---|
| 0 | 10 vs 2 | ā Swap | [2, 10, 15, 20, 30, 35] |
2
idx 0 ā
10
idx 1 ā
15
idx 2 ā
20
idx 3 ā
30
idx 4 ā
35
idx 5 ā
š Sorted: [2, 10, 15, 20, 30, 35]
Comparisons Summary
| Pass (i) | Inner range | Comparisons |
|---|---|---|
| 0 | n-1 = 5 | 5 |
| 1 | n-2 = 4 | 4 |
| 2 | n-3 = 3 | 3 |
| 3 | n-4 = 2 | 2 |
| 4 | n-5 = 1 | 1 |
| Total | 15 = n(n-1)/2 |
Time & Space Complexity
| Case | Time | Reason |
|---|---|---|
| Best | O(n) | Already sorted ā 0 swaps (optimized) |
| Average | O(n²) | Random order |
| Worst | O(n²) | Reverse sorted ā maximum swaps |
| Space | O(1) | In-place ā only a temp swap variable |
Is Bubble Sort Stable?
ā Yes. We only swap when arr[j] > arr[j+1] (strict greater than). Equal elements are never swapped, preserving their relative order.