什么是递归?
所谓的递归就是在函数体内调用本函数。使用递归函数一定要有结束的条件,否则就会进入死循环。关于递归有两个经典的案列,比如阶乘、斐波那契数列
下面以斐波那契数列数列为例:
斐波那契数列数列:1 1 2 3 5 8 13 21 34.……
fib(1) = 1 fib(2) = 1 fib(n) = fib(n-1) + fib(n-2)
递归实现
function fib(n) {
if(n === 1 || n ===2) return 1
return fib(n) = fib(n-1) + fib(n-2)
}
递归的缺点
在递归执行的时候,会调用一个又一个的函数,每次调用函数的时候都会压入调用栈,直到得到一个返回值,才会一级一级的出栈,比如:同事A让同事B帮忙解决一个问题,B又找同事C帮忙,如果C能够解决问题告诉B,B得到答案(出栈),B再告诉A,A得到答案(出栈),未解决问题之前,A和B都压入了调用栈,如果调用的函数太多,而栈的内存有限,就会出现栈溢出
递归的另一个缺点就是重复计算,以上面斐波那契的代码为例,如果传入参数5,那么计算过程是这样的:
上面就可以看出,fib(3)计算了两次,如果递归计算大数字,就会出现很多函数重复计算,导致性能非常差
递归的优化
不用递归实现
function fn(n) {
let last1 = 1, last2 = 1, temp
for(let i = 3; i <= n; i++) {
temp = last1 + last2
last1 = last2
last2 = temp
}
return last2
}
空间换效率
function fib(n) {
let arr = [0, 1, 1]
let(i=3; i<=n; i++) {
arr[i] = arr[i-1] + arr[i-2]
}
return arr[n]
}
定义一个缓存数组,存储已经计算过的数列,每次计算前看看数组里有没有,如果有直接用,如果没有就计算,然后存在数组,以便下一次计算使用
function fib(n) {
let cache = [0, 1, 1]
function _fib(n) {
if(cache[n]) return cache[n]
cache[n] = _fib(n-1) + _fib(n-2)
return cache[n]
}
return _fib(n)
}
本文参考自饥人谷前端课程