PHP算法之归并排序、堆排序、快速排序、插入排序、选择排序、冒泡排序

上学时这些算法都是基础中的基础但现在基本都忘记了,现在再复习和总结下:

1.1时间复杂度

一个算法的效率主要从时间复杂度空间复杂度来衡量,时间复杂度:执行算法需要的计算工作量。计算机算法是问题规模n的函数f(n)即算法的时间复杂度,可以表示为T(n)=O(f(n)),时间复杂度计算方式有:

常数阶:O(1)
线性阶:O(n)    
平(立)方阶:O(n^2)/O(n^3)    
特殊平方阶:O(n^2/2+n/2)->O(n^2)
对数阶:O(log2n)
while($n>=1){
  $n=$n/2
}
nlog2n阶,指数阶
O(1)>O(log2n)>O(n)>O(nlog2n)>O(n^2)>O(n^3)>O(2^n)>O(n!)>O(n^n)>O(∞)

时间复杂度其他概念:最坏情况运行时间,一种保证,如果没有特别说明,说的时间复杂度即为最坏情况的时间复杂度

1.2空间复杂度

算法需要消耗内存的空间,记作S(n)=O(f(n)) ,包括程序代码占用空间,输入数据所占用空间和辅助变量所占用空间这三个方面,计算和表达方法与时间复杂度类似,一般用复杂度的渐近性表示,空间复杂度计算方式有时用空间换取时间,冒泡排序的元素交换,空间复杂度为O(1)。

2.1归并排序

将两个(或两个以上)有序表合并成一个新的有序表,即待排序序列分为若干个有序的子序列,再把有序的子序列合并成整体有序序列
时间复杂度:最差(O(nlog2n)),平均(O(nlog2n))
空间复杂度:O(n)

<?php
// 将数组两两拆开比较大小后递归返回数据
function merge($arr){
    $len = count($arr);
    if($len <= 1){
        return $arr;
    }

    $mid = $len>>1;
    $_left_arr = array_slice($arr,0,$mid);
    $_right_arr = array_slice($arr,$mid);
    $left_arr = merge($_left_arr);
    $right_arr = merge($_right_arr);
    $arr = _Sort($left_arr,$right_arr);
    return $arr;
}

// 两个有序数组($left_arr,$right_arr)从头节点项目相互比较截取到第三个数组
function _Sort($left_arr,$right_arr){
    $temp = [];
    while(count($left_arr) && count($right_arr)){
        $temp[] = $left_arr[0]> $right_arr[0]?array_shift($right_arr):array_shift($left_arr);
    }
    return array_merge($temp,$left_arr,$right_arr);
}

$arr = range(1, 10);
shuffle($arr);
$arr = merge($arr);
echo implode(',',$arr);
#结果
#1,2,3,4,5,6,7,8,9,10

2.2堆排序
把待排序的元素安装大小在二叉树位置上排列,排列好的元素要满足:父节点的元素要大于等于子节点;这个过程叫做堆化过程,如果根节点存放的最大的树,则叫做大根堆,如果是最小,就叫小根堆,可以把根节点拿出来,然后再堆化,循环到最后一个节点
时间复杂度:最差(O(nlog2n)),平均(O(nlog2n))
空间复杂度O(1)

<?php
// 当前节点与子节点比较和交换,子子节点逻辑一样
function heapSort(&$arr,$start,$length){
    for($child = 2*$start+1;$child<$length;$child = 2*$child+1){
        if($child != $length -1 && $arr[$child] > $arr[$child+1]){
            $child++;
        }

        if($arr[$start] < $arr[$child]){
            break;
        }

        list($arr[$start],$arr[$child]) = array($arr[$child],$arr[$start]);
        $start = $child;
    }
}

$arr = range(1,10);
shuffle($arr);
$length = count($arr);

