时间复杂度分析

不足或错误之处指出请指正。


目录

1 为什么要分析复杂度

2 大O表示法

3 时间复杂度分析原则

  • 3.1 只关注循环次数最多的一段代码
  • 3.2 加法原则
  • 3.3 乘法原则

4 常见的几种时间复杂度

  • 4.1 O(1)
  • 4.2 O(logn)、O(nlogn)
  • 4.3 O(m+n)、O(m*n)

正文

1 为什么要分析复杂度

事后统计法

将代码跑一遍,通过统计、监控得到执行时间和占用空间,这种方法有很大的局限性。

1.1 测试结果非常依赖测试环境

最近有很多同学问我怎么选一款电脑,我首先会问什么需求(电脑用来干什么?是编程开发、还是后期制作、还是游戏或者是追剧?)。对于后期制作方面,选i7当然比i5好,i7的渲染能力是实测强于i5的。对于游戏,i7和i5性能发挥差不多,所以买i5处理器划算。当然还需要考虑散热以及预算等问题。。等等。对于编程测试环境的硬件不同会对测试结果有很大影响。

1.2 测试结果受数据规模的影响很大

对于同一种排序算法,待排序数据的有序度不一样,排序的执行时间就会有很大的差别。如果测试数据很小,测试结果可能无法真实的反应算法的性能。

2 大O复杂度表示法

/*求1,2,3,……,n的累加和*/
int add(int n)
{
    int sum = 0;
    int i = 1;
    for(; i<=n; i++)
    {
        sum = sum + i;
    }
    return sum;
}

假设每行代码执行时间一样为unit_time,T(n)为这段代码的执行时间。

T(n) = (2n+2)*unit_time

int fun(int n)
{
    int sum = 0;
    int i = 1;
    int j = 1;
    for(; i<=n; i++)
    {
        for(; j<=n; j++)
        {
            sum = sum + i*j;
        }
    }
    return sum;
}

上面这段代码的执行时间为:T(n) = (2n^2 + 2n +3)*unit_time

所有代码的执行时间T(n)与每行代码的执行次数n成正比

所有就有:T(n) = O(f(n))

大O时间复杂度实际上并不表示具体代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,也称为渐进时间复杂度。当n很大时,公式中的低阶、常量、系数并不左右增长趋势,所以可以忽略。

故,以上两个例子的时间复杂度记为:`T(n)=O(n) T(n) = O(n^2)

3 时间复杂度分析原则

3.1 只关注循环次数最多的一段代码

大O只表示一种变化趋势,所以在分析一个算法、一段代码的时候,只关注循环执行次数最多的那一段就可以了。

int fun1(int n)
{
    int sum = 0;
    int i = 1;
    for( ; i<=n; i++)
    {
        sum = sum + i;
    }
    return sum;
}

fun1的总时间复杂度为O(n)

3.2 加法原则

总复杂度等于量级最大的那段代码的时间复杂度。

int fun2(int n)
{
    int sum1 = 0;
    int p = 1;
    for( ; p<100; p++)
    {
        sum1 = sum1 + p;
    }
    
    int sum2 = 0;
    int q = 1;
    for( ; q<n; q++)
    {
        sum2 = sum2 + q;
    }
    
    int sum3 = 0;
    int i = 1;
    int j = 1;
    for( ; i<=n; i++)
    {
        j = 1;
        for( ; j<=n; j++)
        {
            sum3 = sum3 + i*j;
        }
    }
    
    return sum1+sum2+sum3;
}

第一段执行了100次,和n的规模无关。

第二段代码时间复杂度为O(n)。

第三段代码时间复杂度为O(n^2)。

综合这三段代码的时间复杂度,取最大量级,所以这段代码的时间复杂度为O(n^2)。

3.3 乘法原则

嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。

int fun1(int n)
{
    int ret = 0;
    int i = 1;
    for( ; i<n; i++)
    {
        ret = ret + fun2(i);
    }
    return ret;
}

int fun2(int n)
{
    int sum = 0;
    int i = 1;
    for( ; i<n; i++)
    {
        sum = sum + i;
    }
    return sum;
}

这段代码的时间复杂度为:O(n^2)

4 常见的几种时间复杂度

指数阶:O(2^n) 和 阶乘阶:O(n!)成为非多项式量级。

通常把时间复杂度为非多项式量级的算法问题成为NP问题(Non-Deterministic Polynomial,非确定多项式)。当数据规模n越来越大时,NP问题算法的执行时间会几句增加,非常低效。

4.1 O(1)
int i = 1;
int j = 2;
int sum = i + j;
4.2 O(logn)、O(nlogn)
/* 1 */
int i = 1;
while( i<=n )
{
    i = i*2;
}
/* 2 */
int i = 1;
while( i<=n )
{
    i = i*3;
}

1 代码的复杂度为log2(n)

2 代码的复杂度为log3(n)

对数是可以相互转换的:log3(n) = log3(2) * log2(n)所以:O(log3(n)) = O(C * log2(n)),其中C是一个常量,我们忽略系数C。

故将对数阶时间复杂度均表示为:log(n)

如果一段代码的时间复杂度为log(n),执行了n遍,时间复杂度就为nlogn(n)

4.3 O(m+n)、O(m*n)
int fun1(int m, int n)
{
    int sum1 = 0;
    int i = 1;
    for( ; i<m; i++)
    {
        sum1 = sum1 + i;
    }
    
    int sum2 = 0;
    int j = 1;
    for( ; j<n; j++)
    {
        sum2 = sum2 + j
    }
    
    return sum1+sum2;
}

这段代码的时间复杂度为:O(m+n)

针对这种情况,时间复杂度和m、n均有关,加法原则就不正确了,乘法原则依然正确。


本文完,不足之处,请指正。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值