算法基本和常见排序算法

c/c++

浏览数:21

2019-9-8

算法5大特征
有穷,确切,输入项,输出项,可行性
时间复杂度:执行算法所需要的计算工作量,一般来说,计算机算法是问题规模n的函数f(n),算法的时间复杂度因此记做 T(n)=O(f(n))
问题的规模越大,算法执行的时间的增长率与f(n) 的增长率正相关,称作渐进时间复杂度(Asympotic Time Complexity)

计算方式:

1.计算次数公式
1+2+3+…….+n;

<?php
$sum=0;
for($i=1;$i<=$n;$i++){
sum+=$i;
}
?>

计算n次,时间复杂度为O(n)
2.用常数1来取代所有时间中所有加法常数 比如O(3) 记做O(1)

<?php
function test($n){
echo $n;
echo $n;
echo $n;
}
?>

O(3) 记做O(1)
3.在修改后的运算次数函数中,只保留最高阶项
n^2+n+1 则记做O(n^2)
4.如果最高阶存在且不是1,则去除与这个项相乘的常数
2n^2+3n+1 记做O(n^2)

常数阶:O(1)
线性阶:O(n)
平(立)方阶:O(n^2),O(n^3)

<?php
$sum=0;
for($i=1;$i<=$n;$i++){
for($j=1;$j<=$n;$j++){
$sum+=$j;
}
}
?>

两层循环 O(n^2) 三层O(n^3)
特殊平方阶:O(n^2/2+n/2)-> O(n^2)

for(){
for(){

}
}
for(){

}
echo $a+$b;

n^2+n+1->O(n^2)

最坏情况:最坏情况下的运行时间,一种保证,如果没特殊说明,说的时间复杂度即为最坏情况下的时间复杂度

平均情况:期望的运行时间

空间复杂度:算法需要消耗的内存空间,记作S(n)=O(f(n))

包括程序代码所占用的空间,

输入数据所占用的空间和

辅助变量所占用的空间

这3个方面

计算和表示方法与时间复杂度类似,一般用复杂度的渐进性表示

——————-

排序算法及其时间复杂度空间复杂度

1.冒泡排序

<?php
$arr=[8,7,6,4,3,10,1,-1];
$len=count($arr);

for($i=0;$i<$len;$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;
        }
    }
}
echo "<hr>";
print_r($arr);
?>

 内部循环每一轮将最大的沉到尾部

优化见:冒泡

时间复杂度:O(n^2),平均O(n^2)
空间复杂度:O(1)

2.选择排序

每次从待排序的序列中取出最小或者最大的元素放在序列的起始位置,直到待排序的数据元素排完

<?php
$arr=[8,7,6,4,3,10,1,-1];


$len=count($arr);

for($i=0;$i<$len;$i++){
    $min_key=$i;
    for($j=$i+1;$j<$len;$j++){
        if($arr[$j]<$arr[$min_key]){
            $min_key=$j;
        }
    }
    if($min_key!=$i){
        $tmp=$arr[$i];
        $arr[$i]=$arr[$min_key];
        $arr[$min_key]=$tmp;
    } 
}
?>

比较时间:T = (n-1)+ (n -2)+(n – 3)…. + 1; ===>> T = [n*(n-1) ] / 2;
交换时间:最好的情况全部元素已经有序,则 交换次数为0,最差的情况,全部元素逆序,就要交换 n-1 次
所以最优的时间复杂度 和最差的时间复杂度 和平均时间复杂度 都为:O(n^2)
空间复杂度:O(1)

3.快速排序

选择一个基数,通过一趟排序将要排序的数据分割成独立的2部分,一部分比这个基数都要小,一部分比这个基数都要大,然后按照此方法再去处理这2部分

时间复杂度:最差 O(n^2) ,平均 O(nlogn)

空间复杂度:最差O(n),平均 O(logn)

<?php
function quick_sort(&$s, $l, $r)
{
    if ($l < $r)
    {
        //Swap(s[$l], s[($l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        $i = $l; $j = $r; $x = $s[$l];
        while ($i < $j)
        {
            while($i < $j && $s[$j] >= $x) // 从右向左找第一个小于x的数
                $j--;
            if($i < $j)
                $s[$i++] = $s[$j];

            while($i < $j && $s[$i] <$x) // 从左向右找第一个大于等于x的数
                $i++;
            if($i < $j)
                $s[$j--] = $s[$i];
        }
        $s[$i] = $x;
        quick_sort($s, $l, $i - 1); // 递归调用
        quick_sort($s, $i + 1, $r);
    }
}
$arr=array(6,1,2,7,9,3,4,5,10,8);
print_r($arr);
quick_sort($arr,0,count($arr)-1);
print_r($arr);

或者借用php函数

