排序算法 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.程序一定要运行 2.程序运行还依赖外部硬件
- 事前估算法
通过分析某个算法的时间复杂度来判断算法的算法优劣
时间频度
- 一个算法花费的时间与算法中语句的执行次数成正比,那个算法中语句执行的次数越多,它花费的时间就越多,一个算法中的语句执行次数称为语句频度或者
时间频度,记为 T(n)
eg:
//计算1-100之和
$i = 1;
$max = 100;
$total = 0;
for ($i = 0; $i < $max; $i++) {
$total += $i;
}
上述算法的时间频度就是: T(n) = n+1
- 时间频度的估算
- 忽略常数项
T(n) = 2n+20
T(n) = 2n
可以忽略常数项 20
- 忽略低次项
T(n) = 2n² + 3n + 10
T(n) = 2n²
可以忽略低次项 3n 和常数项 10
- 忽略系数
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 代替运行时间中的所有加法常数
2n²+7n+1
-
修改后的运行次数函数中,只保留最高阶项
2n²
-
去除最高阶项的系数
n²
常见的时间复杂度
- 常数阶 1
$i = 1;
$j = 10;
$i++;
++$j;
echo $i + $j;
- 对数阶 ㏒2N
//N = a² a的2次方等于N,a>0 a != 1; 叫做以2为底的a的对数 ==》 ㏒₂a
$i = 1;
$n = 1024;
while($i < $n) {
$i = $i * 2
}
- 线性阶 n
$n = 10;
for($i = 0; $i < $n; $i++) {
echo $i;
}
- 线性对数阶 n㏒₂n
$n = 10;
$m = 1024;
$j = 1;
for($i = 0; $i < $n; $i++) {
while($j < $m) {
$j = $i * 2;
}
}
- 平方阶 n²
<?php
for ($i = 0; $i < 100; $i++) {
for ($j = 0; $j < 100; $j++) {
echo $i * $j;
}
}
?>
- 立方阶 n³
<?php
for ($i = 0; $i < 100; $i++) {
for ($j = 0; $j < 100; $j++) {
for ($m = 0; $m < 100; $m++) {
echo $i * $j * $m;
}
}
}
?>
-
k次方阶 n*
-
指数阶 2^n
-
算法时间复杂度的大小关系,常数阶 < 对数阶 < 线性阶 < 线性对数阶 < 平方阶 < 立方阶 < k次方阶 < 指数阶
-
算法时间复杂度之平均时间复杂度和最坏时间复杂度
算法 复杂度
冒泡 O(n²)
交换 O(n²)
插入 O(n²)
基数 O(n²)
希尔 O(㏒₂2)
快速 O(㏒₂2)
归并 O(㏒₂2)
堆 O(㏒₂2)
排序实现
- 冒泡排序 Bubbling
- 定义一个随机的待排序的 int 类型的数组
$arr = [1, 20, -3, -5, 6];
- 冒泡排序是将待排序的数组进行双重
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));