Sorting — Selection, Bubble, Insertion, Merge Sort and Quicksort
The three elementary sorts with exact comparison and swap counts, inversions and adaptivity, stability and in-place sorting, merge sort (top-down, merging, recurrence, space), quicksort (Lomuto and Hoare partitions, pivot choice, best/average/worst case), the Ω(n log n) lower bound for comparison sorting, and a comparison table to answer "which sort?" questions.
Vocabulary
| Term | Meaning |
|---|---|
| In place | uses (or ) extra memory |
| Stable | equal keys keep their relative order — needed when sorting by several keys in turn |
| Adaptive | faster on nearly sorted input |
| Inversion | a pair with ; for sorted, for reversed, on average |
| Comparison sort | only learns about the keys by comparing pairs |
Selection sort
Repeatedly select the minimum of the unsorted suffix and swap it to the front.
def selection_sort(a):
n = len(a)
for i in range(n - 1):
m = i
for j in range(i + 1, n):
if a[j] < a[m]:
m = j
a[i], a[m] = a[m], a[i]
return a
- Comparisons: always . Swaps: at most (the fewest of any simple sort — useful when writes are expensive).
- in every case; in place; not stable; not adaptive.
Bubble sort
Sweep left to right, swapping adjacent out-of-order pairs; after pass the largest elements are in their final places.
def bubble_sort(a):
n = len(a)
for i in range(n - 1):
swapped = False
for j in range(n - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
swapped = True
if not swapped: # early exit: makes the best case O(n)
break
return a
- Swaps = number of inversions. Comparisons: worst ; best with the early-exit flag.
- In place, stable, adaptive (with the flag). Rarely the right choice in practice.
Insertion sort
Grow a sorted prefix; insert each new element into place by shifting larger elements right.
def insertion_sort(a):
for i in range(1, len(a)):
key = a[i]
j = i - 1
while j >= 0 and a[j] > key:
a[j + 1] = a[j] # shift
j -= 1
a[j + 1] = key
return a
- Shifts = inversions; comparisons between (sorted) and (reversed).
- Best , average and worst ; in place, stable, adaptive; excellent for small or nearly sorted arrays, which is why hybrid sorts (Timsort, introsort) use it for small runs.
Merge sort (divide and conquer)
Split in half, sort each half recursively, merge the two sorted halves.
def merge_sort(a):
if len(a) <= 1:
return a
mid = len(a) // 2
left, right = merge_sort(a[:mid]), merge_sort(a[mid:])
out, i, j = [], 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]: # <= keeps it stable
out.append(left[i]); i += 1
else:
out.append(right[j]); j += 1
return out + left[i:] + right[j:]
- in every case; at most comparisons.
- Merging lists of sizes and : between and comparisons.
- Needs extra space for arrays (not in place); stable; ideal for linked lists and external sorting of data that doesn't fit in memory.
Quicksort (divide and conquer)
Choose a pivot, partition the array into elements ≤ pivot and > pivot, then recursively sort both sides. All the work is in partitioning; there is no merge step.
def quicksort(a, lo=0, hi=None):
if hi is None:
hi = len(a) - 1
if lo < hi:
p = partition(a, lo, hi) # Lomuto: pivot = a[hi]
quicksort(a, lo, p - 1)
quicksort(a, p + 1, hi)
return a
- Lomuto partition (pivot = last element) is simple; Hoare partition (two pointers moving inward) does about three times fewer swaps.
- Best/average: (about comparisons on average). Worst: when the pivot is always the smallest or largest — e.g. sorted input with first/last-element pivots, or all-equal keys with a naive partition.
- In place ( stack expected, worst unless you recurse on the smaller side first); not stable; usually the fastest in practice thanks to cache-friendly scanning.
- Fixes for bad pivots: random pivot, median-of-three, three-way partitioning for duplicates; introsort switches to heapsort when recursion gets too deep.
Lower bound and non-comparison sorts
Any comparison sort corresponds to a binary decision tree with at least leaves, so the worst case needs at least comparisons (e.g. at least 3 comparisons for 3 elements, 5 for 4 elements).
Counting sort ( for keys in ), radix sort and bucket sort avoid comparisons and can run in linear time for suitable keys.
Which sort?
| Algorithm | Best | Average | Worst | Extra space | Stable | In place |
|---|---|---|---|---|---|---|
| Selection | no | yes | ||||
| Bubble (with flag) | yes | yes | ||||
| Insertion | yes | yes | ||||
| Merge | yes | no | ||||
| Quick | no | yes | ||||
| Heap | no | yes | ||||
Python sorted (Timsort) | yes | no |
Quick revision
Practice questions
GATE-style questions: 4 one-mark and 7 two-mark. Wrong MCQs cost ⅓ of their marks in the real exam; MSQ and NAT have no negative marking. Attempt each before opening the solution.
Selection sort is run on an array of 10 elements. The number of element comparisons it makes is ______.
The number of swaps performed by bubble sort (swapping adjacent out-of-order elements) to sort [3, 1, 4, 2] in ascending order is ______.
Which of the following sorting algorithms are stable in their standard implementations?
One or more options are correct.
Insertion sort is run on an already sorted array of 8 elements. The number of element comparisons is ______.
Quicksort that always picks the first element as pivot is run on an array that is already sorted. Its running time is
What does this program print?
def partition(a, lo, hi):
pivot = a[hi]
i = lo - 1
for j in range(lo, hi):
if a[j] <= pivot:
i += 1
a[i], a[j] = a[j], a[i]
a[i + 1], a[hi] = a[hi], a[i + 1]
return i + 1
a = [4, 7, 2, 9, 1, 5]
p = partition(a, 0, len(a) - 1)
print(p, a)
The maximum number of comparisons needed to merge two sorted lists of 4 elements each into one sorted list is ______.
Any comparison-based sorting algorithm needs, in the worst case, at least
Bubble sort (ascending, comparing neighbours left to right) is applied to [5, 1, 4, 2, 8]. The number of swaps made during the first pass is ______.
Which statements are correct?
One or more options are correct.
Insertion sort is applied to [5, 4, 3, 2, 1]. The total number of element shifts (moves of an element one position to the right) is ______.