<?php

    //待排序数组
    $arr=array(6,3,8,7,4,2,5,1,0,-3,-1);
    //函数实现快速排序
    function quick_sort($arr)
    {
        //判断参数是否是一个数组
        if(!is_array($arr)) return false;
        //递归出口:数组长度为1,直接返回数组
        $length=count($arr);
        if($length<=1) return $arr;
        //数组元素有多个,则定义两个空数组
        $left=$right=array();
        //使用for循环进行遍历,把第一个元素当做比较的对象
        for($i=1;$i<$length;$i++)
        {
            //判断当前元素的大小
            if($arr[$i]<$arr[0]){
                $left[]=$arr[$i];
            }else{
                $right[]=$arr[$i];
            }
        }
        //递归调用
        $left=quick_sort($left);
        $right=quick_sort($right);
        //将所有的结果合并
        return array_merge($left,array($arr[0]),$right);
    }
    //调用
    echo "<pre>";
    print_r(quick_sort($arr));
    ?>

 4.插入排序

将一组数据分成两组,分别将其称为有序组与待插入组;
每次从待插入组中取出一个元素,与有序组的元素进行比较,并找到合适的位置,将该元素插到有序组当中
就这样,每次插入一个元素,有序组增加,待插入组减少
直到待插入组元素个数为0,当然,插入过程中涉及到了元素的交换

   时间复杂度:O (n^2) ,空间复杂度:O(1)

$arr=[6,1,7,8,12,0,20,-1,3,9,-11,9,8,0,6];
function insertsort(&$arr){
    $len=count($arr);
    for($i=1;$i<$len;$i++){
        $tmp=$arr[$i];
        $j=$i;
        while($j>0 && $tmp<$arr[$j-1]){
            $arr[$j]=$arr[$j-1];//若不是合适位置,有序组元素向后移动
            $j--;

        }
        $arr[$j]=$tmp;//找到合适位置,将元素插入
    }

}
echo "<pre>";
print_r($arr);
insertsort($arr);
print_r($arr);

参考:http://blog.csdn.net/llzk_/article/details/51628574

 5.希尔排序

希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n^2)的第一批算法之一
大致思路:先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素,这样可以快速减少大量的无序情况,
从而减轻后续的工作,被比较的元素之间的距离逐步减少,直到减少为1,这时的排序变成了相邻元素的互换

排序中对于增量序列的选择十分重要,直接影响到希尔排序的性能

时间复杂度 O(N^2)

function shellsort(&$arr){
    $len=count($arr);
    for($gap=intval($len/2);$gap>0;$gap=intval($gap/2)){
        for($i=$gap;$i<$len;$i++){
            $j=$i;
            while($j-$gap>=0 && $arr[$j]<$arr[$j-$gap]){
                //交换法
                $tmp=$arr[$j];
                $arr[$j]=$arr[$j-$gap];
                $arr[$j-$gap]=$tmp;
                $j-=$gap;
            }
        }

    }
}

function shellsort1(&$arr){
    $len=count($arr);
    for($gap=intval($len/2);$gap>0;$gap=intval($gap/2)){
        for($i=$gap;$i<$len;$i++){
            $j=$i;
            $tmp=$arr[$j];
            if($arr[$j]<$arr[$j-$gap]){
                while($j-$gap>=0 && $arr[$j] <$arr[$j-$gap]){
                    //移动
                    $arr[$j]=$arr[$j-$gap];
                    $j-=$gap;
                }
                $arr[$j]=$tmp;
            }
        }
    }
}


$arr=[3,2,-1,0,5,2,1,7,6,4];
echo "<pre>";
print_r($arr);
shellsort1($arr);
print_r($arr);

 可参考:https://www.cnblogs.com/chengxiao/p/6104371.html

6.归并排序

function mergeSort(&$arr,$l,$r){
    if($l>=$r) return;
    $mid=intval(($l+$r)/2);
    mergeSort($arr,$l,$mid);
    mergeSort($arr,$mid+1,$r);
    _merge($arr,$l,$mid,$r);

}

//对$arr[$l,$mid] ,arr[$mid+1,$r] 排序,对于元素少的时候可以采用插入排序优化
function _merge(&$arr,$l,$mid,$r){
    if($l>=$r) return;
    $tmp=[];
    $i=$l;
    $j=$mid+1;

    while($i<=$mid && $j<=$r){
        if($arr[$i] <$arr[$j]){
            $tmp[]=$arr[$i];
            $i++;
        }else{
            $tmp[]=$arr[$j];
            $j++;
        }
    }
    while($i<=$mid){
        $tmp[]=$arr[$i];
        $i++;
    }
    while($j<=$r){
        $tmp[]=$arr[$j];
        $j++;
    }
    foreach($tmp as $k=>$v){
       $arr[$l++]=$v;
    }

}

 

作者:H&K