首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 選擇排序算法實現與性能分析:O(n²) 經典排序的優化與實戰應用

     編輯:PHP 綜合知識

算法原理

選擇排序 是一種簡單直觀的比較排序算法。核心思想:

  1. 在未排序序列中找到最小(大)元素
  2. 將其與未排序序列的第一個元素交換
  3. 重複上述步驟,直到所有元素有序

特點:交換次數最少(O(n)),適合寫入成本高的存儲介質(如 EEPROM、Flash)。

PHP 面向對象實現

<?php
class SelectionSort {
    /**
     * 選擇排序(升序)
     * @param array &$arr 引用傳遞,原地排序
     * @param callable|null $compare 自定義比較函數
     * @return void
     */
    public function sort(array &$arr, callable $compare = null): void {
        $compare ??= fn($a, $b) => $a <=> $b; // PHP 7.4+ 箭頭函數
        $len = count($arr);
        
        for ($i = 0; $i < $len - 1; $i++) {
            $minIdx = $i;
            // 內層循環:尋找最小元素索引
            for ($j = $i + 1; $j < $len; $j++) {
                if ($compare($arr[$j], $arr[$minIdx]) < 0) {
                    $minIdx = $j;
                }
            }
            // 交換(僅當找到更小元素時)
            if ($minIdx !== $i) {
                $this->swap($arr, $i, $minIdx);
            }
        }
    }
    
    /**
     * 交換數組兩個位置的元素
     */
    private function swap(array &$arr, int $i, int $j): void {
        [$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]]; // PHP 7.1+ 解構賦值
    }
    
    /**
     * 降序排序
     */
    public function sortDesc(array &$arr): void {
        $this->sort($arr, fn($a, $b) => $b <=> $a);
    }
    
    /**
     * 對象數組按屬性排序
     */
    public function sortByProperty(array &$arr, string $prop, bool $asc = true): void {
        $this->sort($arr, fn($a, $b) => $asc 
            ? ($a->$prop <=> $b->$prop) 
            : ($b->$prop <=> $a->$prop)
        );
    }
}

// 使用示例
$sorter = new SelectionSort();

$numbers = [4, 6, 1, 2, 9, 8, 7, 3, 5];
$sorter->sort($numbers);
echo "升序: " . implode(', ', $numbers) . "\n"; // 1, 2, 3, 4, 5, 6, 7, 8, 9

$objects = [
    (object)['name' => 'C', 'age' => 30],
    (object)['name' => 'A', 'age' => 25],
    (object)['name' => 'B', 'age' => 28],
];
$sorter->sortByProperty($objects, 'age');
echo "按年齡升序: " . json_encode($objects) . "\n";
?>

複雜度分析

指標複雜度說明
時間複雜度(最好)O(n²)無論輸入如何,比較次數固定:n(n-1)/2
時間複雜度(平均)O(n²)
時間複雜度(最壞)O(n²)
空間複雜度O(1)原地排序,僅需常數額外空間
交換次數O(n)最多 n-1 次交換,優於冒泡排序 O(n²)
穩定性不穩定相等元素相對位置可能改變(如 5a, 5b → 交換後變 5b, 5a)

與其他 O(n²) 排序對比

算法比較次數交換/移動次數穩定性適合場景
選擇排序n(n-1)/2≤ n-1不穩定寫入昂貴、小數據量、教學
冒泡排序n(n-1)/2O(n²)穩定近乎有序數據(優化後)、教學
插入排序O(n²)O(n²)穩定小數據、近乎有序、在線排序

優化變體

1. 雙向選擇排序

每輪同時找最小和最大,放到兩端,輪數減半:

public function bidirectionalSort(array &$arr): void {
    $left = 0;
    $right = count($arr) - 1;
    while ($left < $right) {
        $minIdx = $left;
        $maxIdx = $right;
        for ($i = $left; $i <= $right; $i++) {
            if ($arr[$i] < $arr[$minIdx]) $minIdx = $i;
            if ($arr[$i] > $arr[$maxIdx]) $maxIdx = $i;
        }
        $this->swap($arr, $left, $minIdx);
        // 注意:若 maxIdx == left,交換後最大元素已移至 minIdx
        if ($maxIdx === $left) $maxIdx = $minIdx;
        $this->swap($arr, $right, $maxIdx);
        $left++;
        $right--;
    }
}

2. 堆排序(選擇排序的優化版)

利用堆結構將「尋找最小元素」從 O(n) 降為 O(log n),整體複雜度達到 O(n log n):

public function heapSort(array &$arr): void {
    $n = count($arr);
    // 建堆
    for ($i = ($n >> 1) - 1; $i >= 0; $i--) {
        $this->heapify($arr, $n, $i);
    }
    // 排序
    for ($i = $n - 1; $i > 0; $i--) {
        $this->swap($arr, 0, $i);
        $this->heapify($arr, $i, 0);
    }
}
private function heapify(array &$arr, int $n, int $i): void {
    $largest = $i;
    $left = 2 * $i + 1;
    $right = 2 * $i + 2;
    if ($left < $n && $arr[$left] > $arr[$largest]) $largest = $left;
    if ($right < $n && $arr[$right] > $arr[$largest]) $largest = $right;
    if ($largest !== $i) {
        $this->swap($arr, $i, $largest);
        $this->heapify($arr, $n, $largest);
    }
}

實際應用場景

  • 教學演示:算法課程入門、面試考察基礎
  • 極小數據量:n < 50 時,常數因子較小,可能比快排更快
  • 寫入受限存儲:EEPROM、Flash 記憶體、磁帶存儲
  • 併發環境只讀排序:無需複製數組,原地排序佔用最小內存
  • 部分排序需求:只需前 k 小元素(可優化為部分選擇)

PHP 內置排序 vs 手寫排序

$arr = [4, 6, 1, 2, 9, 8, 7, 3, 5];

// 生產代碼永遠使用內置函數
sort($arr);                    // 升序,重建索引
rsort($arr);                   // 降序
asort($arr);                   // 升序,保持索引關係
uasort($arr, fn($a, $b) => $a <=> $b); // 自定義比較,保持索引
usort($arr, fn($a, $b) => $a <=> $b);  // 自定義比較,重建索引

// 內置排序採用 Timsort(PHP 8+)或 QuickSort,平均 O(n log n)、高度優化、穩定
// 手寫排序僅用於教學、特殊約束環境、面試

基準測試(參考)

數據量選擇排序PHP sort()倍數差距
1,000~15 ms~0.3 ms50x
5,000~350 ms~1.8 ms194x
10,000~1.4 s~4 ms350x

總結

選擇排序作為經典 O(n²) 算法,核心價值在於教學示範、交換次數最少理論意義、特殊硬體環境適用性。實際 PHP 開發中,絕不應在生產代碼中使用手寫選擇排序,內置 sort()/usort() 經過 C 層高度優化、採用 Timsort/QuickSort 混合算法、平均 O(n log n)、穩定可靠。理解選擇排序原理、複雜度分析、穩定性特徵、優化方向(堆排序),有助於建立扎實的算法思維,應對面試與底層原理分析。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved