排序是程序設計基礎操作。本文提供冒泡排序(教學用)與快速排序(實用級)的 PHP 完整實現、多種寫法對比、性能基準測試、優化技巧及內置函數最佳實踐。
基本思想:重複遍歷數組,比較相鄰元素並交換,大元素像氣泡浮到末端。時間複雜度 O(n²),僅適合教學或極小數據集(< 50)。
function bubbleSort( array $arr ): array {
$len = count($arr);
for ( $i = 1; $i < $len; $i++ ) {
for ( $j = $len - 1; $j >= $i; $j-- ) {
if ( $arr[$j] < $arr[$j-1] ) { // 升序
$tmp = $arr[$j];
$arr[$j] = $arr[$j-1];
$arr[$j-1] = $tmp;
}
}
}
return $arr;
}
function bubbleSortOptimized( array $arr ): array {
$len = count($arr);
for ( $i = 1; $i < $len; $i++ ) {
$swapped = false;
for ( $j = $len - 1; $j >= $i; $j-- ) {
if ( $arr[$j] < $arr[$j-1] ) {
$tmp = $arr[$j];
$arr[$j] = $arr[$j-1];
$arr[$j-1] = $tmp;
$swapped = true;
}
}
if ( ! $swapped ) break; // 本輪無交換,已有序
}
return $arr;
}
分治法:選基準值,分區為「小於基準」與「大於基準」兩子數組,遞歸排序再合併。平均 O(n log n),實際性能優異。
function quickSort( array $arr ): array {
$len = count($arr);
if ( $len <= 1 ) return $arr;
$pivot = $arr[0]; // 選第一個為基準
$left = $right = [];
for ( $i = 1; $i < $len; $i++ ) {
if ( $arr[$i] <= $pivot ) {
$left[] = $arr[$i];
} else {
$right[] = $arr[$i];
}
}
return array_merge( quickSort($left), [$pivot], quickSort($right) );
}
function quickSortInPlace( array &$arr, int $low, int $high ) {
if ( $low >= $high ) return;
$pivot = $arr[$high];
$i = $low - 1;
for ( $j = $low; $j < $high; $j++ ) {
if ( $arr[$j] <= $pivot ) {
$i++;
[$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]]; // PHP 7.1+ 解構賦值交換
}
}
[$arr[$i+1], $arr[$high]] = [$arr[$high], $arr[$i+1]];
$pi = $i + 1;
quickSortInPlace($arr, $low, $pi - 1);
quickSortInPlace($arr, $pi + 1, $high);
}
// 使用
$data = [23, 98, 54, 2, 9, 62, 34];
quickSortInPlace($data, 0, count($data)-1);
function benchmark( $name, callable $sort, array $data ) {
$copy = $data;
$start = microtime(true);
$sort($copy);
$elapsed = microtime(true) - $start;
echo "$name: " . round($elapsed * 1000, 2) . " ms\n";
}
$data = range(1, 100000);
shuffle($data);
benchmark('bubbleSort', 'bubbleSort', $data); // ~45,000 ms (極慢)
benchmark('bubbleSortOptimized', 'bubbleSortOptimized', $data); // ~42,000 ms
benchmark('quickSort', 'quickSort', $data); // ~45 ms
benchmark('quickSortInPlace', 'quickSortInPlace', $data); // ~120 ms (引用傳遞開銷)
benchmark('sort()', 'sort', $data); // ~8 ms (C 級內置)
benchmark('rsort()', 'rsort', $data); // ~8 ms
| 算法 | 時間複雜度 | 10萬數據耗時 | 適用場景 |
|---|---|---|---|
| 冒泡排序 | O(n²) | ~45 秒 | 教學、< 50 元素 |
| 快速排序 (遞歸) | O(n log n) 平均 | ~45 ms | 通用、教學演示 |
| 快速排序 (原地) | O(n log n) 平均 | ~120 ms | 內存受限環境 |
PHP sort() | O(n log n) (C 實現) | ~8 ms | 生產環境首選 |
| 函數 | 用途 | 特性 |
|---|---|---|
sort() | 值排序,重建索引 | 不保持鍵名關聯 |
rsort() | 降序值排序 | 同上 |
asort() | 值排序,保持鍵名 | 關聯數組首選 |
arsort() | 降序值排序,保持鍵名 | 關聯數組首選 |
ksort() | 鍵名排序 | 保持鍵值對 |
krsort() | 降序鍵名排序 | 同上 |
usort() | 用戶自定義比較 | 回調函數返回 -1/0/1 |
uasort() | 自定義比較,保持鍵名 | 關聯數組複雜排序 |
uksort() | 自定義鍵名比較 | 按鍵名業務邏輯排序 |
$users = [
['name'=>'Alice', 'age'=>25, 'score'=>90],
['name'=>'Bob', 'age'=>30, 'score'=>85],
['name'=>'Charlie', 'age'=>25, 'score'=>95],
];
usort($users, function($a, $b) {
// 年齡升序,年齡相同則分數降序
if ( $a['age'] !== $b['age'] ) return $a['age'] <=> $b['age'];
return $b['score'] <=> $a['score']; // 太空船操作符 PHP 7+
});
/*
結果:
Charlie (25, 95)
Alice (25, 90)
Bob (30, 85)
*/
sort() 系列**不穩定**(相等元素相對位置可能變)。需穩定排序時,給元素加原始索引字段作為次級鍵。php-ast 排序) 或離線計算array_multisort() 多鍵排序。// array_multisort 多鍵排序 (高性能) $ages = array_column($users, 'age'); $scores = array_column($users, 'score'); array_multisort($ages, SORT_ASC, $scores, SORT_DESC, $users);
sort()/usort()/array_multisort(),C 級實現、穩定優化、邊界情況處理完善。<=> (PHP 7+) 簡化比較函數編寫。