常见算法

1. 算法的概念;

  • 解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
  • 一个问题可以有多种算法,每种算法都有不同的效率。比如:1 + 2 + 3 + 4 + … + n 的值是多少,可以一个数字一个数字加,也可以用公式 (1 + n) * n / 2
  • 一个算法具有五个特征:有穷性(能够计算完,不能无限计算下去,会变成死循环)、确切性(每一步都要有意义)、输入项(1 加到 100)、输出项(最终要给出一个结果)、可行性(算法要可以执行,每一步都是正确的)

2. 时间复杂度和空间复杂度;

算法评定:
算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要是从 时间复杂度空间复杂度 来考虑。
时间复杂度:
执行算法所需要的计算工作量(时间消耗的效率)。一般来说,计算机算法是问题规模 n 的函数 f(n),算法的时间复杂度也因此记做 T(n)=O(f(n))
问题的规模 n 越大,算法执行的时间的增长率与 f(n) 的增长率正相关,称作渐进时间复杂度(Asymptotic Time Complexity)
时间复杂度的计算方式:
得出算法的计算次数公式。下图的计算次数是 n 次,时间复杂度就是 O(n),时间复杂度就是计算次数。
在这里插入图片描述
用常数 1 来取代所有时间中的所有加法常数。上图的计算,如果 n 是常数 3 ,时间复杂度不能写 O(3),而是用 O(1) 表示。只要是常数,都用 1 替代。
在修改后的运行次数函数中,只保留最高阶项。看上图的计算,如果最后计算的次数是 n 2 + n + 1,那最终的表达式是 O(n 2),只拿最高阶。
如果最高阶存在且不是 1,则去除与这个项相乘的常数。看上图的计算,如果计算次数是 2n 2 + 3n + 1,那最终的表达式是 O(n 2)。
总结:也就是说时间复杂度是一个根据规模去拿到表达式的高阶项里面最高的一个值,其它全部忽略。拿到的是一个粗略的值,不是一个精确的值
关于时间复杂度的例子:
常数阶 O(1):如下函数,不管 n 是多少,函数只运行 3 次,时间复杂度是 O(3),记录成 O(1)
在这里插入图片描述
线性阶 O(n):1 + 2 + 3 + 4 + … + n
平(立)方阶:O(n 2) / O(n 3)
在这里插入图片描述
特殊平方阶:O(n 2 / 2 + n / 2) -> O(n 2)
在这里插入图片描述
对数阶:O(log2n)
在这里插入图片描述 在这里插入图片描述
总结时间复杂度相关:
常见的时间复杂度:常数阶、线性阶、平(立)方阶、对数阶、nlog2n阶、指数阶
时间复杂度的效率:O(1) > O(log2n) > O(n) > O(nlog2n) > O(n 2) > O(n 3) > O(2 n) > O(n!) > O(n n)
时间复杂度的其它概念:
最坏情况:最坏情况时的运行时间,一种保证。如果没有特别说明,说的时间复杂度即为最坏情况的时间复杂度
平均情况:期望的运行时间
空间复杂度:
算法需要消耗的内存空间,记做 S(n) = O(f(n))
包括程序代码所占用的空间,输入数据所占用的空间和辅助变量所占用的空间这三个方面
计算和表示方法和时间复杂度类似,一般用复杂度的渐进性来表示
空间复杂度的计算方式:
有时用空间换取时间
冒泡排序的元素交换,空间复杂度 O(1): 冒泡排序就是两两进行比较,中间会拿一个临时变量来存储交换的值,这个临时变量会占用一个内存。不管内容多大,临时变量就只会有一个。是一个常数,不会因为 n 的增大而增大。

3. 常见排序算法:

冒泡排序直接插入排序选择排序快速排序、希尔排序、堆排序、归并排序

冒泡排序:两两相邻的数进行比较,如果反序就交换,否则不交换
时间复杂度:最坏 O(n 2),平均 O(n 2)
空间复杂度:O(1)
在这里插入图片描述
// 实例:
<?php
$arr = [1, 3, 2, 4, 6, 5];
echo '<pre>';

for($i = 0, $c = count($arr); $i < $c; $i++){
	for($j = $i+1; $j < $c; $j++){
		if($arr[$i] > $arr[$j]){
			$temp = $arr[$i];
			$arr[$i] = $arr[$j];
			$arr[$j] = $temp;
			// 打印当前步骤的排序结果
			print_r($arr);
		}
	}
}
// 最终排序结果
echo '<hr>';
print_r($arr);
exit;
直接插入排序:每次从无序表中取出一个元素,把它插入到有序表的合适位置,使有序表仍然有序(参考:摸牌理牌)
时间复杂度:最差 O(n 2),平均 O(n 2)
空间复杂度:O(1)
// 实例:
<?php
$arr = [1, 3, 2, 4, 6, 5];

