一 冒泡排序
// 冒泡排序
function bubble_sort($arr)
{
$len = count($arr);
for ($i = 0; $i < $len -1; $i++) {//循环对比的轮数
for ($j = 0; $j < $len - $i - 1; $j++) {//当前轮相邻元素循环对比
if ($arr[$j] > $arr[$j + 1]) {//如果前边的大于后边的
$tmp = $arr[$j];//交换数据
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $tmp;
}
}
}
return $arr;
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
冒泡排序 | O(n) | O(n2) | O(n2) | 稳定 | O(1) |
二 直接插入排序
function InsertSort(array &$arr){
$count = count($arr);
//数组中第一个元素作为一个已经存在的有序表
for($i = 1;$i < $count;$i ++){
$temp = $arr[$i]; //设置哨兵
for($j = $i - 1;$j >= 0 && $arr[$j] > $temp;$j --){
$arr[$j + 1] = $arr[$j]; //记录后移
}
$arr[$j + 1] = $temp; //插入到正确的位置
}
return $arr;
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
插入排序 | O(n) | O(n2) | O(n2) | 稳定 | O(1) |
三 希尔排序
<?php
//希尔排序(对直接插入排序的改进)
function ShellSort(array $arr)
{
$len = count($arr);
$count = 0;
$f = 5; // 定义因子
$h = 1; // 最小为1
while ($h < $len / $f)
{
$h = $f * $h + 1; // 1, 4, 13, 40, 121, 364, 1093, ...
}
while ($h >= 1)
{
// 将数组变为h有序
for ($i = $h; $i < $len; $i++)
{
// 将a[i]插入到a[i-h], a[i-2*h], a[i-3*h]... 之中 (算法的关键
for ($j = $i; $j >= $h&&$arr[$j] < $arr[$j - $h]; $j -= $h)
{
$tmp = $arr[$j];
$arr[$j] = $arr[$j - $h];
$arr[$j - $h]= $tmp;
}
}
$h = intval($h / $f);
}
return $arr;
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
希尔排序 | O(nlog2n) | O(n2) | O(n2) | 不稳定 | O(1) |
四 选择排序
/**
* 选择排序
* 在一列数字中,选出最小数与第一个位置的数交换。然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
*/
function SelectSort($arr)
{
$len = count($arr);
for ($i = 0; $i < $len - 1; $i++)
{
//定义最小位置
$minIndex = $i;
for ($j = $i + 1; $j < $len; $j++)
{
if ($arr[$j] < $arr[$minIndex])
{
$minIndex = $j;
}
}
if ($i != $minIndex)
{
$tmp = $arr[$i];
$arr[$i] = $arr[$minIndex];
$arr[$minIndex] = $tmp;
}
}
return $arr;
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
选择排序 | O(n2) | O(n2) | O(n2) | 不稳定 | O(1) |
五 快速排序
<?php
function quick_sort($a)
{
// 判断是否需要运行,因下面已拿出一个中间值,这里<=1
if (count($a) <= 1) {
return $a;
}
$middle = $a[0]; // 中间值
$left = array(); // 接收小于中间值
$right = array();// 接收大于中间值
// 循环比较
for ($i=1; $i < count($a); $i++) {
if ($middle < $a[$i]) {
// 大于中间值
$right[] = $a[$i];
} else {
// 小于中间值
$left[] = $a[$i];
}
}
// 递归排序划分好的2边
$left = quick_sort($left);
$right = quick_sort($right);
// 合并排序后的数据,别忘了合并中间值
return array_merge($left, array($middle), $right);
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
快速排序 | O(nlog2n) | O(n2) | O(nlog2n) | 不稳定 | O(log2n)~O(n) |
六 堆排序
function HeapSort($arr)
{
$len = count($arr);
//先将数组构造成大根堆(由于是完全二叉树,所以这里用floor($count/2)-1,下标小于或等于这数的节点都是有孩子的节点)
for ($i = floor($len / 2) - 1; $i >= 0; $i--) //14=29 13=27 12=25 11=23
{
$temp = $arr[$i];
$start = $i;
//沿关键字较大的孩子节点向下筛选
//左右孩子计算(我这里数组开始下标识 0)
//左孩子2 * $start + 1,右孩子2 * $start + 2
for ($j = 2 * $start + 1; $j < $len - 1; $j = 2 * $j + 1)
{
if ($j != $len && $arr[$j] < $arr[$j + 1])
{
$j++; //转化为右孩子
}
if ($temp >= $arr[$j])
{
break; //已经满足大根堆
}
//将根节点设置为子节点的较大值
$arr[$start] = $arr[$j];
//继续往下
$start = $j;
}
$arr[$start] = $temp;
}
for ($i = $len - 1; $i >= 0; $i--)
{
//将堆顶元素与最后一个元素交换,获取到最大元素(交换后的最后一个元素),将最大元素放到数组末尾
$tmp = $arr[0];
$arr[0] = $arr[$i];
$arr[$i] = $tmp;
//经过交换,将最后一个元素(最大元素)脱离大根堆,并将未经排序的新树($arr[0...$i-1])重新调整为大根堆
$temp = $arr[0];
$start = 0;
for ($j = 2 * $start + 1; $j <= $i - 1; $j = 2 * $j + 1)
{
if ($j != $i - 1 && $arr[$j] < $arr[$j + 1])
{
$j++;
}
if ($temp >= $arr[$j])
{
break;
}
$arr[$start] = $arr[$j];
$start = $j;
}
$arr[$start] = $temp;
}
return $arr;
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | 不稳定 | O(1) |
七 归并排序
// 归并排序主程序
function mergeSort($arr) {
$len = count($arr);
if ($len <= 1) {
return $arr;
} // 递归结束条件, 到达这步的时候, 数组就只剩下一个元素了, 也就是分离了数组
$mid = intval($len / 2); // 取数组中间
$left = array_slice($arr, 0, $mid); // 拆分数组0-mid这部分给左边left
$right = array_slice($arr, $mid); // 拆分数组mid-末尾这部分给右边right
$left = mergeSort($left); // 左边拆分完后开始递归合并往上走
$right = mergeSort($right); // 右边拆分完毕开始递归往上走
$arr = merge($left, $right); // 合并两个数组,继续递归
return $arr;
}
// merge函数将指定的两个有序数组(arrA, arr)合并并且排序
function merge($arrA, $arrB) {
$arrC = array();
while (count($arrA) && count($arrB)) {
// 这里不断的判断哪个值小, 就将小的值给到arrC, 但是到最后肯定要剩下几个值,
// 不是剩下arrA里面的就是剩下arrB里面的而且这几个有序的值, 肯定比arrC里面所有的值都大所以使用
$arrC[] = $arrA[0] < $arrB[0] ? array_shift($arrA) : array_shift($arrB);
}
return array_merge($arrC, $arrA, $arrB);
}
排序算法 | 最好时间分析 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | 稳定 | O(n) |
时间复杂度有:常数阶O(1)>对数阶O(log2n)>线性阶O(n)>线性对数阶O(nlog2n)>平方阶O(n2)>立方阶O(n3)
衍生时间复杂度
sum = n*(n+1)/2; //时间复杂度O(1)
for(int i = 0; i < n; i++){
printf("%d ",i);
}
//时间复杂度O(n)
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
printf("%d ",i);
}
}
//时间复杂度O(n^2)
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
printf("%d ",i);
}
}
//运行次数为(1+n)*n/2
//时间复杂度O(n^2)
int i = 0, n = 100;
while(i < n){
i = i * 2;
}
//设执行次数为x. 2^x = n 即x = log2n
//时间复杂度O(log2n)
by 沐澍