一,算法的时间复杂度
算法的时间复杂度反应了程序执行时间随输入的规模增长而增长的量级,在很大程度上反映出算法的优劣与否
1,时间复杂度
时间频度:一个算法中语句执行的次数称为语句频度或者时间频度记为T(n)
时间复杂度:在刚才提到的时间频度中,n称为问题的规模,当n不断变化的时间,时间频度T(n) 也会不断地变化,但有时候我们想知道它变化时呈现什么规律,为此引入时间复杂度的概念
一般情况下,算法中的基本操作重复的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大的时候,T(n)/f(n)的极限值为不等于0的常数,则称F(n)是T(n)的同量级函数,记为T(n)=O(F(n)),称O(F(n))为算法的渐进时间复杂度,简称为时间复杂度
T(n)=O(f(n))表示存在一个常数C,使得当n趋于正无穷的时候总有T(n) < C*f(n),简单来说,就是T(n)在趋于正无穷的时最大也就跟f(n)差不对大,也就是说当n趋于正无穷的时候T(n)的上届是C*f(n)。
常见的是时间复杂度:常数介O(1),对数阶O(log2n),线性阶O(n),线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),......, k次方阶O(nk),指数阶O(2n)。随着问题规模的不断增大,上述时间复杂度不断地增大,执行效率不断降低
常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
2,求解算法时间复杂度的具体步骤:
(1)找出算法中的基本语句(算法中执行最多的那条语句是基本语句,通常是最内层循环的循环体)
(2)计算基本语句的执行次数和量级(只需要保证基本语句执行次数的数量级,这意味着只要保证基本语句执行次数的函数的最高次幂正确即可,可以忽略所有最低次幂和最高次幂的系数,简化算法分析,主要集中在增长率上)
(3)用大O表示算法的时间性能(将基本语句执行次数的数量级放入大O中)
如果算法中包含嵌套的循环,则基本语句通常是内层嵌套的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加:
for (i=1; i<=n; i++)
x++;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
x++;
第一个for循环的时间复杂度为Ο(n),第二个for循环的时间复杂度为Ο(n2),则整个算法的时间复杂度为Ο(n+n2)=Ο(n2)
Ο(1)表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,其时间复杂度就是Ο(1)
其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)称为多项式时间,而Ο(2n)和Ο(n!)称为指数时间。
3,常见时间复杂度示例说明:
(1)O(1)
$a = $b; $b = $c; $c = $a;
以上三条单据频度都是1,该程序段的执行时间是一个与问题规模n无关的常数,算法的时间复杂度Wie常数阶,记做T(n)=O(1)
算法的执行时间不随问题规模n增长而增长,即使算法中有n条语句,其执行时间也不过是一个较大的常数该类算法时间复杂度是O(1)。
(2)O(n2)
$num = 0;
for ($i=0; $i < $n; $i++) {
for ($i=0; $i < $n; $i++) {
$num++;
}
}
(3)O(n)
$a = 0;
$b = 1;
for ($i=1;$i<=n;$i++)
{
$s = $a + $b;
$b = $a;
$a = $s;
}
(4)O(log2n)
$i = 1;
while ($i <= $n)
$i = $i * 2;
语句1的频度是1, 设语句2的频度是f(n), 则:2^f(n)<=n;f(n)<=log2n 取最大值f(n)=log2n T(n)=O(log2n )
(5)O(n3)
for($i=0;$i<$n;$i++)
{
for($j=0;$j<$i;$j++)
{
for($k=0;$k<$j;$k++)
$x=$x+2;
}
}
4,常用算法的时间复杂度和空间复杂度
排序法 | 平均时间 | 最差情形 | 稳定度 | 额外空间 | 备注 |
冒泡 | O(n²) | O(n²) | 稳定 | O(1) | n小时较好 |
交换 | O(n²) | O(n²) | 不稳定 | O(1) | n小时较好 |
选择 | O(n²) | O(n²) | 不稳定 | O(1) | n小时较好 |
插入 | O(n²) | O(n²) | 稳定 | O(1) | 大部分已排序时候好 |
基数 | O(logRB) | O(logRB) | 稳定 | O(n) | B是真数(0-9)R是基数(个十百) |
Shell | O(nlogn) | O(Nⁿ)1<n<2 | 不稳定 | O(1) | s是所选分组 |
快速 | O(nlogn) | O(n2) | 不稳定 | O(nlogn) | n大时较好 |
归并 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n大时较好 |
堆 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |
二,算法的空间复杂度
一个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。算法在运行过程中临时占用的存储空间随算法的不同而异,有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地\"进行的,是节省存储的算法。
当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为0(10g2n);当一个算法的空I司复杂度与n成线性比例关系时,可表示为0(n).若形参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若形参为引用方式,则也只需要为其分配存储一个地址的空间,用它来存储对应实参变量的地址,以便由系统自动引用实参变量。