解决递归用栈溢出问题、尾递归优化

解决递归调用栈溢出问题

ES6允许函数内部使用严格模式,而尾调用必须在严格模式下才能使用,因此函数必须使用‘use strict’,尾递归优化只在严格模式下生效,那么正常模式下,或者那些不支持严格模式的环境中,有没有办法也使用尾递归优化呢?

1.什么是尾递归?

尾调用是指函数的最后一步是调用另一个函数。那么尾递归就是最后一步是调用自己。我们知道,在函数调用时,会产生一个调用栈,执行内部函数时会把这个函数push到栈首,内部函数执行完会将状态、数据返回给栈中的下一层,并pop出栈。如果使用尾调用,你会发现,栈中不需要一个个存栈,因为我只需要最后执行的那个函数的数据。因此,对于一些复杂度为O(n)的函数,可以优化到O(1)。

2.非严格模式下的尾递归优化

思路:过多的递归层数会是的函数调用栈溢出,那么我们是不是可以把 ‘递归’ 转换为 ‘循环’

2.1 蹦床函数

我们可以写一个函数,传一个函数进去。此函数就是我们的递归函数,但是我们需要处理一下:边界的地方不进行处理,我们对自身函数的执行更改为返回一个函数(一个新函数)。比如对1,1000000求和:

//改进后的函数
function sum(x, y) {
  if (y > 0) {
    return sum.bind(null, x + 1, y - 1);	//bind返回了一个新函数,正常递归是执行sum函数,如果用递归,调用栈会满。
  } else {
    return x;
  }
}
//蹦床函数
function trampoline(f) {
  while (f && f instanceof Function) {
    f = f();	
  }
  return f;
}

trampoline(sum(1,100000));
//把sum函数传入,执行循环:满足条件后执行sum函数,返回一个新函数。

2.2真正的尾递归优化
function tco(f) {
  var value;	
  var active = false;		//是否处于尾递归
  var accumulated = [];		//参数数组

  return function accumulator() {	//返回一个函数
    accumulated.push(arguments);
    if (!active) {
      active = true;
      while (accumulated.length) {
        value = f.apply(this, accumulated.shift());	//除掉第一个,保留上一次的数据。
      }
      active = false;
      return value;	//返回执行后的值
    }
  };
}

var sum = tco(function(x, y) {
  if (y > 0) {
    return sum(x + 1, y - 1)
  }
  else {
    return x
  }
});

sum(1, 100000)
3.结尾

对于实现尾递归,重点在于将’递归’转换为’循环’。代码、思路来源:阮一峰《ECMAScript 6 入门》
有兴趣的猿可以深入看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值