A hybrid sorting algorithm that provides both fast average performance and optimal worst-case performance. It starts with quicksort, switches to heapsort when the recursion depth exceeds a level based on the number of elements being sorted, and switches to insertion sort for small partitions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
{
"arr": "[2,1,0,5,8,3,7,4,9,6]"
}Overview
Intro Sort (introspective sort) starts as Quick Sort but watches its own recursion depth. If the depth passes 2 * floor(log2(n)), the input is behaving like a Quick Sort worst case, so it switches that range to Heap Sort, which is guaranteed O(n log n). Small ranges, under 16 elements, are finished with Insertion Sort.
This combination gives Quick Sort's speed on typical data, Heap Sort's worst-case guarantee, and Insertion Sort's low overhead on tiny pieces. It is the algorithm behind std::sort in most C++ standard libraries and behind .NET's Array.Sort.
The default input has 10 elements, below the 16-element threshold, so the dry run goes straight to Insertion Sort — a nice illustration that hybrid sorts often never use their 'main' algorithm on small inputs. Try 20 or more numbers to see partitioning, and a sorted 40-element list to push it toward the heap-sort fallback.
Step by step
- Compute
maxdepth = 2 * floor(log2(n)). - If the current range has fewer than 16 elements, sort it with Insertion Sort and return.
- If
maxdepthhas reached 0, sort the range with Heap Sort and return. - Otherwise partition around a pivot as in Quick Sort.
- Recurse on both sides with
maxdepth - 1.
Complexity
| Case | Cost | Why |
|---|---|---|
| Best case | O(n log n) | Balanced partitions, as in Quick Sort. |
| Average case | O(n log n) | Quick Sort behaviour dominates. |
| Worst case | O(n log n) | The depth limit hands bad ranges to Heap Sort. |
| Extra space | O(log n) | Recursion depth is capped at 2·log2(n). |
When to use it
- General-purpose unstable sorting where worst-case guarantees matter, e.g. sorting untrusted input that could be crafted to attack Quick Sort.
- Systems code in C and C++ — it is the default choice there.
- Any time you would use Quick Sort but cannot rule out adversarial or pre-sorted data.
Common mistakes
- It is not stable; use Merge Sort or Tim Sort when equal keys must keep their order.
- Getting the depth limit wrong either never triggers the fallback or triggers it too often.
- The 16-element cutoff is a tuning constant; benchmarking on your platform may suggest a different value.
A dry run is the best way to check your understanding of Intro Sort: follow each row, predict the next one, and compare. The run below takes 80 steps in total. Steps that only re-print loop counters are left out so the decisions stand out. The Line column refers to the line numbers in the code listing above.
- Input
- 2, 1, 0, 5, 8, 3, 7, 4, 9, 6
- Result
- return value = [0,1,2,3,4,5,6,7,8,9], arr = [0,1,2,3,4,5,6,7,8,9]
| Step | Line | Array | What happens |
|---|---|---|---|
| 1 | 1 | [2, 1, 0, 5, 8, 3, 7, 4, 9, 6] | |
| 4 | 9 | [2, 1, 0, 5, 8, 3, 7, 4, 9, 6] | status = Switching to Insertion Sort |
| 5 | 68 | [2, 1, 0, 5, 8, 3, 7, 4, 9, 6] | begin = 0, end = 9, status = Running Insertion Sort |
| 9 | 72 | [2, 1, 0, 5, 8, 3, 7, 4, 9, 6] | j = 0, key = 1, condition = 2 > 1 |
| 10 | 73 | [2, 2, 0, 5, 8, 3, 7, 4, 9, 6] | |
| 12 | 76 | [1, 2, 0, 5, 8, 3, 7, 4, 9, 6] | |
| 16 | 72 | [1, 2, 0, 5, 8, 3, 7, 4, 9, 6] | j = 1, key = 0, condition = 2 > 0 |
| 17 | 73 | [1, 2, 2, 5, 8, 3, 7, 4, 9, 6] | |
| 19 | 72 | [1, 2, 2, 5, 8, 3, 7, 4, 9, 6] | j = 0, key = 0, condition = 1 > 0 |
| 20 | 73 | [1, 1, 2, 5, 8, 3, 7, 4, 9, 6] | |
| 22 | 76 | [0, 1, 2, 5, 8, 3, 7, 4, 9, 6] | |
| 34 | 72 | [0, 1, 2, 5, 8, 3, 7, 4, 9, 6] | j = 4, key = 3, condition = 8 > 3 |
| 35 | 73 | [0, 1, 2, 5, 8, 8, 7, 4, 9, 6] | |
| 37 | 72 | [0, 1, 2, 5, 8, 8, 7, 4, 9, 6] | j = 3, key = 3, condition = 5 > 3 |
| 38 | 73 | [0, 1, 2, 5, 5, 8, 7, 4, 9, 6] | |
| 40 | 76 | [0, 1, 2, 3, 5, 8, 7, 4, 9, 6] | |
| 44 | 72 | [0, 1, 2, 3, 5, 8, 7, 4, 9, 6] | j = 5, key = 7, condition = 8 > 7 |
| 45 | 73 | [0, 1, 2, 3, 5, 8, 8, 4, 9, 6] | |
| 47 | 76 | [0, 1, 2, 3, 5, 7, 8, 4, 9, 6] | |
| 51 | 72 | [0, 1, 2, 3, 5, 7, 8, 4, 9, 6] | j = 6, key = 4, condition = 8 > 4 |
| 52 | 73 | [0, 1, 2, 3, 5, 7, 8, 8, 9, 6] | |
| 54 | 72 | [0, 1, 2, 3, 5, 7, 8, 8, 9, 6] | j = 5, key = 4, condition = 7 > 4 |
| 55 | 73 | [0, 1, 2, 3, 5, 7, 7, 8, 9, 6] | |
| 57 | 72 | [0, 1, 2, 3, 5, 7, 7, 8, 9, 6] | j = 4, key = 4, condition = 5 > 4 |
| 58 | 73 | [0, 1, 2, 3, 5, 5, 7, 8, 9, 6] | |
| 60 | 76 | [0, 1, 2, 3, 4, 5, 7, 8, 9, 6] | |
| 68 | 72 | [0, 1, 2, 3, 4, 5, 7, 8, 9, 6] | j = 8, key = 6, condition = 9 > 6 |
| 69 | 73 | [0, 1, 2, 3, 4, 5, 7, 8, 9, 9] | |
| 71 | 72 | [0, 1, 2, 3, 4, 5, 7, 8, 9, 9] | j = 7, key = 6, condition = 8 > 6 |
| 72 | 73 | [0, 1, 2, 3, 4, 5, 7, 8, 8, 9] | |
| 74 | 72 | [0, 1, 2, 3, 4, 5, 7, 8, 8, 9] | j = 6, key = 6, condition = 7 > 6 |
| 75 | 73 | [0, 1, 2, 3, 4, 5, 7, 7, 8, 9] | |
| 77 | 76 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
| 80 | 4 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | return value = [0,1,2,3,4,5,6,7,8,9] |