JavaScript时间和空间复杂度解析

首先我们要知道为什么需要分析这些复杂度?

任何一个程序最重要是准确性,即要确保程序能正常运行,实现预期功能。
但是,任何一个有价值的程序除了确保能正常运行,还要确保尽量短的运行时间和尽量少的运行空间,使程序正确高效执行得到预期效果。这就涉及时间复杂度分析和(空间复杂度分析),通过分析程序算法的时间复杂度可以找出运行时间尽量短的算法。
对于一些数据处理比较少的简单程序,不同算法使程序运行时间不同,但由于数据处理量少,这种运行时间的差别可以忽略。但是在实际应用中,很多程序往往涉及相当大量的数据处理,这就会导致实现同一个功能的程序,用不同算法,运行时间差别很大。有些算法可能只要几秒,有些算法却要几天才能得到结果。这时候,时间复杂度的分析就显得必要

时间复杂度和空间复杂度分别表示什么?
T(n) = O(f(n)); //时间复杂度
S(n) = O(f(n)); //空间复杂度

它们都叫做大O表示法,
T代表算法执行总时长,
S代表算法占用总空间,
f(n)代表执行的总次数。

时间复杂度:

举个例子:

function total(n) { // 1
      var sum = 0; // 2
      for (var i = 0; i < n; i++) { // 3
        sum += i; // 4
      } //5 
    } //6

上面的代码,在执行第二行的时执行了一次,暂且记做为1,第二行代码的迭代器,由于不知晓n的长度,所以暂且记做为n,第四行代码嵌套在迭代器中,所以也记做为n,所以他们的执行次数为 (2n+1)

再举个例子

 function total(n) { // 1
      var sum = 0; // 2
      for (var i = 0; i < n; i++) { // 3 
        for (var j = 0; j < n; j++) { // 4
          sum = sum + i + j; // 5
        }
      }
    }

按照之前的逻辑,第二行需要执行一次,第三行需要执行n次,第四行呢?大家都知道在迭代器中嵌套是互乘的关系,所以是n²,第五行的常亮嵌套在第四行中,所以它也是n²,总共计算所得(1+n+2n²)

所以由此得出,代码的总执行时间T(n)与每行代码的执行次数成正比
T(n) = O(f(n))
T(n)代表代码的执行时间,n代表数据规模的大小,f(n)代表代码执行次数综合,O代表代码的执行时间与f(n)成正比

所以上述的两个例子的结果(2n+1)和(1+n+2n²)就是大O时间复杂表示法,它并不是代码的真正执行时间,而是标识代码随着数据规模增长的变化趋势,简称为时间复杂度。
并且在n比较大的时候,常亮是不会起到决定性的作用,所以只保留一个最大量级即可,所以对上述两个结果简化所得(n)和(n²)。

如何快速分析一段代码的时间复杂度?
我们只需要关注循环次数最多的那一段代码即可

function total(n) { // 1
      var sum = 0; // 2
      for (var i = 0; i < n; i++) { // 3
        sum += i; // 4
      } //5 
    } //6

很明显,在第三和第四行代码执行次数是最多的,分别执行了n次,忽略常数项,所以这段代码的时间复杂度为O(n)

集中常见的时间复杂度分析:

类型大O表示法术语说明
15O(1)常数阶最低的时间复杂度,无论输入数据增大多少倍,耗时永远不变
3lognO(logn)对数阶以2为底数的log,数据增大n倍,耗时更加logn倍,比如数据量增大256倍时,耗时只增大8倍,因为它术语二分查找法,每次取一半来进行排除,所以256个数据就只需要查找八次就可以找到目标
3n+5O(n)线性阶去除常量,只剩下n,数据量增大几倍,耗时也增大几倍
5n^2+3n+1O(n^2)平方阶n的平方,计算的复杂度随着数据量的平方根增长
6n^3+4n+2O(n^3)立方阶n的立方,计算的复杂度随着数据量的立方根增长
2^n+1O(2^n)指数阶左边为底数,右上角为指数,结果为幂,随着数据量的指数增长
n!+3O(n!)阶乘阶n! = n*(n-1),随着数据量的阶乘增长

空间复杂度

空间复杂度的推算和时间复杂度类似,唯一不同的是,空间复杂度表示算法的存储空间和数据规模之间的关系

举个例子:

function initArr(n) {
      var arr = [];
      for (var i = 0; i < n; i++) {
        arr[i] = i;
      }
    }

忽略掉常量,那么它的空间复杂度就是O(n);

如何优化程序,降低时间和空间复杂度?

再举个例子:

function total(n) {
      var sum = 0;
      for (var i = 1; i < n; i++) {
        sum += i;
      }
      return sum;
    }

很明显,它的复杂度为O(n),我们尝试把它降维O(1),常数阶

function total(n) {
      var sum = n*(n+1)/2
      return sum;
    }

但更高层的延伸还可分为低中高的复杂度等级:

function find(n, x, arr) {
        let ind = -1;
        for (let i = 0; i < n; i++) {
          if (arr[i] === x){
             ind = i;
            break;
           } 
        }
        return ind;
      }

其中的if判断是一个位置的结果,因为你并不知道x这个值是在第一位还是在最后一位,所以还分为低中高的三个复杂度等级

总结

复杂度也叫渐进复杂度,包含了时间和空间复杂度,一个标识执行的时长,一个表示占用的内存,它们都用来分析算法执行效率与数据规模之前的增长关系,越高阶的复杂度算法,执行效率越低

参考文章:
https://www.jb51.net/article/167003.htm 时间和空间复杂度的浅析
https://zhuanlan.zhihu.com/p/54267154 时间和空间复杂度的等级划分
https://juejin.im/post/5c2a1d9d6fb9a04a0f654581 时间和空间复杂度的讲解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值