echo '<pre>';
// 数组中的第一个元素作为一个已经存在的有序表
for($i = 1; $i < count($arr); $i++){
	$temp = $arr[$i];
	for($j = $i-1; $j >= 0 && $arr[$j] > $temp; $j--){
		$arr[$j+1] = $arr[$j];	// 记录后移
	}
	$arr[$j+1] = $temp;	// 插入到正确的位置
}
echo '<hr>';
print_r($arr);
exit;
选择排序:每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完
时间复杂度:最差 O(n 2),平均 O(n 2)
空间复杂度:O(1)
<?php
$arr = [1, 3, 2, 4, 6, 5];

echo '<pre>';
for($i = 0, $c = count($arr); $i < $c; $i++){
	// 记录第 $i 个元素后的所有元素最小值下标
	$min = $i;
	for($j = $i+1; $j < $c; $j++){
		if($arr[$j] < $arr[$min]){
			$min = $j;
		}
	}
	$temp = $arr[$i];
    $arr[$i] = $arr[$min];
    $arr[$min] = $temp;
}
echo '<hr>';
print_R($arr);
exit;

快速排序:通过一趟排序将套排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后再按照此方法对这两部分数据分别进行快速排序,整个排序过程可以递归完成。
时间复杂度:最差 O(n 2),平均 O(n*log2n)
空间复杂度:最差 O(n),平均 O(log2n)
<?php
$arr = [1, 3, 2, 4, 6, 5];

$left = 0;
$right = count($arr) - 1;

function quick_sort(&$arr, $left, $right){
	if($left >= $right)	return;
	
	$temp = $arr[$left];
	$i = $left;
    $j = $right;
	
	while($i < $j){
		while($i < $j && $arr[$j] >= $temp){
			$j--;
		}
		while($i < $j && $arr[$i] <= $temp){
			$i++;
		}
		$itemp = $arr[$i];
        $arr[$i] = $arr[$j];
        $arr[$j] = $itemp;	
	}
	if ($left < $i){
        $arr[$left] = $arr[$i];
        $arr[$i] = $temp;
    }
    quick_sort($arr, $left, $i-1);
    quick_sort($arr, $i+1, $right);
}

quick_sort($arr, $left, $right);
echo '<pre>';
print_r($arr);
exit;
希尔排序:把待排序的数据根据增量分成几个子序列,对子序列进行插入排序,直到增量为1,直接进行插入排序;增量的排序,一般是数组的长度的一半,再变为原来增量的一半,直到增量为1
时间复杂度:最差 O(n 2),平均 O(n*log2n)
空间复杂度:O(1)
堆排序:把待排序的元素按照大小在二叉树位置上排列,排序好的元素要满足:父节点的元素要大于等于子节点;这个过程叫做堆化过程,如果根节点存放的是最大的数,则叫做大根堆,如果是最小,就叫小根堆,可以把根节点拿出来,然后再堆化,循环到最后一个节点。
时间复杂度:最差 O(n log2n),平均 O(nlog2n)
空间复杂度:O(1)
归并排序:将两个(或两个以上)有序表合成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。
时间复杂度:最差 O(n log2n),平均 O(nlog2n)
空间复杂度:O(n)
  • 总结:快速排序、归并排序的理想时间复杂度都是 O(n*log2n),但是快速排序的时间复杂度并不稳定,最坏情况下复杂度为 O(n2) ,所以最理想的的算法还是归并排序

4. 常见查找算法。

二分查找:从数组的中间元素开始,如果中间元素正好是要查找的元素,搜索结束。如果某一个特定元素大于或者小于中间元素,则在数组大于或者小于中间元素的那一半中查找,而且跟开始一样从中间开始比较,如果某一步骤数组为空,代表找不到
时间复杂度:最差 O(log2n),平均 O(log2n))
空间复杂度:迭代 O(1),递归 O(log2n)
顺序查找:按一定的顺序检查数组中的每一个元素,直到找到所要寻找的特定值为止。
时间复杂度:最差 O(n),平均 O(n)
空间复杂度:O(1)
  • 总结:二分查找法的时间复杂度是最差 O(log2n),顺序查找的时间复杂度最差为 O(n),所以二分查找法更快,但是递归情况下,二分查找更消耗内容,时间复杂度为 O(log2n)

同类题:1. 简述时间复杂度和空间复杂度的感念

  • 时间复杂度是描述算法时间消耗的计算量,空间复杂度就是内存的计算量
  1. 对无序数组排序,最优的时间复杂度是什么,用 PHP 给出一个实际的例子(如了解,给出算法名称),该算法的空间复杂度是什么?
  • 快速排序,也可以归并。
  1. 一个有序数组中,查询待定的 item 是否存在的最优算法是什么?时间复杂度是什么?
  • 二分查找法。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页