快速排序使用分治策略(Divide and Conquer)来把一个序列分为两个子序列。
原理:
从序列中挑出一个元素,作为"基准"(pivot)
把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作
对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了
<?php
/**
* 快速排序
* 数据结构----------------数组
* 最差时间复杂度-----------每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2)
* 最优时间复杂度-----------每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logn次划分就能结束递归,时间复杂度为O(nlogn)
* 平均时间复杂度-----------O(nlogn)
* 空间复杂度--------------O(logn)
* 稳定性-----------------不稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
$len = count($arr);
function Swap(&$arr, $i, $j)
{
$temp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $temp;
}
// 划分
function Partition(&$arr, $left, $right)
{
$pivot = $arr[$right]; // 每次都选择最后一个元素作为基准
$tail = $left - 1; // tail为小于基准的子数组最后一个元素的索引
for ($i = $left; $i < $right; $i++) { // 遍历基准以外的其他元素
if ($arr[$i] <= $pivot) { // 把小与等于基准的元素放到前一个子数组的末尾
$tail++;
if ($tail != $i) {
Swap($arr, $tail, $i);
}
}
}
Swap($arr, $tail + 1, $right); // 最后把基准放到前一个子数组的后边,剩下的子数组即是大于基准的子数组
return $tail + 1;
}
function QuickSort(&$arr, $left, $right)
{
if ($left >= $right)
return;
$pivot_index = Partition($arr, $left, $right); // 基准的索引
QuickSort($arr, $left, $pivot_index - 1);
QuickSort($arr, $pivot_index + 1, $right);
return $arr;
}
print_r(QuickSort($arr, 0, $len - 1));