// 第一次构建堆,形成了一个大顶(根)堆,每个节点为子节点的最大(小)
for($start = ($length >> 1) -1 ;$start >= 0 ;$start--){
    heapSort($arr,$start,$length);
}

for($i = $length - 1;$i >=0; $i--){
    // 交换根顶和根尾元素
    list($arr[0],$arr[$i]) = array($arr[$i],$arr[0]);

    // 根顶为根尾元素后继续从根节点开始向下调整
    heapSort($arr,0,$i);
}

echo implode(',',$arr);
#结果
#10,9,8,7,6,5,4,3,2,1

2.3快速排序
通过一趟排序将要排序的数据分割成独立的两个部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后按照次方法对这两部分数据进行快速排序。整个排序可以递归完成。
时间复杂度:最差(O(n^2)),平均(O(nlog2n))
空间复杂度:最差(O(n)),平均(O(log2n))

<?php
// 头节点的数组和其他数组比较分成左右两个数组,每个数组递归做同样操作,最后一次按照排好的数组递归返回
function _sort($arr){
    if(count($arr)<=1){
        return $arr;
    }
    $left_arr=array();
    $right_arr=array();
    for($i = 1; $i < count($arr); $i++){
        if($arr[0]>$arr[$i]){
            $left_arr[]=$arr[$i];
        }else{
            $right_arr[]=$arr[$i];
        }
    }
    $left_arr = _sort($left_arr);
    $right_arr = _sort($right_arr);
    return array_merge($left_arr,array($arr[0]),$right_arr);
}

$arr = range(1,10);
shuffle($arr);
$arr = _sort($arr);
echo implode(',',$arr);
#结果
#1,2,3,4,5,6,7,8,9,10

2.4直接排序

前面的数组都是有序的,将下一个数字插入进去
时间复杂度:最坏(O(n^2)),平均O(O(n^2)) 空间复杂度:O(1)

<?php
$arr = range(1,10);
shuffle($arr);
$len = count($arr);
for($i = 1; $i < $len; $i++){
    $temp = $arr[$i];
    for($j = $i-1; $j >= 0; $j--){
        if($temp > $arr[$j]){
            $arr[$j+1] = $arr[$j];
            $arr[$j] = $temp;
        }
    }
}
echo implode(',',$arr);
#结果
#10,9,8,7,6,5,4,3,2,1

2.5选择排序
将第一个数字和后面的数字比较,每次确定第一个参数
时间复杂度:最差(O(n^2)),平均(O(n^2)),空间复杂度:O(1)
                  

<?php
$arr = range(1,10);
shuffle($arr);
for($i = 0;$i < count($arr)-1; $i++){
    $p=$i;
    for($j = $i+1;$j < count($arr);$j++){
        if($arr[$p] < $arr[$j]){
            $p=$j;
        }
    }
    $temp = $arr[$i];
    $arr[$i] = $arr[$p];
    $arr[$p] = $temp;
}
echo implode(',',$arr);
#结果
#10,9,8,7,6,5,4,3,2,1

2.6冒泡排序

相邻的两个数字比较,每次确定最后一个数
时间复杂度:最坏(O(n^2)),平均O(O(n^2))
 

<?php
$arr = range(1,10);
shuffle($arr);
for($i = 0;$i < count($arr)-1; $i++){
    for($j = 0;$j < count($arr)-$i-1; $j++){
        if($arr[$j] > $arr[$j+1]){
            $temp = $arr[$j];
            $arr[$j] = $arr[$j+1];
            $arr[$j+1] = $temp;
        }
    }
}
echo implode(',',$arr);
#结果
#1,2,3,4,5,6,7,8,9,10

总结:快速排序,归并排序的理想时间复杂度都是O(nlog2n)属于6个排序中比较快的,但是快速排序的时间复杂度不稳定,最坏情况下复杂度为O(n^2),所以最理想的算法还是归并排序。

おすすめ

転載: blog.csdn.net/qq_24973351/article/details/116109860