IntroSort: Mechanism, Complexity Analysis & Interactive Visualizer
Introsort
A hybrid sorting algorithm: starts with Quick Sort for high speed, switches to Heap Sort if recursion limits are hit, and drops to Insertion Sort for tiny subarrays.
How it works
Introsort (Introductory Sort), designed by David Musser in 1997, is the standard sort algorithm in the C++ Standard Template Library (STL). It provides the best of both worlds—Quicksort's speed and Heapsort's worst-case guarantees—using three phases:
- Quicksort Phase: Begin sorting using Quicksort. It partitions subarrays recursively by choosing pivots (typically median-of-three).
- Heapsort Switch: Keep track of recursion depth. If the depth exceeds a threshold (typically
2 · log₂(n)), the partition is likely pathological (e.g. nested duplicate patterns). Switch that partition to Heapsort to ensureO(n log n)worst-case behavior. - Insertion Sort Cleanup: When any subarray size drops below a threshold (usually 16 elements), skip partitioning and sort it quickly using Insertion Sort.
Complexity
O(n log n), making it immune to Quicksort's classic O(n²) worst-case vulnerability.Interactive visualization
Pseudocode
procedure introsort(A): n ← length(A) maxDepth ← 2 * floor(log2(n)) introsortUtil(A, 0, n - 1, maxDepth) procedure introsortUtil(A, left, right, depthLimit): size ← right - left + 1 if size < 16: insertionSort(A, left, right) else if depthLimit == 0: heapsort(A, left, right) else: p ← partition(A, left, right) introsortUtil(A, left, p - 1, depthLimit - 1) introsortUtil(A, p + 1, right, depthLimit - 1)
JavaScript implementation
function introsort(arr) { const n = arr.length; const maxDepth = 2 * Math.floor(Math.log2(n || 1)); function insertionSort(left, right) { for (let i = left + 1; i <= right; i++) { let key = arr[i]; let j = i - 1; while (j >= left && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } function heapsort(left, right) { const size = right - left + 1; function heapify(hSize, i) { let largest = i; const l = 2 * i + 1; const r = 2 * i + 2; if (l < hSize && arr[left + l] > arr[left + largest]) largest = l; if (r < hSize && arr[left + r] > arr[left + largest]) largest = r; if (largest !== i) { [arr[left + i], arr[left + largest]] = [arr[left + largest], arr[left + i]]; heapify(hSize, largest); } } for (let i = Math.floor(size / 2) - 1; i >= 0; i--) heapify(size, i); for (let i = size - 1; i > 0; i--) { [arr[left], arr[left + i]] = [arr[left + i], arr[left]]; heapify(i, 0); } } function partition(left, right) { const pivotVal = arr[right]; let i = left - 1; for (let j = left; j < right; j++) { if (arr[j] < pivotVal) { i++; [arr[i], arr[j]] = [arr[j], arr[i]]; } } [arr[i + 1], arr[right]] = [arr[right], arr[i + 1]]; return i + 1; } function introsortLimit(left, right, depthLimit) { const size = right - left + 1; if (size < 16) { insertionSort(left, right); return; } if (depthLimit === 0) { heapsort(left, right); return; } const p = partition(left, right); introsortLimit(left, p - 1, depthLimit - 1); introsortLimit(p + 1, right, depthLimit - 1); } introsortLimit(0, n - 1, maxDepth); return arr; }
Pros and cons
Pros
- Worst-case runtime is O(n log n), avoiding Quicksort's worst scenarios.
- Highly cache-friendly, executing Quicksort operations primarily.
- Extremely fast average-case performance.
- Operates in-place (O(log n) stack memory).
Cons
- Unstable sorting order (relative positions of duplicates can swap).
- Cannot take advantage of natural runs like Timsort does.
- Slightly higher code complexity due to bundling three algorithms.
When (not) to use it
- Standard in-place sort: Excellent default sort when stability is not a requirement (e.g. C++ vector sorting).
- Strictly stable sorting: Avoid when duplicate stability is essential; use Timsort or Merge Sort instead.
Related reading
Sleep Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A unique concurrency-based sorting algorithm: spawns a separate thread for each element, sleeping for a duration proportional to the element value before writing it to the output.
By Md. Harun-Or-Roshid
Cube Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A parallel dimension sorting algorithm: organizes elements in a 3D coordinate cube and sorts vectors along the height, width, and depth axes sequentially to achieve sorted order.
By Md. Harun-Or-Roshid
Patience Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A card-game inspired sorting algorithm: distributes elements onto a series of piles such that each pile's top is \(\ge\) the incoming value, then performs a multi-way merge across pile tops.
By Md. Harun-Or-Roshid
Library Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A gapped variation of Insertion Sort: leaves empty slots (gaps) in the array, allowing elements to be inserted in \(O(1)\) shift time on average by avoiding massive shifts.
By Md. Harun-Or-Roshid