介紹
快速排序是一種高效的排序演算法,它透過不斷地將一個陣列分成兩個子數組來實現排序。在快速排序演算法中,一個基準值(pivot)被選出並所有小於基準值的元素放在其左側,而所有大於基準值的元素放在其右側。然後,這個過程被遞歸地應用在左右兩側的子數組中,直到整個數組有序為止。
快速排序是一個遞歸函數,因為它需要將原問題拆解成兩個更小的子問題,然後透過遞歸地求解這些子問題來求解原問題。雖然這種方法在某些情況下可以很有效地工作,但它也有一些限制。具體來說,在處理大型數組時,遞歸演算法可能會耗盡電腦的堆疊空間,從而引發棧溢位異常。此外,遞歸函數呼叫的額外開銷也可能導致演算法的效能下降。
因此,在某些情況下,使用非遞迴的實作方法可能更為適當。在本文中,我們將介紹一種使用PHP實作快速排序的非遞歸演算法。
演算法實作
我們先定義一個輔助函數partition,用來將一個陣列分成兩個子陣列:一個包含所有小於基準值的元素,一個包含所有大於基準值的元素。
function partition(&$arr, $left, $right) { $pivot = $arr[$right]; // 选择最后一个元素作为基准值 $i = $left - 1; for ($j = $left; $j < $right; $j++) { if ($arr[$j] < $pivot) { $i++; list($arr[$i], $arr[$j]) = array($arr[$j], $arr[$i]); // 交换i和j处的元素 } } list($arr[$i + 1], $arr[$right]) = array($arr[$right], $arr[$i + 1]); // 将基准值放到正确的位置 return $i + 1; }
此函數從陣列中選擇最後一個元素作為基準值,並透過交換陣列元素將所有小於基準值的元素放到陣列的左邊。在這個過程中,我們用變數 $i 來記錄目前處理的子數組的下標,$j 用來遍歷整個數組。當我們找到一個小於基準值的元素時,我們將 $i 向右移動一位,並將這個元素放到 $i 的位置。最後,我們將基準值放到最終的位置 $i 1 上。
有了 partition 函數,我們現在可以實作快速排序演算法的非遞迴版本。在該版本中,我們使用一個堆疊來儲存待處理的子數組。當我們處理一個子數組時,我們首先在堆疊中記錄該子數組的左右邊界,然後不斷將它劃分成兩個更小的子數組,直到所有子數組都已有序為止。
function quick_sort(&$arr) { $stack = new SplStack(); // 使用SplStack实现栈 $stack->push(count($arr) - 1); // 将整个数组的下标压入栈 $stack->push(0); while (!$stack->isEmpty()) { $left = $stack->pop(); $right = $stack->pop(); $pivotIndex = partition($arr, $left, $right); if ($left < $pivotIndex - 1) { $stack->push($pivotIndex - 1); $stack->push($left); } if ($pivotIndex + 1 < $right) { $stack->push($right); $stack->push($pivotIndex + 1); } } }
在這個版本的程式碼中,我們使用 SplStack 類別來實作堆疊。我們首先將整個陣列的左右邊界壓入堆疊中,然後不斷從堆疊中取出左右邊界,並將它們傳遞給 partition 函數來進行子數組的劃分。如果 left < pivotIndex - 1,則表示左側子數組尚未有序,將其壓入堆疊中等待處理。同樣地,如果 pivotIndex 1 < right,則表示右側子數組尚未有序,將其壓入堆疊中等待處理。
此演算法的時間複雜度為 O(nlogn)。雖然它不如遞歸版快速排序在所有情況下都快,但它可以顯著降低演算法的空間複雜度,並避免了遞歸函數呼叫的開銷。如果您需要在PHP中快速排序一個大型數組,這種演算法可能比遞歸版的快速排序更適合您的需求。
以上是PHP怎麼實作快速排序的非遞歸演算法的詳細內容。更多資訊請關注PHP中文網其他相關文章!