排序算法 sort algorithm之冒泡排序

排序算法 sort algorithm

  • 排序算法的介绍分类

排序是将一组数据,依次指定的顺序进行排列的过程

  • 分类

  • 内部排序 将数据一次性加载到内存中进行排序

1.1 插入排序

1.1.1 直接插入排序

1.1.2 希尔排序

1.2 选择排序

1.2.1 简单选择排序

1.2.2 堆排序

1.3 交换排序

1.3.1 冒泡排序

1.3.2 快速排序

1.4 归并排序

1.5 基数排序

  • 外部排序 数据量过来,无法一次加载到内存中,需要借助外部存储区

  • 算法的时间复杂度

  1. 事后统计法

注意:1.程序一定要运行 2.程序运行还依赖外部硬件

  1. 事前估算法

通过分析某个算法的时间复杂度来判断算法的算法优劣

时间频度
  • 一个算法花费的时间与算法中语句的执行次数成正比,那个算法中语句执行的次数越多,它花费的时间就越多,一个算法中的语句执行次数称为语句频度或者
    时间频度,记为 T(n)

eg:

//计算1-100之和

$i = 1;

$max = 100;

$total = 0;

for ($i = 0; $i < $max; $i++) {
    $total += $i;
}

上述算法的时间频度就是: T(n) = n+1

  • 时间频度的估算
  1. 忽略常数项

T(n) = 2n+20 T(n) = 2n 可以忽略常数项 20

  1. 忽略低次项

T(n) = 2n² + 3n + 10 T(n) = 2n² 可以忽略低次项 3n 和常数项 10

  1. 忽略系数

T(n) = 3n² + 2n T(n) = 5n²+7n 可以忽略前面的系数 3 和 5

  • 时间复杂度

一般情况下,算法中的基本操作语句的重复执行的次数是问题规模n的某个函数,用f(n)表示,若某个辅助函数f(n),使得当趋于无穷大时,
T(n)/f(n) 的极限值为不等于0的一个常数,则称为f(n)时T(n)的同数量级函数,记作T(n) = O(f(n)),称O(f(n))为算法的渐进时间复杂度,
简称时间复杂度。

  • T(n)不同,但时间复杂度可能相同,2n²+7n+6 3n²+2n+2,它们的T(n)不同,但是时间复杂度相同,都为O(n²)

  • 计算时间复杂度的方法:

  1. 用常数 1 代替运行时间中的所有加法常数 2n²+7n+1

  2. 修改后的运行次数函数中,只保留最高阶项 2n²

  3. 去除最高阶项的系数

常见的时间复杂度
  1. 常数阶 1
$i = 1;
$j = 10;
$i++;
++$j;
echo $i + $j;
  1. 对数阶 ㏒2N
//N = a²  a的2次方等于N,a>0 a != 1; 叫做以2为底的a的对数 ==》 ㏒₂a

$i = 1;
$n = 1024;

while($i < $n) {
    $i = $i * 2
}
  1. 线性阶 n
$n = 10;
for($i = 0; $i < $n; $i++) {
    echo $i;
}
  1. 线性对数阶 n㏒₂n
$n = 10;
$m = 1024;
$j = 1;

for($i = 0; $i < $n; $i++) {
    while($j < $m) {
        $j = $i * 2;
    }
}
  1. 平方阶
<?php
for ($i = 0; $i < 100; $i++) {
    for ($j = 0; $j < 100; $j++) {
        echo $i * $j;
    }
}
?>
  1. 立方阶
<?php
for ($i = 0; $i < 100; $i++) {
    for ($j = 0; $j < 100; $j++) {
        for ($m = 0; $m < 100; $m++) {
            echo $i * $j * $m;
        }
    }
}
?>
  1. k次方阶 n*

  2. 指数阶 2^n

  • 算法时间复杂度的大小关系,常数阶 < 对数阶 < 线性阶 < 线性对数阶 < 平方阶 < 立方阶 < k次方阶 < 指数阶

  • 算法时间复杂度之平均时间复杂度和最坏时间复杂度

算法 复杂度

冒泡 O(n²)

交换 O(n²)

插入 O(n²)

基数 O(n²)

希尔 O(㏒₂2)

快速 O(㏒₂2)

归并 O(㏒₂2)

堆 O(㏒₂2)

排序实现
  1. 定义一个随机的待排序的 int 类型的数组
$arr = [1, 20, -3, -5, 6];
  1. 冒泡排序是将待排序的数组进行双重for循环,相邻的两个数组做比较,如果是从小到大的排序,那么就是两两比较,把前面的大数和后面的小数交换位置,大致如
    下:ps 示意图如下
$arr = [1, 20, -3, -5, 6];
//第一轮比较
$arr = [1, 20, -3, -5, 6];  //1 20     => $arr = [1, 20, -3, -5, 6];
$arr = [1, 20, -3, -5, 6];  //1 , -3  => $arr = [-3, 20, 1, -5, 6]; 
$arr = [-3, 20, 1, -5, 6];  //-3, -5   => $arr = [-5, 20, 1, -3, 6];
$arr = [-5, 20, 1, -3, 6];  //-5, 6    => $arr = [-5, 20, 1, -3, 6];
//第一论结束得到的结果:
$arr = [-5, 20, 1, -3, 6];

