复杂度分析(一) 分析算法的执行效率

13 篇文章 0 订阅
2 篇文章 0 订阅

 

      为什么要进行复杂度分析?

      有人会想,平时一个功能都会有相应的性能测试,跑一遍不就好了吗,为什么还要去分析呢?

      首先,不同的设备配置如i3和i7处理器,同一个功能跑一遍,耗时肯定是不一样的,所以测试环境会影响判断。

      再者,数据量的大小也会影响对功能性能的判断,极端的比如同步10000条数据和同步10000w条数据,性能波动也会影响判断。

      在这种情况下,使用复杂度分析,至少能粗略计算不同方案的执行效率,进行对比和选择。

     大O复杂度

     算法的执行效率,容易理解点说,就是在相同数量情况下,代码块执行的时间。比如:

int cl(int n){
    int m = 0 ;
    for(int i = 0 ; i < n ; i ++){
       m = m + 1;
    }
    return m;
}

这段代码按系统的角度进行了读取 、计算 、 赋值。假设每行执行的时间是一个单元u,第二行为u,第3和4行分别执行了n*u次

那么所有代码执行总时间 u + 2*n*u,那么这里得出了一个公式就是,所有代码的执行时间T(n)和每行代码的执行次数n成正比。

T(n) = O(f(n)) 

那么T(n)表示代码执行时间,n表示数据规模,f(n)表示每行代码执行次数总和。O表示T(n)和f(n)成正比。

那么上边的例子可以:

    T(n) = O(1 + 2n)

这种就是大O复杂度表示。

需要搞清楚一点:大O时间复杂度实际上并不表示具体执行时间,它只表示代码执行时间随数据规模变化的一个趋势,简称时间复杂度。

当n非常大,那么公式中的低阶、常量、系数并不能改变这个变化的趋势,所有上边例子的时间复杂度又可以表示成:

    T(n) = O(n)

再来一个:

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

可以看到,第二行为1 , 第三行为n ,第四行为 n * n ,第五行为 n * n

T(n) = O(1 + n + 2 * n^2)

进化 : T(n) = O(n^2)

时间复杂度几种分析 

只关注循环次数多的

前边讲过,通常忽略掉低阶、常量、系数,只关注最大阶的量级即可,所以能造成循环次数多的那一段即可反应问题。

int cl(int n){
    int m = 0 ;
    for(int i = 0 ; i < n ; i ++){
       m = m + 1;
    }
    return m;
}

比如第二行执行1,第三行、四行为n,那么时间复杂度为n。

加法法则

其实和上边的差不多,即总的复杂度为量级最大的那个。

 

int cl(int n){
    int m = 0 ;
    for(int i = 0 ; i < 1000 ; i ++){
       m = m + 1;
    }
    for(int i = 0 ; i < n ; i ++){
       m = m + 1;
    }
    for(int i = 0 ; i < 2n ; i ++){
       m = m + 1;
    }
    return m;
}

上边可以看到 一个是1000,一个是n,一个是2n,那么 最大次数 为   2n,去掉系数,最大量级还是n。

T(n) = O(1000 + n + 2n)

进化 : T(n) = O(n)

乘法法则

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

int cl(int n){
    int sum = 0 ;
    for(int i = 0 ; i < n ; i ++){
       sum = sum + incal(n);    
    }
    return sum;
}

int incal(int n){
    int tmp = 0;
    for(int i = 0 ; i < n ; i ++){
       tmp = tmp + 1;
       
    }
    return tmp;
}



T(n) = Tcal(n) * Tincal(n) = O(n*n) = O(n^2)

几种常见时间复杂表示

常量阶 O(1)
对数阶 O(logn)
线性阶 O(n)
线性对数阶 O(nlogn)
k方阶 O(n^k)

指数阶 O(2^n)
阶乘阶 O(n!)

对上边的可分为 多项式量阶 和 非多项式量阶(指数阶 O(2^n)   阶乘阶 O(n!))

非多项式的成为NP (No - Deterministic polynomial),数据量越大,执行时间急剧上升。

int a = 0 ;
int b = 1;
int c = a * b;

复杂度: O(1)

对于对数阶


int i = 1;
while(i <= n){
  i = i * 2;
}

第三行执行了多少次呢?

从代码中看到,变量从1开始,每次循环乘以2 ,那么可以表示 2^n = x,那么x = log2n所以时间复杂度为 log2n


int i = 1;
while(i <= n){
  i = i * 5;
}

上边的时间复杂度为log5n

基于前边的理论 采用大O标记复杂度时,忽略系数,所以,上面的复杂度都是O(logn)

 

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

上边的复杂度为 O(m + n)  ,为什么不符合加法法则呢,因为m 和 n 都是不确定量,这种情况不能简单的采用加法法则去忽略任何一个。

 

空间发杂度分析

时间复杂度分析的是算法的执行时间与数据规模之间的增长关系,而空间复杂度指的是算法的存储空间与数据规模之间的增长关系。

void ts(int n){
   int i = 0 ;
   int [] a = new int[n];
   for (;i < n ; i ++){
     a[i] = i*i;
   }
}

第二行 i赋值 申请了一个存储变量空间,但是它是常量阶的,第三行 申请了n个存储变量空间,n阶。所以这个空间复杂度为n

常见的空间复杂度

O(1)
O(n)
O(n^2)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值