Back to Catalog
Big O
Efficient
O(n log n) - Linearithmic Time
The sweet spot for sorting — better than O(n²), as good as sorting gets.
Intent & Description
Real-world Use Case
Database ORDER BY on 10M rows — the query engine uses merge sort or a heap-based sort to return sorted results in O(n log n). Building a leaderboard, sorting search results by relevance, or merging two sorted lists all live here.
Source
📌 TL;DR
O(n log n) = the sorting sweet spot. You cannot sort faster (in general). Use your language’s built-in sort — it is already optimal and battle-tested.
Advantages
- Provably optimal for general comparison-based sorting
- Scales well — 100M items is very manageable
- Language built-ins (V8 Timsort, Java’s Arrays.sort) are O(n log n) and extremely well optimized
- Merge sort variant is stable (preserves original order of equal elements)
Disadvantages
- Merge sort requires O(n) extra memory for the merge step
- Quicksort has O(n²) worst case on adversarial input (mitigated by random pivot)
- Slower than O(n) for specific data types (integers, short strings) where counting/radix sort applies
- More complex to implement correctly than O(n²) bubble sort
Implementation Example
// O(n log n) — Merge Sort (stable, guaranteed)
function mergeSort(arr) {
if (arr.length <= 1) return arr; // Base case
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid)); // Recurse left half
const right = mergeSort(arr.slice(mid)); // Recurse right half
// Recursion depth is O(log n), merge at each level is O(n) — total O(n log n)
return merge(left, right);
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
left[i] <= right[j] ? result.push(left[i++]) : result.push(right[j++]);
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
// O(n log n) — Quicksort (in-place, average case)
function quickSort(arr, lo = 0, hi = arr.length - 1) {
if (lo >= hi) return;
const pivot = partition(arr, lo, hi); // Partition around pivot
quickSort(arr, lo, pivot - 1);
quickSort(arr, pivot + 1, hi);
// Average log n levels deep, O(n) work per level — O(n log n) average
}
function partition(arr, lo, hi) {
const pivot = arr[hi];
let i = lo - 1;
for (let j = lo; j < hi; j++) {
if (arr[j] <= pivot) [arr[++i], arr[j]] = [arr[j], arr[i]];
}
[arr[i + 1], arr[hi]] = [arr[hi], arr[i + 1]];
return i + 1;
}