• 复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?


    1、大 O 复杂度表示法

     1 int cal(int n) {
     2    int sum = 0;
     3    int i = 1;
     4    int j = 1;
     5    for (; i <= n; ++i) {
     6      j = 1;
     7      for (; j <= n; ++j) {
     8        sum = sum +  i * j;
     9      }
    10    }
    11  }

    第 2、3、4 行代码,每行都需要 1 个 unit_time 的执行时间,第 5、6 行代码循环执行了 n 遍,需要 2n * unit_time 的执行时间,第 7、8 行代码循环执行了 n2遍,所以需要 2n2* unit_time 的执行时间。所以,整段代码总的执行时间 T(n) = (2n2+2n+3)*unit_time。用大 O 表示时间复杂度T(n) = O(n2)。

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

    公式: 

    含义:T(n) 表示代码执行的时间;n 表示数据规模的大小;f(n) 表示每行代码执行的次数总和。公式中的 O,表示代码的执行时间 T(n) 与 f(n) 表达式成正比。 

    定义:大 O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。当 n 很大时,你可以把它想象成 10000、100000。而公式中的低阶、常量、系数三部分并不左右增长趋势,所以都可以忽略。我们只需要记录一个最大量级就可以了,如果用大 O 表示法表示这段代码的时间复杂度,就可以记为: T(n) = O(n2)。

    2、复杂度分析法则

    1)单段代码看高频:比如循环。
    2)多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度。
    3)嵌套代码求乘积:比如递归、多重循环等
    4)多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加。

    3、几种常见时间复杂度实例分析

    多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。包括,O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n2)(平方阶)、O(n3)(立方阶)

    非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。包括,O(2n)(指数阶)、O(n!)(阶乘阶)

    案例:

          1、O(1)  常数阶:一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)。

    1  int i = 8;
    2  int j = 6;
    3  int sum = i + j;

        2、O(logn)  对数阶:

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

    第三行代码是循环执行次数最多的,只要能计算出这行代码被执行了多少次,就能知道整段代码的时间复杂度。从代码中可以看出,变量 i 的值从 1 开始取,每循环一次就乘以 2。当大于 n 时,循环结束。还记得我们高中学过的等比数列吗?实际上,变量 i 的取值就是一个等比数列。如果我把它一个一个列出来,就应该是这个样子的:

    所以,我们只要知道 x 值是多少,就知道这行代码执行的次数了。通过 2x=n 求出x=log2n,所以,这段代码的时间复杂度就是 O(log2n)。但是当n无穷大的时候,忽略对数的“底”,统一表示为 O(logn)。

       3、O(nlogn)    线性对数阶:  如果一段代码的时间复杂度是 O(logn),我们循环执行 n 遍,时间复杂度就是 O(nlogn) 了。比如,归并排序、快速排序的时间复杂度都是 O(nlogn)。

     4、O(m+n)、O(m*n)   :代码的复杂度由两个数据的规模来决定。如下面的代码时间复杂度就是 O(m+n)。

     1 int cal(int m, int n) {
     2   int sum_1 = 0;
     3   int i = 1;
     4   for (; i < m; ++i) {
     5     sum_1 = sum_1 + i;
     6   }
     7 
     8   int sum_2 = 0;
     9   int j = 1;
    10   for (; j < n; ++j) {
    11     sum_2 = sum_2 + j;
    12   }
    13 
    14   return sum_1 + sum_2;
    15 }
  • 相关阅读:
    远程连接Ubuntu中的MySQL
    以API 配置的方式来配置你的 Dubbo 应用
    jdk1.8:stream流式分组groupby
    springboot如何通过apollo动态去注册dubbo服务
    JDK动态代理[3]WeakCache缓存的实现机制
    Linq 交集、并集等集合理论学习
    Build my first Blazor app
    关于
    MySql数据库优化维度
    面霸篇:Java 集合容器大满贯(卷二)
  • 原文地址:https://www.cnblogs.com/gshao/p/12323335.html
Copyright © 2020-2023  润新知