如何规范的表述时间复杂度的推导过程?
-
循环主题中的变量参与循环条件的判断
此类题应该找出主题语句中与T(n)成正比的循环变量,将之带入条件中进行计算。例如
//1. int i = 1; while (i<n){ i=i*2; } //2. int y = 5; while ((y+1)*(y+1)<n){ y=y+1; }
例1中,i乘以2的次数正式主题语句的执行次数t,因此有 2 t < = n 2^t<=n 2t<=n,取对数后得到 t < = l o g 2 n t<=log_2n t<=log2n,则 T ( n ) = O ( l o g 2 n ) T(n)=O(log_2n) T(n)=O(log2n)
例2中,y加1的次数恰好与T(n)成正比,记t为该程序执行的执行次数并令t=y-5,有y=t+5,(t+5+1)×(t+5+1)<n,得 t < n − 6 t<\sqrt{n}-6 t<n−6,即 T ( n ) = O ( n ) T(n)=O(\sqrt{n}) T(n)=O(n)
-
循环主体中的变量与循环条件无关
此类题可采用数学归纳法或直接累计循环次数。多层循环时从内到外分析,忽略单步语句、条件判断语句,只关注主题语句的执行次数。此类问题又可分为递归程序和非递归程序:
(1)递归程序一般使用公式进行递推,假设代码如图所示:
for(i = n-1 ; i>1 ; i--){ for(j = 1 ; j<i ; j++){ if(A[j]>A[j+1]){ swap(A[j],A[j+1]); } } }
那么这个代码的时间复杂度可以这么计算:
T ( n ) = 1 + T ( n − 1 ) = 1 + 1 + T ( n − 1 ) = . . . = n − 1 + T ( 1 ) T(n)=1+T(n-1)=1+1+T(n-1)=...=n-1+T(1) T(n)=1+T(n−1)=1+1+T(n−1)=...=n−1+T(1)
也就是T(n) = O(n) (2)非递归程序比较简单,可以直接累计次数,例如下面的代码段:
x = 2; while(x<n/2){ x = x*2; }
我们直接计算这个代码一共会执行多少次就行。
求解斐波那契数列通常有两种算法:递归算法和非递归算法,分别分析两种算法的时间复杂度
-
递归算法
#include<stdio.h> #include<windows.h> long long Fib(int N){ if (N<=2) return 1; return Fib(N-1)+Fib(N-2); } int main(){ int i = 0 ; printf("下标为:"); scanf_s("%d",&i); printf("数字为:%d\n",Fib(i)); system("pause"); return 0; }
使用公式进行递推,分析如下:
T ( n ) = 1 + T ( n − 1 ) = 1 + 1 + T ( n − 1 ) = . . . = n − 1 + T ( 1 ) T(n)=1+T(n-1)=1+1+T(n-1)=...=n-1+T(1) T(n)=1+T(n−1)=1+1+T(n−1)=...=n−1+T(1)
即T(n) = O(n) -
非递归算法(迭代算法)
#include<stdio.h> #include<windows.h> long long Fib(ing N){ int First = 1; int Second = 1; int Third = 1; while(N>2){ Third = First + Second; First = Second; Second = Third; N--; } return Third; } int main (){ int i = 0; printf("下标为:"); scanf_s("%d",&i); printf("数字为:%d\n",Fib(i)); system("pause"); return 0; }
在其中,N代表问题的规模,也就是需要求的第N个数,我们发现(N–)这一行代码会执行N-2次,那么就说明T(n)=O(n)。