1、算法时间复杂度的定义
系统执行次数就为时间。
算法的时间量度 | 语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。 |
记作 | T(n)= O(f(n)) |
表示 | 随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同 |
2、确定时间复杂度的方法
这里主要有三个方法
- 用常数1期待运行时间的所有加法常数
- 保留最高项
- 去除最高项的系数
示例1:常数阶 O(1)
int n = 0, s = 0;
n = 100;
s = (1+n)*n/2;
printf("这是示例1\n");
printf("常数阶\n");
printf("时间复杂度为O(1)\n");
解析:时间复杂度为O(1),因为T(n)是关于问题规模n的函数,而这里只有s = (1+n)*n/2这句代码关于n,所以为O(1)。简单来说算法的执行时间不随问题规模n的增加而增。
示例2:线性阶 O(n)
int i = 1,n = 100,sum = 0;
for(i = 0; i < n ;i++)
{
sum = sum + i;
}
printf("这是示例2\n");
printf("线性阶,这种非嵌套的循环\n");
printf("时间复杂度为O(n)\n");
解析:这里有个for循环,随着N的增大,时间也增大,所以这里为O(n)。
示例3:平方阶 O(n2)
int i = 1,j = 0,n = 100;
for(i = 0; i < n ;i++)
{
for(j = 0; j < n; j++){
printf("%d\n",i);
}
}
printf("这是示例3\n");
printf("平方阶,这种是嵌套的循环\n");
printf("时间复杂度为O(n^2)\n");
解析:这里时间复杂度为O(n2),是因为这里有个for循环里面只嵌套了一个,如果最里面的for循环再有嵌套for循环,那么时间复杂度就为O(n^3)
这里再拿出一个示例,复杂度也为O(n2)
int i = 1,j = 0,n = 100;
for(i = 0; i < n ;i++)
{
//这里区别在于j = i
for(j = i; j < n; j++)
{
printf("%d\n",i);
}
}
解析:算法执行总次数为n+(n-1)+(n-2)+……1
那么我们优化一下为 n(n+1)/2,再化简为n2/2+n/2。根据我们上面的方法,保留最高项(此时为n2/2),再去除最高项的系数,此时就为n2。
示例4:对数阶 O(logn)
int i = 1,n = 100;
while(i < n){
i = i*2;
}
printf("这是示例4\n");
printf("对数阶\n");
printf("时间复杂度为O(logn)\n");
解析:每次 i * 2 之后比较n,大于就退出。这里假设我们有X个2相乘后大于n。算出X就是时间复杂度!
因为 2^x = n
所以有 log(2)n = x 所以时间复杂度O( logn )
3、函数调用的时间复杂度分析
上面讲解了常数阶、线性阶、平方阶和对数阶,那么现在就是将上面几种,通过函数的方式组合起来。
组合示例1
int i,j;
for(i = 0; i < n; i++){
function(i);
}
void function(count){
printf("%d",count);
}
解析:for循环的是时间复杂度为O(n),函数function的复杂度为O(1),所以整体的时间复杂度为O(n)
组合示例2
n++; //执行1次
function(n); //执行n次
for(i = 0; i < n; i++){ //执行n^2
function(i);
}
for(i = 0; i < n ;i++){ //执行n^2
for(j = i ; j < n ;j++){
printf("%d",j);
}
}
void function(count){
for(int i = 0; i<count ;i++){
printf("%d",count);
}
}
解析:总的执行了1+n+n2+n2根据文章第2节的三个方法,最终得到O(n2)
4、常见的时间复杂度
例子 | 时间复杂度 | 名称 |
---|---|---|
5256525 | O(1) | 常数阶 |
3n+4 | O(n) | 线性阶 |
3n2+5n+91 | O(n2) | 平方阶 |
9log(2)n+4 | O(logn) | 对数阶 |
2n+3nlog(2)n+14 | O(nlogn) | nlogn阶 |
n3+5n2+6 | O(n3) | 立方阶 |
2^n | O(2^n) | 指数阶 |
这里简单用关系总结
O(nn) > O(n!) > O(2n) > O(n3) > O(n2) > O(nlogn) > O(n) > O(logn) > O(1)