函数直接或间接调用自身
避免无限递归,无限递归会导致执行栈溢出
对比死循环,不会导致栈溢出
执行栈
任何代码的执行都必须有一个执行环境,执行环境为代码的执行提供支持
执行环境是放到执行栈中的
每个函数的调用,都需要创建一个函数的执行环境,函数调用结束,执行环境销毁
执行栈有相对谷固定的大小,如果执行环境太多,执行栈无法容纳,栈溢出会报错
尾递归
如果一个函数最后一条语句是调用函数,并且调用函数不是表达式的一部分,则该语句称为尾调用,如果尾调用是调用自身函数,称为尾递归
某些语言或执行环境会对尾调用进行优化,他们会销毁当前函数,避免执行栈空间被调用
浏览器执行环境中,尾调用没有优化
nodeJs中有优化
1.汉诺塔
解析参考这个链接吧
// hannuo塔
function move (pillarStart, pillarEnd, plateNumer) {
console.log(`把第${plateNumer}个盘子从${pillarStart}号柱子挪到${pillarEnd}号柱子`)
}
// no1, no2, no3三个编号的柱子
// 盘子数量
function movePlate (no1, no2, no3, plateNumer) {
if (plateNumer == 1) {
move(no1, no3, plateNumer)
} else {
//n-1从1号挪到2号 需经过3号
movePlate(no1, no3, no2, plateNumer - 1)
//n挪到3号
move(no1, no3, plateNumer)
//n-1从2号挪到3号,需经过1号
movePlate(no2, no1, no3, plateNumer - 1)
}
}
movePlate('A', 'B', 'C', 4)
2.Fibonacci
使用第二种 递归的方式更为简洁
//动态规划 0,1,1,2,3,5,8,13,······
function fibo (n) {
if (n <= 0) return -1
if (n == 1) return 0
if (n == 2) return 1
var a = 0
var b = 1
var c = 0
for (var i = 3; i <= n; i++) {
c = a + b
a = b
b = c
}
return c
}
console.log(fibo(3))
// f(n) = f(n - 1) + f(n - 2) 递归
function FIBO (n) {
if (n <= 0) return -1
if (n == 1) return 0
if (n == 2) return 1
return FIBO(n - 1) + FIBO(n - 2)
}
console.log(FIBO(5))
3.青蛙跳台阶
一个青蛙,一次只能跳一级合阶,或者跳两级合阶。
问:这个青蛙跳上n级台阶有多少种跳法。
如果这只青蛙,跳上了第n级台阶,那么最后二次跳跃之前,他一定在n-1级台阶或n-2级台阶上。
那么跳上n级台阶有多少种情况就变成了两个子问题:跳上n-1级台阶的跳法 加上 跳上n-2级台阶的跳法。
按照此逻辑递推,跳上n-1级台阶可以拆解为两公子问题既:跳上n-2级台阶的跳法 加上 跳上n-3级台阶的跳法
f(n) = f(n - 1) + f(n - 2)
function jump (n) {
if (n <= 0) return -1
if (n == 1) return 1
if (n == 2) return 2
return jump(n - 1) + jump(n - 2)
}
console.log(jump(5))//8
4.变态青蛙跳台阶
这只青蛙 一次可以跳1级台阶、2级台阶、或n级台阶
问:这只青蛙 跳上n级台阶共有多少种方法
f(n) = f(n - 1) + f(n - 2) + f(n - 3) +·····+f(2) + f(1) + f(0)
function jump (n) {
if (n <= 0) return -1
if (n == 1) return 1
if (n == 2) return 2
var result = 0
for (var i = 1; i < n; i++) {
result += jump(n - i)
}
return result + 1//+1代表从0级台阶直接跳上去的情况
}
console.log(jump(5))//16