通过js示例讲解时间复杂度与空间复杂度


Posted in Javascript onAugust 06, 2019

1. 博客背景

今天有同事在检查代码的时候,由于函数写的性能不是很好,被打回去重构了,细思极恐,今天和大家分享一篇用js讲解的时间复杂度和空间复杂度的博客

2. 复杂度的表示方式

之前有看过的,你可能会看到这么一串东西

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

这个叫做大O表示法,其中的T代表的是算法需要执行的总时间

S表示的算法需要的总空间

f(n)表示的是代码执行的总次数

举个例子

function go(n) { 
 var item = 0;   // 这里执行了一次
 for (var i = 0; i < n; i++) {  //这里执行了N次
  for (var j = 0; j < n; j++) {   //这里执行了n*n次
   item = item + i + j;   //这里执行了n*n次
  }
 }
 return item; //这里执行了一次
}

所以说上边这段代码是 1+n+n*n*2+1=2+n+2n²

也就是说 T(n) = O(f(2+n+2n²))

然后之前说了时间复杂度看的是一个代码执行的时间的趋势, 所以说在N,也就是规模比较大的时候,那些常量是起不到决定性的作用的,所以这个时候我们忽略这些常量,这里的例子是一个单段的代码,这里只看最大量级的循环就可以了

所以最后的这个代码的时间复杂度是T(n) = O(n²)

大家可以想想一下数据中平方的曲线图

3. 时间复杂度

3.1 时间复杂度的定义

首先什么是时间复杂度,时间复杂度这个定义如果在之前没有接触过的话,你可能会认为他代表的是一个代码执行的时间,其实不然,算法的时间复杂度就是说一个算法的执行时间根据数据规模增长的一个趋势,并不是说代码执行的具体时间

3.2 几种常见的时间复杂度

最简单的O(n)

for (var i = 0; i < n; i++) { 
sum += i; 
}

通俗易懂,这段代码的执行时间完全由N来控制,所以说T(n) = O(n)

当然还有个更简单的O(1)

function total(n) {

console.log(1)
}

无论怎么样,这段函数不受任何参数影响,代码走一遍就完事,这种的代码用T(n) = O(1) 表示

T(n) = O(n²)

上边的例子已经说了一个了两层循环的那种,在举一个时间复杂度多块代码的情况时间复杂度的计算方式

function go(i) {
 var sum = 0;
 for (var j = 0; j < i; j++) {
  sum += i;
 }
 return sum;
}
function main(n) {
 var res = 0;
 for (var i = 0; i < n; i++) {
  res = res + go(i); // 这里是重点
 }
}

在上边的代码种第二段代码里边调用了第一段代码,所以说在这个代码里边是

go:(1+n)

在main函数里边的时候是(1+n*go)=(1+n+n*n)

所以最后的时间复杂度是T(n) = O(n²)

3.3 多块代码的时间复杂度

上边距离说明的T(n) = O(n²) ,是一个函数在另一个函数里边被调用,这种情况是被把两个函数的时间复杂度相乘。

还有另外一种情况,就是说在一个函数里边有多块代码,但是并没有被相互调用,那么这种情况的时候,我们只需要取复杂度最大的代码块就可以了

比如说

function go(n) {

     for (var i = 0; i < n; i++) {
      for (var j = 0; j < n; j++) {
       console.log(1)
      }
     }


     for (var i = 0; i < n; i++) {
      console.log(2)
     }
    }

上边这块代码中,第一块代码有两层循环,通过上边的例子我们已经得知复杂度是

下边这块代码,是n

那么在这种情况的时候,当N接近无限大的时候N是对n²起不到决定性作用的,所以上边这块代码的时间复杂度就是取最大值的n²

3.4 对数阶和相加情况

var i = 1;
while (i <= n) {
    i = i * 10;
}

在这段代码中,可以看到while里边,作为判断条件的i被每次*10,那么所以说最后循环的次数并不是n次,而是说十分之一n次,所以说这个时候的时间复杂度是10i=n,
i=logn

所以得出结论就是时间复杂度是T(n)=O(logn)

然后还有一种情况就是通过改变的变量去增加循环次数的,同理是增加了时间复杂度

还有一些其他的情况比如时间复杂度相加

function go(m,n) {

 for (var i = 0; i < n; i++) {
  console.log(1)
 }

 for (var i = 0; i < m; i++) {
  console.log(2)
 }

}

请看上边这一段,这段代码里边一个函数里边有两个循环,但是形参有两个,我们现在无法得知n和m到底谁大谁小,所以说这个时候代码的时间复杂度是O(m+n)

4. 空间复杂度

4.1 空间复杂度的定义

上边说了那么一大堆的时间复杂度,相比各位已经比较了解了,就名字来看,时间复杂度看的是代码的执行时间的趋势,那么同理的,空间复杂度就是指的占用内存的趋势

4.2 常见的空间复杂度

空间复杂度没有时间复杂度那么复杂,常见的就那么几种

毕竟我感觉不会有人一直循环着各种花样的声明变量吧。。。

如果有,那么请打死。。。。

  • O(1)
let a = 1;
let b = 1;
let c = 1;
let d = 1;

很简单,O(1)

  • O(n)
let arr =Array(n)

看这句代码,代码中创建了一个n长度的数组,很明显数组的长度根据n来决定,所以说
O(n)

这里需要说明一下,这里没有用循环,是因为只要不是在循环里边不停的声明变量,只改变值的话是不会层架空间复杂度的

  • O(n²)
let arr=[]
for (var i = 0; i < n; i++) {
  arr[i]=i
  for (var j = 0; j < n; j++) {
    arr[i][j]=j
  }
}

