1.满足递归的条件
- 一个问题能够被分解成规模更小的子问题,且该子问题与原问题有同样的解法,将问题一直分解到规模最小的问题后,求解最小问题。
- 存在一个能让递归调用停止的出口。
- 先是递进,然后是回归
2.运用递归的注意点
- 递归调用函数时通过
console.log()
打印有值,但是在获取的时候是undefined,原因是在递归函数内部没有对递归函数进行return,否则外层函数无法接收到返回值。 - 如果想要函数最后一次计算所得值,就需要在每次调用该函数的时候进行return,每一次return都是把最新的函数调用返回给外层的函数调用。
3.应用示例
- 数字递归求和,亦可用循环
// 1~num 数字递归求和
function recursionSum(params) {
let temp = null
function addNum(num) {
if (num < 0) {
return 0
}
temp = num
return 0 + temp + addNum(num - 1)
}
return addNum(params)
}
console.log(recursionSum(6));
4.递归的缺陷
- 可能堆栈溢出
递归的过程,可以理解为函数调用栈进出问题。当递归的层次很深时,可能会导致栈溢出。
(1)我们可以规定递归的最大深度,当超过该深度时,报错。下面是斐波那契的例子。
let depth = 0
function fc(num) {
++depth
if(depth > 5) throw new Error('超过最大深度')
console.log('depth==', depth);
console.log('num==', num);
if (num == 1 || num == 2) return 1
return fc(num - 1) + fc(num - 2)
}
const res = fc(5)
console.log(res);
(2)我们可以使用迭代循环,去改写递归,每次都去计算值,而不是将函数存储在内存中等待调用,从而避免堆栈溢出。
function fc(num) {
let res = 0;
let pre = 1;
let lastPre = 1;
let i = 3
for (i; i <= num; i++) {
res = pre + lastPre
lastPre = pre
pre = res
}
console.log(res);
}
fc(6)
- 重复计算度高(这个根据具体逻辑来看,不是所有的递归都有重复计算)
(1)非重复计算度高栗子-- 数组求和
function add(arr) {
if(!arr.length) {
return 0
}
console.log(arr[0]);
return arr[0] + add(arr.slice(1))
}
console.log(add([1,2,3]));
(2)对于重复计算度高的递归
可以使用哈希表(定义:哈希表是一种根据关键码去寻找值的数据映射结构)存储计算过的值。递归过程中,先去哈希表查找有无计算过。