排序算法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) 逆序,有序都会最差 | 平均O(logn) 最差O(n) 即栈的深度 | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
希尔排序 | O(n^1.3) | - | O(n^2) | O(1) | 不稳定 |
基数排序 | O(d*(n+r)) | O(d*(n+r)) | O(d*(n+r)) | O(r) | 稳定 |
计数排序 | O(n + k) | O(n + k) | O(n + k) | O(n + k) | 稳定 |
冒泡排序
public function bubbleSort($nums){
$len = count($nums);
$turn = 0;
$flag = false;
for($i = 0; !$flag && $i < $len; $i-){
$flag = true;
for($j = $len - 1; $j > $i; $j--){
if($nums[$j] < $nums[$j - 1]){
$temp = $nums[$j];
$nums[$j] = $nums[$j - 1];
$nums[$j - 1] = $temp;
$flag = true;
}
}
}
}
选择排序
2,2
,1 => 1,2
,2 不稳定
public function selectPop($nums){
$len = count($nums);
for($i = 1; $i < $len; $i++){
$min = $i;
for($j = $i; $j < $len; $j++){
if($nums[j] < $nums[min])
$min = $j;
}
$temp = $nums[$i];
$nums[$i] = $nums[$min];
$nums[$min] = $temp;
}
}
插入排序
public function insertSort($nums){
$len = count($nums);
for($i = 1; $i < $len; $i++){
if($nums[$i] < $nums[$i - 1]){
$temp = $nums[$i];
$j = $i - 1;
for(; $temp < $nums[$j] && $j >= 0; $j--)
$nums[$j + 1] = $nums[$j];
$nums[$j + 1] = $temp;
}
}
}
快速排序
public function quickSort($nums, $start, $end){
if($start < $end){
$pivotPos = partition($nums, $start, $end);
quickSort($nums, $start, $pivotPos - 1);
quickSort($nums, $pivotPos + 1, $high)
}
}
public function partition($nums, $start, $end){
$temp = $nums[$start];
while($start < $end){
while($start < $end && $nums[$end] >= $temp) $end--;
$nums[$start] = $nums[$end];
while($start < $end && $nums[$start] <= $temp) $start++;
$nums[$end] = $num[$start];
}
$nums[$start] = $temp;
return $start;
}
归并排序
public function mergeSort($nums, $start, $end){
if($start < $end){
$mid = ($start + $end) / 2;
mergeSort($nums, $start, $mid);
mergeSort($nums, $mid + 1, $end);
merge($nums, $start, $mid, $end);
}
}
public function merge($nums, $start, $mid, $end){
$temp = [];
for($i = $start; $i < $end; $i++)
$temp[] = $nums[$i];
$i = 0;
$j = $mid - $start;
for($k = $start; $i <= $mid - $start && $j < count($temp); $k++)
$nums[$k] = $temp[$i] > $temp[$j] ? $temp[$i++] : $temp[$j++];
while($i <= $mid - $start) $nums[$k++] = $temp[$i++];
while($j < count($temp)) $nums[$k++] = $temp[$j++];
}
堆排序
nums[0]处不存储数据,当作哨兵位,用来存储中间值。还有个好处是可以让数据从1开始算起,这样算左右节点的时候比较方便
public function heapSort($nums, $len){
buildMaxHeap($nums, $len);
for($i = $len, $i > 1; $i--){
$temp = $nums[1];//堆顶下标为1
$nums[1] = $nums[$i];
$nums[$i] = $temp;//将最大元素放到最后,整理前面i - 1个元素,使之形成新的堆
adjustDown($nums, 1, $i - 1);
}
}
public function buildMaxHeap($nums, $len){
for($i = $len / 2; $i > 0; $i--)
adjustDown($nums, $i, $len);
}
public function adjustDown($nums, $k, $len){
$nums[0] = $nums[$k];
for($i = 2 * $k; $i < $len; $i *= 2){//$i * 2向下调整
if($i < $len && $nums[$i] < $nums[$i + 1])//因为从1开始算数据,所以下标为2的一定为左节点
$i++;
if($nums[0] >= $nums[i]) break;
else{
$nums[$k] = $nums[$i];
$k = $i;
}
}
$nums[$k] = $nums[0];
}
//插入新元素的时候,将新元素放在堆底,然后向上调整
public function adjustUp($nums, $k){
$nums[0] = $nums[$k];
$i = $k / 2;
while($i > 0 && $nums[i] < $nums[0]){
$nums[$k] = $nums[i];
$k = $i;
$i = $k / 2;
}
$nums[$k] = $nums[0];
}
希尔排序
3,2
,2 => 2,2
,3 不稳定
public function shellSort($nums, $len, $n){
for($dk = $len / 2; $dk >= 1; $dk /= 2)
for($i = $dk + 1; $i <= 2*$dk; $i++)
if($nums[$i] < $nums[$i - $dk]){
$nums[0] = $nums[$i];
$j = $i - $dk;
for(; $j > 0 && $nums[0] < $nums[$j]; $j -= $dk)
$nums[$j + $dk] = $nums[$j];
$nums[$j + $dk] = $nums[0];
}
}