怎么样,猛的一看这个代码是不是很刺激,我觉得如果有这种情况的话,一般都会被乱棍打死了。。。

复杂度的优化

再说优化之前我先盗一张图给大家看一下各个复杂度的曲线图,方便大家有一个直观的认识

通过js示例讲解时间复杂度与空间复杂度

举个比较简单的优化的例子

console.time('a')
function go(n) {
   var item = 0;
   for (var i = 1; i <= n; i++) {
    item += i;
   }
   return item;
}
console.timeEnd('a')

console.time('b')
function go2(n) {
 var item = n*(n+1)/2
 return item;
}
console.timeEnd('b')

go(1000)
go2(1000)

大家可以打印一下看一下

希望大家原谅我数学不好,记得之前看到过一个等差数列的例子,想不到其他的性能优化的例子

希望大家看完之后可以了解这些概念,有的时候这个东西真的很重要,找一个曲线比较高的例子

斐波那契,就是从第三项开始依次等于前两项的和

斐波那契定义

function Fibonacci(n) {
  if (n <= 1 ) {
    return n;
  } else {
    return Fibonacci(n - 1) + Fibonacci(n - 2);
  }
}

console.time('b')
Fibonacci(????)
console.timeEnd('b')

有兴趣的可以试试打印一下,看看时间,不过大概50次的时候你得浏览器就应该没有响应了,具体请往上看曲线图。。。。

以上是我对时间复杂度和空间复杂度的一些认识,有不足或者不对的地方,希望指出来

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jQuery 学习6 操纵元素显示效果的函数
Feb 07 Javascript
jquery中ajax调用json数据的使用说明
Mar 17 Javascript
Jquery 类网页微信二维码图块滚动效果具体实现
Oct 14 Javascript
node.js中的fs.closeSync方法使用说明
Dec 17 Javascript
jQuery实现动画效果circle实例
Aug 06 Javascript
理解Javascript的call、apply
Dec 16 Javascript
AngularJS变量及过滤器Filter用法分析
Nov 22 Javascript
vuejs响应用户事件(如点击事件)
Mar 14 Javascript
JS实现AES加密并与PHP互通的方法分析
Apr 19 Javascript
Vuex之理解state的用法实例
Apr 19 Javascript
使用vue的transition完成滑动过渡的示例代码
Jun 25 Javascript
vue 的 solt 子组件过滤过程解析
Sep 07 Javascript
Flutter 超实用简单菜单弹出框 PopupMenuButton功能
Aug 06 #Javascript
JS中如何轻松遍历对象属性的方式总结
Aug 06 #Javascript
VUE组件中的 Drawer 抽屉实现代码
Aug 06 #Javascript
浅入深出Vue之自动化路由
Aug 06 #Javascript
解决vue单页面修改样式无法覆盖问题
Aug 05 #Javascript
微信小程序3种位置API的使用方法详解
Aug 05 #Javascript
微信小程序 高德地图路线规划实现过程详解
Aug 05 #Javascript
You might like
PHP错误抑制符(@)导致引用传参失败Bug的分析
2011/05/02 PHP
判断Keep-Alive模式的HTTP请求的结束的实现代码
2011/08/06 PHP
PHP中的str_repeat函数在JavaScript中的实现
2013/09/16 PHP
PHP中file_exists函数不支持中文名的解决方法
2014/07/26 PHP
php验证session无效的解决方法
2014/11/04 PHP
PHP图片处理之图片旋转和图片翻转实例
2014/11/19 PHP
php+html5实现无刷新图片上传教程
2016/01/22 PHP
redis查看连接数及php模拟并发创建redis连接的方法
2016/12/15 PHP
PHP解析url并得到url参数方法总结
2018/10/11 PHP
JavaScript中Object和Function的关系小结
2009/09/26 Javascript
简单的两种Extjs formpanel加载数据的方式
2013/11/09 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
2014/03/06 Javascript
JavaScript实现带标题的图片轮播特效
2015/05/20 Javascript
JavaScript实现把数字转换成中文
2015/06/29 Javascript
jQuery中(function($){})(jQuery)详解
2015/07/15 Javascript
原生js获取元素样式的简单方法
2016/08/06 Javascript
JSONP基础知识详解
2017/03/19 Javascript
js实现关闭网页出现是否离开提示
2017/12/07 Javascript
微信小程序实现图片上传放大预览删除代码
2020/06/28 Javascript
微信小程序之裁剪图片成圆形的实现代码
2018/10/11 Javascript
Electron-vue脚手架改造vue项目的方法
2018/10/22 Javascript
vue2路由方式--嵌套路由实现方法分析
2020/03/06 Javascript
基于hashlib模块--加密(详解)
2017/06/21 Python
Python中序列的修改、散列与切片详解
2017/08/27 Python
3分钟看懂Python后端必须知道的Django的信号机制
2020/07/26 Python
浅谈Python描述数据结构之KMP篇
2020/09/06 Python
Python约瑟夫生者死者小游戏实例讲解
2021/01/04 Python
GAP美国官网:美国休闲时尚品牌
2016/08/26 全球购物
英国女装网上商店:I Saw It First
2018/10/18 全球购物
给女儿的表扬信
2014/01/18 职场文书
医生进修自我鉴定
2014/01/19 职场文书
保险公司年会主持词
2014/03/22 职场文书
舞蹈教育学专业求职信
2014/06/29 职场文书
2014审计局领导班子民主生活会对照检查材料思想汇报
2014/09/20 职场文书
nginx简单配置多个server的方法
2021/03/31 Servers
Nginx设置HTTPS的方法步骤 443证书配置方法
2022/03/21 Servers