时间复杂度
- 算法的时间复杂度反映了程序执行时间随输入规模增长而增长的量级,在很大程度上能很好地反映出算法的优劣与否;
- 算法执行时间需要依据该算法编制的程序在计算机上执行运行时消耗的时间来度量,度量方法有两种。事后统计方法和事前分析估算方法,因为事后统计方法更多的依赖计算机的硬件,软件等环境元素,有时容易掩盖算法本身的优劣。因此常常采用事前分析估算的方法。
- 一个算法是由控制结构(顺序、分支、循环)和原操作(固有数据类型的操作)构成的,而算法时间取决于两者的综合效率。
- 一个算法花费的时间与算法中语句的执行次数成正比,执行次数越多,花费的时间就越多。一个算法中的执行次数称为语句频度或时间频度。记为 T(n)。
- 在时间频度中,n 称为问题的规模,当 n 不断变化时,它所呈现出来的规律,我们称之为时间复杂度。
- 在各种算法中,若算法中的语句执行次数为一个常数,则时间复杂度 O(1);同时,若不同算法的时间频度不一样,但他们的时间复杂度却可能是一样的;eg:T(n) = n2+2n+4 与 T(n) = 4n2+n+8,他们的时间频度显然不一样,但他们的时间复杂度却是一样的,均为 O(n2),时间复杂度只关注最高数量级,且与之系数也没有关系。
- 求解算法时间复杂度步骤:
(1)找出算法中的基本语句;
算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
(2)计算基本语句的执行次数的数量级
只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。
(3)用大 O 记号表示算法的时间性能
将基本语句执行次数的数量级放入大 O 记号中。
如果算法中包含嵌套得到循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加。
常见时间复杂度量级:常数阶 O(1)、对数阶 O(logN)、线性阶 O(n)、线性对数阶 O(nlogN)、平方阶 O(n2)、立方阶 O(n3)、K 次方阶 O(nk)、指数阶 O(2n).
(1)O(1)
Temp = i; i = j; j = temp;
以上三条单个语句的频度均为 1,该程序段的执行时间是一个与问题规模 n 无关的常数。算法时间复杂度为常数阶 O(1)。
注: 如果算法的执行时间不随着问题 n 的增加而增长,即使有千万条语句,共执行时间也不是一个较大的常数。
(2)O(logN)
int i = 1;
while(i < n){
i = i * 2;
}
每次 i 乘以 2,当 i >= n 结束:x = log2n
时间复杂度为 O(logN).
(3)O(n)
for(i = 1; i <= n; i++){
j = i;
j++;
}
执行 n 次。
(4)O(nlogN)
for(m = 1; m < n; m++){
i = 1;
while(i < n){
i = i * 2;
}
}
第一重循环:执行 n 次
第二重循环:执行 logN 次
n O(logN) = O(nlogN)
(5)O(n2)
for(i = 1; i <= n; i++){
for(j = 1; j <= n; j++){
k = i;
k ++;
}
}
第一重循环:执行 n 次
第二重循环:执行 n 次
空间复杂度
- 空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度;
- 一个算法在计算机上占用的内存包括:程序代码所占用的空间,输入输出数括所占用的空间,辅助变量所占用的空间这三个方面,程序代码所占用的空间取决于算法本身的长短,输入输出数据占用的空间取决于要解决的问题,是通过参数表调用函数传递而来,只有辅助变量是算法运行过程中临时占用的存储空间,与空间复杂度相关;
- 通常来说,只要算法不涉及到动态分配空间,以及递归、栈所需的空间,空间复杂度为 O(1);
- 对于一个算法,其时间复杂度和空间复杂度往往是相互影响的。当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能占用较多的存储空间;反之,求一个较多的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。另外,算法的所有性能之间都存在着或多或少的相互影响。因此,当设计一个算法时,要综合考虑算法的各项性能,算法的使用频率,算法处理的数据量的大小,算法描述语言的特性,算法运行的机器系统环境等各方面元素,才能够设计出比较好的算法。
递归二分法:时间复杂度为 O(logN),空间复杂度为 O(logN)。
(1)O(1)空间复杂度
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
(2)O(n)空间复杂度
int num[10000];//n = 10000
for(i = 1; i <= n; i++){
j = i;
j++;
}
如果算法执行所需的临时时间不随着某个变量 n 的大小变化,即此算法空间复杂度为一个常量,可表示为 O(1)。