众所周知,计算机在执行算法时都会消耗一定的时间,但是不同的算法消耗的时间肯定是不同的。这就和我们做数学题一样,简单的用时少,复杂的用时多。为了描述一个算法运行消耗的时间,我们便定义了时间复杂度。
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数,记作T(n)=O(f(n)),它称为算法的渐进时间复杂度,简称时间复杂度。
说这个可能有点难以理解,所以我们直接上图。
时间复杂度有5个层级:O(1) < O(logn) O(n) < O(nlogn) < O(n²)
那如何判断一个算法的时间复杂度呢?最简单有效的方法便是列出每一次执行基本操作的次数,找出规律,这样的话,时间复杂度便一目了然了。
来看个例子:
for(int i=1;i<=n;i*=2){
count ++;
}
这是一个最基本的for循环。
找到基本运算:i = i*2;
第一次执行:i = 1;
第二次执行:i = 2;
第三次执行:i = 4;
第四次执行:i = 8;
.......
第t次执行: i = 2^t;
判断逻辑:i<= n;
时间复杂度:2^t <= n 即:t <= log2n。
再来看一个复杂一点的:
int func(int n){
int i =0 ,sum = 0;
while(sum < n){
sum += ++i;
}
return i;
}
找到基本运算:sum += ++i;
第一次执行:sum = 1
第二次执行:sum = 1+2
第三次执行:sum = 1+2+3
第四次执行:sum = 1+2+3+4
第五次执行:sum = 1+2+3+4+5
......
第t次执行:sum = 1+2+3+4+...+t
判断逻辑:sum < n
时间复杂度:1+2+3+4+...+t < n 即: t + t(t-1)/2 < n ----> O(t^1/2)。
再来看一个双层循环嵌套:
int n=8,count=0;
for(int i=1;i<=n;i*=2){
for(int j=1;j<=i;j++){
count++;
}
}
第一层for循环的执行次数:log2n
第二层第一次执行:1
第二层第二次执行:2
第二层第三次执行:4
第二层第四次执行:8
......
第二层第t次执行:2^t
t的最大值为log2n ----> 2^log2n
总的执行次数: 1 + 2 +4 + 8 +...+ 2^log2n = 2n -1
时间复杂度:O(n)。