今天有同事在检查代码的时候,因为函数写的性能不是很好,被打回去重构了,细思极恐,今天和你们分享一篇用js讲解的时间复杂度和空间复杂度的博客算法
以前有看过的,你可能会看到这么一串东西数组
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²)) spa
而后以前说了时间复杂度看的是一个代码执行的时间的趋势, 因此说在N,也就是规模比较大的时候,那些常量是起不到决定性的做用的,因此这个时候咱们忽略这些常量,这里的例子是一个单段的代码,这里只看最大量级的循环就能够了code
因此最后的这个代码的时间复杂度是T(n) = O(n²) blog
你们能够想一想一下数据中平方的曲线图
首先什么是时间复杂度,时间复杂度这个定义若是在以前没有接触过的话,你可能会认为他表明的是一个代码执行的时间,其实否则,算法的时间复杂度就是说一个算法的执行时间根据数据规模增加的一个趋势,并非说代码执行的具体时间
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) 表示
上边的例子已经说了一个了两层循环的那种,在举一个时间复杂度多块代码的状况时间复杂度的计算方式
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²)
上边距离说明的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²起不到决定性做用的,因此上边这块代码的时间复杂度就是取最大值的n²
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)
上边说了那么一大堆的时间复杂度,相比各位已经比较了解了,就名字来看,时间复杂度看的是代码的执行时间的趋势,那么同理的,空间复杂度就是指的占用内存的趋势
空间复杂度没有时间复杂度那么复杂,常见的就那么几种
毕竟我感受不会有人一直循环着各类花样的声明变量吧。。。
若是有,那么请打死。。。。
let a = 1; let b = 1; let c = 1; let d = 1;
很简单,O(1)
let arr =Array(n)
看这句代码,代码中建立了一个n长度的数组,很明显数组的长度根据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 } }
怎么样,猛的一看这个代码是否是很刺激,我以为若是有这种状况的话,通常都会被乱棍打死了。。。
再说优化以前我先盗一张图给你们看一下各个复杂度的曲线图,方便你们有一个直观的认识
举个比较简单的优化的例子
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次的时候你得浏览器就应该没有响应了,具体请往上看曲线图。。。。
以上是我对时间复杂度和空间复杂度的一些认识,有不足或者不对的地方,但愿指出来
o(* ̄▽ ̄*)ブ