The pass invariant
After pass i, the i largest values occupy their final positions at the right. Inside a pass, the largest value seen so far moves one neighbor to the right. That is why the inner loop stops before the sorted tail.
Typorithm · easy
Step 1 of 35 · intro card
Sorting Algorithms
Bubble Sort repeatedly compares neighbors and swaps them when they are out of order.
Start at the left side of the array and compare two neighboring values.
If the left value is larger than the right value, swap them. If not, leave them in place and move one position to the right.
After one full pass, the largest unsorted value has moved to the end. The next pass can ignore that sorted tail.
Bubble Sort is slow for large arrays, but it is useful for learning nested loops, comparisons, swaps, and time complexity because every move is visible.
Compare neighboring elements.
Swap the pair when the left value is greater.
Ignore the sorted tail after each pass.
Average and worst time are O(n^2).
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}Go beyond the happy path
After pass i, the i largest values occupy their final positions at the right. Inside a pass, the largest value seen so far moves one neighbor to the right. That is why the inner loop stops before the sorted tail.
The strict > comparison leaves equal values in their original relative order. Changing it to >= loses that stability. Swapping writes into the input array; callers that need the original should copy it before calling bubbleSort.
The inner loop makes n(n−1)/2 comparisons even on sorted input: this basic version takes O(n²) time in all cases. It uses O(1) auxiliary space. An early-exit flag can reduce the best case to O(n), but that is a different implementation.
Empty and single-value arrays need no comparison. Reversed arrays trigger every possible swap. Duplicates must remain stable; negative values still use the same numeric comparison. The trace above lets you compare mixed, reversed and duplicate inputs.
bubbleSort([]) // []
bubbleSort([7]) // [7]
bubbleSort([3, 1, 3, 2]) // [1, 2, 3, 3]
bubbleSort([-1, 4, -3]) // [-3, -1, 4]Reflection: which boundary would read beyond the array, and why does one successful swap not prove that the whole array is sorted?
Connect each part of the code to the concept before you type.
Define a reusable function that receives the array to sort.
function bubbleSort(arr)The outer loop controls how many full passes we make.
for (let i = 0; i < arr.length; i++)The inner loop walks across neighboring pairs.
for (let j = 0; j < arr.length - i - 1; j++)After each pass, the largest remaining value is already at the end.
arr.length - i - 1Compare two neighbors and only swap if the left value is larger.
arr[j] > arr[j + 1]This destructuring assignment exchanges the two neighboring values.
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]Return the same array after the in-place sorting passes finish.
return arrRead the concept map and follow the code breakdown.
Type the implementation, repair mistakes and work through every recall exercise.
Use the final check without hints; revisit weak concepts in short practice sessions.
Algorithm lab · interactive
Input[5,1,4,2,8]
One temporary value and a fixed number of indices. In-place does not mean zero extra memory. The input array is not counted as extra space.
One reusable value slot. Empty until the next operation needs it.
Around this step
Small, reproducible examples · ← → step · Space play/pause · Home/End first/last state