时间复杂度
当电脑运行下面这段代码的时候,执行任何一条语句都需要花费时间(为了方便讨论,这里我们把每一条语句的执行时间都看做是一样的,记为一个时间单元)
这个程序有这么几个地方消耗了时间:
① 蓝色框的两条语句,花费2个时间单元
② 黑色框的一条语句,花费n+1个时间单元
③ 红色框的两条语句,花费2*n个时间单元
那么一共花费了3n+3个时间单元,可以看出,程序消耗的时间和n成线性关系
- 用T(n)表示这个程序运行了多长时间,那么这个程序运行的时间就可以写成T(n)=3n+3。其中的n被我们称为问题的规模,其实就是处理的问题的大小
我们常常会对这个函数进行简化,使得它既简单又不失函数的主要特性
所以一般只关心随着问题规模n趋于无穷时函数中对函数结果影响最大的项,也就是最高次项
举个栗子:
- T(n)=n+1 忽略常数项 :T(n)~n
- T(n)=n+n2 忽略低阶项: T(n)~n2
- T(n)=3n 忽略最高阶的系数: T(n)~n
至于判断哪个是高阶项,哪个是低阶项,只需记住下面的大小关系就行了,到时按照这个进行忽略(忽略相对较小的)
简化后的式子被称为这个程序算法的时间复杂度,记做O(f(n)),f(n)就是简化后的式子,比如说刚开始讨论的T(n)=3n+3,简化后T(n)~f(n)=n,那我们记为O(n)
时间复杂度可以表示某个算法的运行时间的趋势,大致地度量算法效率的好坏
时间复杂度的计算
计算时间复杂度大O的方法
一、得出运行时间的函数
二、对函数进行简化
- 用常数1来取代运行时间中所有加法常数
- 修改后的函数中,只保留最高阶项
- 如果最高阶项存在 且系数不为1,则忽略这个项的系数(即令其系数为1)
举个栗子:
int n = 0;
n = n + 6;
printf(n);
T(n)=3(三条语句1+1+1),对这个函数进行简化,用常数1取代常数3,然后取代后的函数没有最高阶项,那么这个算法的时间复杂度就是O(1).
O(1)也被称为常数阶
如果每次都要把时间函数算出来,挺麻烦的,可以耍耍小聪明,一般来说,最内层执行次数最多的语句就决定了整个算法的趋势
for(int i = 0; i < n; i++)
printf("哈");
这个内层打印语句需要循环n次,随着问题规模n的增加会呈线性增加,可以判定其时间复杂度为O(n)
按照这个方法就很容易得出下面这个嵌套的两层for循环的时间复杂度为O(n2)
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cout << "平方阶" << endl;
}
}
有一个很神奇的函数——对数函数,它随着自变量的增大,因变量增长的很慢
下面这段代码的复杂度就为对数级别O(logn)
int sum = 1;
while(sum < n) {
sum = sum * 2;
}
和之前的分析方法一样,我们着重看执行次数最多的内层代码语句
sum = sum * 2;
每循环一次,sum就给自身乘以2,乘了多少次就跳出循环了呢(大于等于n)?不知道,就设为x吧,那么 2x=n,解出 x=log2n,这说明随着n的增大,最消耗时间的内层语句是呈对数变化的。
感谢阅读~
- 本文参考于:算法分析神器—时间复杂度