Quick sort
Partition around a pivot, recurse on both sides, see why a bad pivot makes it O(n²), and how .NET’s introsort and quickselect build on it.
Partitioning (Lomuto scheme)
j, and keep a boundary i: everything before i is smaller than the pivot. When a[j] is smaller, swap it to position i and move the boundary. Finally swap the pivot to position i.
static void QuickSort(int[] a, int lo, int hi){ if (lo >= hi) return; int p = Partition(a, lo, hi); // pivot ends at index p, in its final place QuickSort(a, lo, p - 1); // smaller values QuickSort(a, p + 1, hi); // bigger values} static int Partition(int[] a, int lo, int hi){ int mid = lo + (hi - lo) / 2; (a[mid], a[hi]) = (a[hi], a[mid]); // use the middle value as pivot, moved to the end int pivot = a[hi]; int i = lo; // a[lo..i-1] < pivot for (int j = lo; j < hi; j++) { if (a[j] < pivot) { (a[i], a[j]) = (a[j], a[i]); i++; } } (a[i], a[hi]) = (a[hi], a[i]); // pivot into its final place return i;} int[] data = { 7, 2, 9, 4, 10, 1, 6, 3, 8, 5 };QuickSort(data, 0, data.Length - 1); // sort the whole arrayConsole.WriteLine(string.Join(" ", data));1 2 3 4 5 6 7 8 9 10
Good pivots, bad pivots
| Pivot choice | Effect |
|---|---|
Quick sort in .NET: introsort
Array.Sort, List<T>.Sort and Span<T>.Sort use introsort (introspective sort): quick sort with a median-of-three pivot, plus two safety nets. Pieces of 16 or fewer items are finished with insertion sort. If the recursion gets suspiciously deep (a bad-pivot input), it switches to heap sort, which is always O(n log n). You get quick sort’s speed with a guaranteed worst case.
| Property | Quick sort |
|---|---|
O(n log n), worst O(n²) | |
O(log n) stack on average (in place otherwise) | |
Bonus: quickselect
// k = 1 means the smallest valuestatic int KthSmallest(int[] a, int k){ int lo = 0, hi = a.Length - 1, target = k - 1; while (true) { int p = Partition(a, lo, hi); // the same Partition as above if (p == target) return a[p]; if (p < target) lo = p + 1; // the answer is on the right else hi = p - 1; // the answer is on the left }} Console.WriteLine(KthSmallest([7, 2, 9, 4, 10, 1, 6, 3, 8, 5], 3));3
{ 2, 0, 2, 1, 1, 0 } → 0 0 1 1 2 2. This is the “Dutch national flag” problem, a three-way partition.
Show a hint
low, mid, high: 0s before low, 1s between low and mid, 2s after high. Look at a[mid]: a 0 swaps to low (advance both), a 1 just advances mid, a 2 swaps to high (decrease high, do not advance mid).
Show the solution
static void SortColors(int[] a){ int low = 0, mid = 0, high = a.Length - 1; while (mid <= high) { if (a[mid] == 0) { (a[low], a[mid]) = (a[mid], a[low]); low++; mid++; } else if (a[mid] == 1) { mid++; } else { (a[mid], a[high]) = (a[high], a[mid]); high--; // the swapped-in value is unchecked: keep mid } }} int[] a = { 2, 0, 2, 1, 1, 0 };SortColors(a);Console.WriteLine(string.Join(" ", a));0 0 1 1 2 2
Remember
Quick sort partitions around a pivot (smaller left, bigger right), then sorts each side. Average O(n log n), in place, not stable; a bad pivot gives O(n²). .NET uses introsort: quick sort + insertion sort for small pieces + heap sort as a safety net. Quickselect finds the k-th smallest value in O(n) on average.