时间复杂度
时间复杂度是一个算法运行时所消耗的时间,而算法的运行时间是与语句的执行次数成正比的
一个算法的运行时间与其他因素也有关系,比如一台低端处理器设备和一台高端处理器设备同时运行,运行时间是不一样的
但是由于一个算法在不去运行的情况下,不太容易算出它精确得运行时间,所以只能去估算它在运行时所消耗的时间
例1
int func1(int n)
{
int count = 0;
for (int j = 0; j < n; j++)
{
for (int i = 0; i < n; i++)
{
count++;
}
}
for(int k=0;k<2*n;k++)
{
count++;
}
printf("%d\n", count);
}
如何计算这个函数的时间复杂度
首先第一个外层循环会执行n次,嵌套的内层循环也会执行n次,所以这里它们的总执行次数是n*n也就是n^2
第三个循环的执行次数是2*n次
这个函数的总执行次数是n^2+2*n
这个执行次数还是比较精确了,现在只需要大概的执行次数就可以了
在这里就要用到大O表示法对它进行估算
现在假设n等于10,代入公式
10^2+2*10,结果是120
估算值只需要知道这里面对结果影响最大的执行次数,那就是n^2
影响最大也可以理解为量级,如:100,1000,10000...,在量级与量级之间的值可以不计算因为它对结果的影响小,就比如这个函数中的2*n
所以这个函数的时间复杂度用大O表示法表示是O(n^2)
例2
int func2(int n,int j)
{
int count = 0;
for (int i; i < n; i++)
{
count++;
}
for (int k = 0; k < j; k++)
{
count++;
}
printf("%d\n", count);
}
再来计算这个函数的时间复杂度
由于无法确认 n,j 的大小所以它的时间复杂度就是O(n+j)
如果n>j那就是O(n),反之就是O(j),相等就取任意一个
例3
int func3()
{
int count = 0;
for (int i = 0; i < 100; i++)
{
count++;
}
printf("%d\n", count);
}
这个函数,乍一看可能会认为它的时间复杂度是O(100)
其实不是,在大O表示法中任何常数项,哪怕它再大它的时间也依然是O(1),1表示常数
例4
int func4(int n)
{
int count = 0;
for (int i = 0; i < 2 * n; i++)
{
count++;
}
printf("%d\n", count);
}
这个函数中时间复杂度也不是O(2*n),因为当n无穷大时,这个系数 2 没有多大影响
总结
大O表示法用来计算算法最坏情况下的结果
使用大O表示法时只保留最大项
用1代替所有运行时间为常数的结果
如果有最高阶项且不是1,就去除与这项相乘的系数
例5
int func5(int n)
{
if (n == 0)
{
return 1;
}
return func5(n - 1) * n;
}
这个递归实现阶乘的函数时间复杂度如何计算
它是这样递归的,n-1,n-2,n-3,...2, 1,0每一层都是上一层的n-1
也就是由最开始的n一直减到0结束递归
所以它的时间复杂度就是O(n)
例6
int Fib(int n)
{
if (n < 3)
{
return 1;
}
return Fib(n - 1) + Fib(n - 2);
}
Fib(3)
Fib(2)
Fib(1)
计算斐波拉契数列的时间复杂度
由此可见斐波那契数列递归是一个等比数列
计算它的执行次数需要计算等比数列和
可以使用错位相减法
n^0+n^1+n^2+......+n^(n-3)+n^(n-2)
乘公比2,然后错位
n^1+n^2+n^3+......+n^(n-2)+n^(n-1)
结果:2^(N-1)-N^0
大O表示法O(2^N)