//第二轮比较
$arr = [-5, 20, 1, -3, 6]; //20, 1  => $arr = [-5, 1, 20, -3, 6]; 
$arr = [-5, 1, 20, -3, 6]; // 1, -3  => $arr = [-5, -3, 20, 1, 6];
$arr = [-5, -3, 20, 1, 6]; // -3, 6   => $arr = [-5, -3, 20, 1, 6];

//第二轮结束得到结果
$arr = [-5, -3, 20, 1, 6];

//第三轮开始
$arr = [-5, -3, 20, 1, 6]; // 20, 1  => $arr = [-5, -3, 1, 20, 6]; 3
$arr = [-5, -3, 1, 20, 6]; // 1, 6   => $arr = [-5, -3, 1, 20, 6];

//第三轮结束,得到结果
[-5, -3, 1, 20, 6];

//第四轮开始
$arr = [-5, -3, 1, 20, 6]; // 20,6 => $arr = [-5, -3, 1, 6, 20];

第四轮结束得到结果:
$arr = [-5, -3, 1, 6, 20];

以上呢就是相当于拿两组一个一个比较,就是有n个数,那么它就要比较除了它自身的(n-1)次,这个就最容易理解的


下面是一个改良版的,稍微复杂一点点。

  • 得到一个无序的数组,求得数组元素的个数

  • 第一轮循环

//第一次比较是拿数组的第一个元素和数组的第二个元素作比较
$data =  [1, 20, -3, -5, 6];

$data =  [1, 20, -3, -5, 6];
$count = count($data);
$temp = 0;
for ($j = 0; $j < $count-1; $j++) {
    if ($data[$j] > $data[$j+1]) {
        $temp = $data[$j];
        $data[$j] = $data[$j+1];
        $data[$j+1] = $temp;
    }
}

//第一次: 1 和 20 比较,判断前面元素和后面元素谁打,后面大交换位置,前面大不交换位置

//第二次: 20 和 -3 比较, 20 > -3 交换位置 得到 1 -3 20 -5 6

//第三次:20 和 -5 比较, 20 > -5 交换位置 得到 1 -3 -5 20 6

//第四次:20 和 6 比较, 20 > 6 交换位置 得到 1 -3 -5 6 20

第一轮循环结束之后,得到的排序结果就是 [1, -3, -5, 6, 20],第一轮循环结束之后,我们得到了一个最大的元素,并且经过交换位置,把它移动到了
最后一个位置,那么再经过第二次循环的时候,我们就可以少比较一个,也就是每轮循环结束以后,我们就可以少比较一个

  • 第二轮循环
$data =  [1, 20, -3, -5, 6];

$data =  [1, 20, -3, -5, 6];
$count = count($data);
$temp = 0;
//不比较最后一个最大的元素了
for ($j = 0; $j < $count-1-1; $j++) {
    if ($data[$j] > $data[$j+1]) {
        $temp = $data[$j];
        $data[$j] = $data[$j+1];
        $data[$j+1] = $temp;
    }
}

//第一次:1 和 -3 比较 ,1 > -3 交换位置 -3 1 -5 6 20
//第二次:1 和 -5 比较 ,1 > -5 交换位置 -3 -5 1 6 20
//第三次:1 和 6 比较 ,1 < 6 不交换位置 -3 -5 1 6 20

第二轮结束以后得到的结果就是 [-3, -5, 1, 6, 20]

依次类推,每次比较完成后减去一个相对最大值,最后得到一个排序完成的数组。

完整代码如下:

<?php
/**
 * Notes:
 * File name:${fILE_NAME}
 * Create by: Jay.Li
 * Created on: 2019/10/18 0018 9:22
 */

class Sort
{
    public static function sortArray(array $data)
    {
        if (!is_array($data)) {
            return ['message' => '非数组'];
        }

        $count = count($data);

        if ($count <= 0) {
            return ['message' => '数组长度小于等于0'];
        }

        if ($count === 1) {
            return $data;
        }

        return static::sortArray2($data, $count);
    }

    public static function sortArray1(array $data, int $count):array
    {
        for ($i = 0; $i < $count; $i++) {
            $flag = false;
            $temp = 0;
            for ($j = $i+1; $j < $count; $j++) {
                if ($data[$i] > $data[$j]) {
                    $temp = $data[$i];
                    $data[$i] = $data[$j];
                    $data[$j] = $temp;
                    $flag = true;
                }
            }

            if (!$flag) {
                break;
            }
        }

        return $data;
    }

    public static function sortArray2(array $data, int $count):array
    {
        $temp = 0;
        for ($i = 0; $i < $count; $i++) {
            $flag = false;
            for ($j = 0; $j < $count-1-$i; $j++) {
                if ($data[$j] > $data[$j+1]) {
                    $temp = $data[$j];
                    $data[$j] = $data[$j+1];
                    $data[$j+1] = $temp;
                    $flag = true;
                }
            }

            if (!$flag) {
                break;
            }
        }
        return $data;

    }
}
$data =  [1, 20, -3, -5, 6];

var_dump(Sort::sortArray($data));

github交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值