Elementary O(n²) Sorting Algorithms
Bubble Sort with early exit flag, Selection Sort minimal write guarantees, and Insertion Sort online adaptive behavior.
Reinforce your mental model: run, pause, and inspect live pointers with our interactive visualizer:
Topics Covered:
50. Bubble Sort (Adjacent Comparisons & Early Exit Optimization) • 51. Selection Sort (Prefix Selection & Instability) • 52. Insertion Sort (Adaptive Shifting & Online Sorting)
Elementary sorting algorithms—Bubble Sort, Selection Sort, and Insertion Sort—form the pedagogical bedrock of computational order. While all three exhibit quadratic worst-case time bounds, their internal mechanics represent fundamentally distinct algorithmic paradigms: local inversion elimination, prefix selection invariants, and adaptive incremental insertion. Analyzing these algorithms uncovers foundational concepts that govern all sorting theory, including inversion counts, memory write minimization, stability preservation, and cache locality. Furthermore, Insertion Sort's exceptional efficiency on nearly sorted data makes it the indispensable base-case engine powering modern hybrid production sorts such as Timsort and Introsort.
Learning Objectives
#- Formulate the mechanics, loop invariants, and early-exit termination condition of Bubble Sort.
- Prove why adjacent transposition algorithms eliminate exactly one inversion per swap.
- Analyze Selection Sort's minimal write guarantee and prove its inherent instability through formal counterexamples.
- Implement Insertion Sort and derive its adaptive runtime as a function of the input inversion count .
- Compare the three elementary sorting paradigms across comparison bounds, swap operations, stability, and adaptive execution.
- Evaluate why Insertion Sort remains the standard base-case sort in production runtimes for small partitions ().
Topic 50: Bubble Sort (Adjacent Transpositions)
#1. Mathematical Foundations & Inversion Elimination
#Given an array of elements, the sorting problem requires finding a permutation such that:
The degree of disorder in an array is formally quantified by its inversion count :
- A strictly sorted array has .
- A strictly reverse-sorted array of distinct elements has the maximum possible inversions:
Theorem (Adjacent Inversion Transposition):
Swapping two adjacent elements and where reduces the total inversion count by exactly one, without altering the inversion status of any other pair in the array.
Bubble Sort is the direct physical realization of this theorem. It repeatedly sweeps across the array, comparing adjacent pairs , and transposes them whenever they violate non-decreasing order. In each pass (), the largest unsorted element "bubbles up" to its final resting position at the rightmost available index .
2. Trace of Pass 0: Bubbling the Maximum Element
#Consider the unsorted array of size . The table below tracks the adjacent comparisons and transpositions during Pass 0 ():
| Inner Step | Inspected Pair | Out of Order? () | Transposition Action | Inversion Eliminated | Resulting Array State | Status |
|---|---|---|---|---|---|---|
0 | True () | Swap | Adjacent swap performed | |||
1 | True () | Swap | Adjacent swap performed | |||
2 | True () | Swap | Adjacent swap performed | |||
3 | False () | None (Preserve order) | None | Element 8 locked at index 4 |
At the conclusion of Pass 0, the global maximum value 8 is guaranteed to be locked into index . Subsequent passes can safely ignore this suffix.
3. Early-Exit Optimization
#In its naive formulation, Bubble Sort executes comparisons regardless of input order. However, if an entire inner pass completes without performing a single swap, then held true for every pair. By mathematical induction, the entire array is sorted.
By introducing a boolean flag swapped, the algorithm terminates early in time when provided an already-sorted or nearly-sorted array:
| Pass | Unsorted Boundary | Inner Comparisons | Swaps | Array State at End of Pass | swapped Flag | Control Flow Outcome |
|---|---|---|---|---|---|---|
0 | 3 | True | Continue to Pass 1 | |||
1 | 1 | True | Continue to Pass 2 | |||
2 | 0 | False | Early Exit Triggered! (Break) |
The algorithm completes in 3 passes rather than the naive 4 passes, avoiding unnecessary quadratic overhead.
4. Canonical Algorithm: Bubble Sort with Early Exit
#FUNCTION BubbleSort(A: Array of Element, n: Integer) -> Array of Element:
FOR i <- 0 TO n - 2 DO
swapped <- False
FOR j <- 0 TO n - 2 - i DO
IF A[j] > A[j + 1] THEN
temp <- A[j]
A[j] <- A[j + 1]
A[j + 1] <- temp
swapped <- True
END IF
END FOR
// If no swaps occurred, the array is already sorted
IF NOT swapped THEN
BREAK
END IF
END FOR
RETURN AComplexity & Invariant Analysis:
- Loop Invariant: At the start of pass , the suffix subarray contains the largest elements of in fully sorted order, and every element in the suffix is every element in the prefix .
- Best-Case Time Complexity: . When the array is already sorted, Pass 0 executes comparisons, performs swaps, observes
swapped == False, and breaks immediately. - Worst-Case Time Complexity: . When the array is reverse-sorted, the number of comparisons and swaps is:
- Average-Case Time Complexity: comparisons and swaps (an average random permutation has inversions).
- Space Complexity: auxiliary memory (strictly in-place).
- Stability: Stable. The condition uses a strict inequality; identical elements are never swapped, preserving their initial relative order.
Topic 51: Selection Sort (Prefix Selection & Instability)
#1. Architectural Concept & The Prefix Invariant
Selection Sort structures the sorting process into two distinct memory partitions:
- A sorted prefix occupying indices .
- An unsorted suffix occupying indices .
In each pass (), the algorithm scans the entire unsorted suffix to locate the minimum element, and performs a single swap placing that minimum element at index . This increments the sorted prefix boundary by one.
Unlike Bubble Sort, which executes numerous intermediate swaps to transport values, Selection Sort isolates the search phase from the mutation phase: it performs comparisons to identify the minimum, but executes at most one swap per outer loop iteration.
2. Step-by-Step Execution Trace
#Sorting of size :
| Pass | Sorted Prefix | Unsorted Suffix | Minimum Candidate Found | Swap Operation | Array Snapshot Post-Pass | Prefix Status |
|---|---|---|---|---|---|---|
0 | Value 11 at index 4 | () | Prefix sorted | |||
1 | Value 12 at index 2 | () | Prefix sorted | |||
2 | Value 22 at index 3 | () | Prefix sorted | |||
3 | Value 25 at index 3 | (Self-swap / No-op) | All elements sorted |
Total comparisons performed: . Total write operations (swaps): 3.
3. Canonical Algorithm: Selection Sort
#FUNCTION SelectionSort(A: Array of Element, n: Integer) -> Array of Element:
FOR i <- 0 TO n - 2 DO
minIdx <- i
// Scan unsorted suffix to locate minimum element
FOR j <- i + 1 TO n - 1 DO
IF A[j] < A[minIdx] THEN
minIdx <- j
END IF
END FOR
// Swap minimum element into current prefix slot
IF minIdx != i THEN
temp <- A[i]
A[i] <- A[minIdx]
A[minIdx] <- temp
END IF
END FOR
RETURN A4. Complexity & The Minimal-Write Guarantee
#Selection Sort exhibits unique performance characteristics:
- Time Complexity: Strictly in all cases (best, average, and worst). The inner loop must scan every remaining unsorted position to verify that no smaller element exists. It cannot adapt to pre-existing order.
- Space Complexity: auxiliary memory.
- Write Complexity (Swaps): At most swaps.
Hardware Significance: In systems where memory write operations are orders of magnitude more expensive than reads—such as embedded EEPROM or flash memory where writes cause physical wear and latency—Selection Sort minimizes bus write traffic compared to Bubble or Insertion Sort.
5. Proof of Instability
#Selection Sort is inherently unstable. A sorting algorithm is unstable if it can invert the relative order of duplicate elements.
Formal Counterexample:
Let where and have identical key values but distinct original positions ().
| Pass | Inspected Array | Minimum Element | Swap Executed | Resulting Array | Stability Evaluation |
|---|---|---|---|---|---|
| Initial | — | — | Relative order: precedes | ||
| Pass 0 | Value 2 at index 2 | () | Long-distance swap jumps over ! | ||
| Pass 1 | Value at index 1 | None () | Relative order inverted: precedes ❌ |
Because the swap transports the minimum element across long distances, duplicate keys are displaced across one another, destroying stability.
Topic 52: Insertion Sort (Adaptive Shifting & Online Sorting)
#1. Mechanics & Playing Card Analogy
#Insertion Sort mirrors the way a human player sorts playing cards in hand. The algorithm partitions the array into a sorted subarray and an unsorted subarray .
In each iteration ():
- The element is extracted as the
key. - The algorithm scans backward through the sorted subarray ( down to ).
- All elements strictly greater than
keyare shifted one position to the right (). - As soon as an element is encountered (or the start of the array is reached), the backward scan halts.
- The
keyis inserted into the vacated slot .
The backward scan below illustrates inserting into the sorted prefix :
| Scan Step | Inspected Element | Comparison () | Action Taken | Array Sub-State |
|---|---|---|---|---|
| Extraction | — | — | Extract | |
7 | True () | Shift 7 right to index 3 | ||
5 | True () | Shift 5 right to index 2 | ||
2 | False () | Halt backward scan! | ||
| Insertion | — | — | Insert at |
2. Full Array Trace: Sorting
#| Pass | key Value | Sorted Prefix Before Pass | Backward Comparisons & Shifts | Vacated Insertion Slot | Array State at End of Pass |
|---|---|---|---|---|---|
1 | 3 | Compare 8 () shift 8 right | Index 0 | ||
2 | 5 | Compare 8 () shift 8 right; Compare 3 () halt | Index 1 | ||
3 | 2 | Compare 8, 5, 3 (all ) shift all right | Index 0 |
3. Canonical Algorithm: Insertion Sort
#FUNCTION InsertionSort(A: Array of Element, n: Integer) -> Array of Element:
FOR i <- 1 TO n - 1 DO
key <- A[i]
j <- i - 1
// Shift elements of A[0..i-1] that are greater than key to the right
WHILE j >= 0 AND A[j] > key DO
A[j + 1] <- A[j]
j <- j - 1
END WHILE
// Place key in its correct sorted location
A[j + 1] <- key
END FOR
RETURN A4. Complexity & Adaptive Performance
#Insertion Sort's performance is strictly tied to the input array's inversion count :
Theorem (Insertion Sort Adaptive Complexity):
The number of element shifts executed by Insertion Sort equals the exact number of inversions in the input array. The total number of comparisons is at most .
- Best-Case Time Complexity: . When the array is already sorted (), the inner condition
A[j] > keyevaluates toFalseon the very first check for every . Exactly comparisons and shifts are executed. - Worst-Case Time Complexity: . When the array is reverse sorted, every element must shift past all preceding elements:
- Average-Case Time Complexity: ( shifts on average).
- Space Complexity: auxiliary memory (in-place).
- Stability: Stable. The condition
A[j] > keystrictly shifts elements greater thankey. If , the while loop halts, placingkeyafter the duplicate element and preserving relative order. - Online Sorting Property: Insertion Sort is an online algorithm. It can process elements in real time as they arrive from an input stream, maintaining a sorted prefix at every intermediate moment.
5. Why Insertion Sort Powers Modern Production Hybrids
#Despite its quadratic worst-case bound, Insertion Sort is widely deployed inside modern programming language runtimes:
- Low Constant Factor (): Insertion Sort involves no recursive call stack allocations, no dynamic heap buffers, and minimal instructions per iteration. For small arrays ( to ), .
- Superior Cache Locality: The inner loop shifts contiguous memory words backward through the L1 CPU cache. Modern superscalar processors execute these contiguous memory shifts with exceptional memory throughput.
- Timsort Integration: Python (
list.sort()) and Java (Arrays.sort()for objects) use Timsort, which partitions input data into monotonic runs and sorts short chunks using Binary Insertion Sort (where binary search determines the insertion slot before shifting). - Introsort Integration: C++
std::sortimplements Introsort, which begins with Quicksort, switches to Heapsort if recursion depth exceeds , and delegates all subarrays smaller than 16 elements to Insertion Sort.
Master Comparison Matrix: Elementary Sorting Algorithms
#| Metric | Bubble Sort | Selection Sort | Insertion Sort |
|---|---|---|---|
| Best-Case Time | (with flag) | ||
| Average-Case Time | |||
| Worst-Case Time | |||
| Auxiliary Space | |||
| Comparisons (Worst) | |||
| Comparisons (Best) | |||
| Memory Writes (Worst) | |||
| Stability | Stable | Unstable | Stable |
| Adaptive to Pre-Sorted? | Yes ( best) | No (Always ) | Yes () |
| Online Data Stream? | No | No | Yes |
| Primary Production Role | Pedagogical instruction | Hardware with expensive writes | Small partitions in Timsort/Introsort |
Module 01 Summary & Key Takeaways
#- Inversion Counting: An inversion is any pair where and . An array is sorted if and only if . Swapping adjacent inverted elements removes exactly one inversion.
- Bubble Sort Invariant: Each pass transports the largest remaining unsorted value to the end of the array. An early-exit boolean flag (
swapped) detects when in Pass 0, yielding an optimal best case. - Selection Sort Write Minimization: Selection Sort separates comparison from mutation, executing at most swaps. While strictly in time and inherently unstable due to long-distance swaps, it minimizes write endurance wear on EEPROM/Flash architectures.
- Insertion Sort Adaptivity: Insertion Sort's runtime is proportional to the number of inversions: . For nearly sorted sequences (), it completes in linear time.
- Modern Hybrid Sorting: Modern production sorting algorithms (Timsort, Introsort) delegate partitions where to Insertion Sort, capitalizing on its low instruction overhead and high cache locality.
References & Academic Attribution
#- Knuth, D. E. (1998). The Art of Computer Programming, Volume 3: Sorting and Searching (2nd ed.), Section 5.2.1: Sorting by Insertion & Section 5.2.2: Sorting by Exchanging. Addison-Wesley.
- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2022). Introduction to Algorithms (4th ed.), Chapter 2: Getting Started (Insertion Sort analysis & loop invariants). MIT Press.
- Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.), Section 2.1: Elementary Sorts. Addison-Wesley.
- Peters, T. (2002). Timsort Description. Python Software Foundation. Available at: https://github.com/python/cpython/blob/main/Objects/listsort.txt.