时间复杂度计算
理解算法的方式:
大家都知道,衡量一个程序好坏有两个标准。
- 占用时间
- 占用空间
那么时间复杂度如何才能在写代码时就可以进行推算呢?下面就进行举例说明
int main()
{
int a = 2;//1
int b = 3;//2
return 0;//3
}
int main()
{
int a = 2,b = 3;
return 0;
}
很明显,这个代码执行了三次,那么它的时间复杂度是3吗?如果将声明改成了第二个代码情况,完全一样,难道就变成了2吗?非常明显,这是不可能的。在实际的项目中会有几千几万行这样的代码,不可能去一一计算。我们在代码的执行时间和执行行数中有一个公式T(n) = O( f(n) ),说明行数和时间是成正比的关系
- n代表输入数据数量
- f(n)代表代码执行总次数
- T(n)代表代码执行总时间
- O代表f(n)和T(n)成正比
回到第一个例子,那么时间复杂度就是O(3)或者O(2)了吗?答案不是这样的。一般情况下我们把此类的时间复杂度认为是O(1),只要在函数中没有声明循环、递归等反人类操作。无论声明多少行,时间复杂度总是为O(1)。
例2:
int main()
{
int n = 10;
for (int i = 0; i < n; i++)
{
cout << "算法真的烦!" << endl;
}
return 0;
}
在这个程序中,添加了循环操作。我们先进行计算一下执行次数。
- int n = 10 1
- int i = 0 1
- i < n n
- i++ n
- cout ... n
- return 0; 1
总共执行了3n+3次,在3n面前3就显得很渺小,所以3可以忽略不计,n和3n只是一个系数的关系。只要n都是一次方,那么我们把这类的时间复杂度都认为是O(n).
例3:双层嵌套
int main()
{
int n = 10;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
cout << "嵌套循环!" << endl;
}
}
return 0;
}
里循环会执行n,外循环也会循环n次。那么执行的次数可以认为是n的平方,那么时间复杂度可以认为是O(n²)。
那么循环是不是都是这样的呢?显然不是,例4将会带你看到不一样的时间复杂度。
例4:
int main()
{
int n = 10;
for (int i = 1; i < n; i*= 2)
{
cout << "嵌套循环!" << endl;
}
return 0;
}
这里的循环条件变成了i = i * 2;那么每次都是倍数上涨,i<n的判断条件就不会再是n次了,而是n/2次。所以时间复杂度也就变成了O(log2N),也可以简写为O(logn)。
以下是一些常见的时间复杂度
- O(1) 常数复杂度
- O(logn) 对数复杂度
- O(n) 线性时间复杂度
- O(nlogn) 线性对数复杂度
- O(n²) 平方
- O(n³) 立方
- O(2n) 指数,卡死了
- O(n!) 阶乘,死机