Sorting algorithms — bubble, merge, quick sort — PHP usort() internals
Concept
Sorting algorithms — understanding the tradeoffs, not just the code. In practice, use PHP's built-in sort()/usort() (they use Timsort, an adaptive O(n log n) algorithm). Know sorting internals for interviews and for choosing the right approach.
Bubble Sort — O(n²) time, O(1) space. Compare adjacent pairs, swap if out of order. Repeat n times. Simple but slow — only useful as a teaching example.
Selection Sort — O(n²) time, O(1) space. Find the minimum, place it at position 0. Find the next minimum, place at position 1. Etc. Fewer swaps than bubble sort.
Insertion Sort — O(n²) worst, O(n) best (already sorted). Builds a sorted subarray by inserting each element in its correct position. Excellent for small arrays and nearly-sorted data. Used by Timsort for small chunks.
Merge Sort — O(n log n) guaranteed. Divide in half, sort each half recursively, merge. Stable (preserves order of equal elements). O(n) extra space for the merge step. Predictable performance.
Quick Sort — O(n log n) average, O(n²) worst (bad pivot). Pivot, partition into smaller/larger, recurse. In-place (no extra array). Fastest in practice for cache performance. PHP's sort uses Timsort (hybrid), not quicksort.
PHP's sort() family:
sort()/rsort(): Sort array values, re-index.asort()/arsort(): Sort values, preserve keys.ksort()/krsort(): Sort by keys.usort(): Sort with a custom comparison function.- All use Timsort (hybrid merge + insertion sort).
O(n log n).
Stability: A stable sort preserves the relative order of equal elements. Timsort (PHP) is stable. Quicksort is not stable.
Code Example
<?php
// Bubble sort — O(n²) — do NOT use in production
function bubbleSort(array $arr): array
{
$n = count($arr);
for ($i = 0; $i < $n - 1; $i++) {
$swapped = false;
for ($j = 0; $j < $n - $i - 1; $j++) {
if ($arr[$j] > $arr[$j + 1]) {
[$arr[$j], $arr[$j + 1]] = [$arr[$j + 1], $arr[$j]];
$swapped = true;
}
}
if (!$swapped) break; // already sorted optimization
}
return $arr;
}
// Merge sort — O(n log n), stable, O(n) space
function mergeSort(array $arr): array
{
$n = count($arr);
if ($n <= 1) return $arr;
$mid = intdiv($n, 2);
$left = mergeSort(array_slice($arr, 0, $mid));
$right = mergeSort(array_slice($arr, $mid));
return merge($left, $right);
}
function merge(array $left, array $right): array
{
$result = [];
$i = $j = 0;
while ($i < count($left) && $j < count($right)) {
if ($left[$i] <= $right[$j]) $result[] = $left[$i++];
else $result[] = $right[$j++];
}
return array_merge($result, array_slice($left, $i), array_slice($right, $j));
}
// Quick sort — O(n log n) average, O(n²) worst
function quickSort(array $arr): array
{
if (count($arr) <= 1) return $arr;
$pivot = $arr[0];
$left = array_filter(array_slice($arr, 1), fn($x) => $x <= $pivot);
$right = array_filter(array_slice($arr, 1), fn($x) => $x > $pivot);
return array_merge(quickSort(array_values($left)), [$pivot], quickSort(array_values($right)));
}
// PHP built-in — use these in practice
$data = [5, 3, 8, 1, 9, 2];
sort($data); // [1, 2, 3, 5, 8, 9]
$users = [['name' => 'Charlie', 'age' => 30], ['name' => 'Alice', 'age' => 25]];
usort($users, fn($a, $b) => $a['age'] <=> $b['age']); // sort by age ascending
// Multi-column sort (like SQL ORDER BY name ASC, age DESC)
usort($users, function ($a, $b) {
return $a['name'] <=> $b['name'] ?: $b['age'] <=> $a['age'];
});
// usort internals: PHP's Timsort is O(n log n), stable, adaptive
// When array is already sorted or nearly sorted, Timsort approaches O(n)