博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
尾调用
阅读量:6891 次
发布时间:2019-06-27

本文共 1505 字,大约阅读时间需要 5 分钟。

hot3.png

见下面几个例子:

function factorial(n) {  if (n === 1) return 1;  return n * factorial(n - 1);}factorial(5)

复杂度为o(n) 太大会造成堆栈溢出

function factorial(n, total) {  if (n === 1) return total;  return factorial(n - 1, n * total);}factorial(5, 1) //

复杂度为哦o(1)

尾递归函数的改写:

尾递归的实现,往往需要改写递归函数,确保最后一步只调用自身。做到这一点的方法,就是把所有用到的内部变量改写成函数的参数

递归本质上是一种循环操作。纯粹的函数式编程语言没有循环操作命令,所有的循环都用递归实现,这就是为什么尾递归对这些语言极其重要。 对于其他支持“尾调用优化”的语言(比如 Lua,ES6),只需要知道循环可以用递归代替,而一旦使用递归,就最好使用尾递归。

解决方案: 1、蹦床函数的一个实现,它接受一个函数f作为参数。只要f执行后返回一个函数,就继续执行。 注意,这里是返回一个函数,然后执行该函数,而不是函数里面调用函数,这样就避免了递归执行,从而就消除了调用栈过大的问题。

例子:

function trampoline(f) {  while (f && f instanceof Function) {    f = f();  }  return f;}function sum(x, y) {  if (y > 0) {    return sum.bind(null, x + 1, y - 1);  } else {    return x;  }}trampoline(sum(1, 100000))// 100001

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)

上面代码中,tco函数是尾递归优化的实现,它的奥妙就在于状态变量active。默认情况下, 这个变量是不激活的。一旦进入尾递归优化的过程,这个变量就激活了。然后,每一轮递归sum返回的都是undefined,所以就避免了递归执行;而accumulated数组存放每一轮sum执行的参数,总是有值的,这就保证了accumulator函数内部的while循环总是会执行。这样就很巧妙地将“递归”改成了“循环”,而后一轮的参数会取代前一轮的参数,保证了调用栈只有一层。

转载于:https://my.oschina.net/u/3407699/blog/1927109

你可能感兴趣的文章
查看Android系统图片(缩放)
查看>>
oracle学习6
查看>>
如何正确地使用android中的progressdialog
查看>>
http协议参数详解
查看>>
Python字符串格式化
查看>>
关于synchronized关键字
查看>>
第3章 高级装配
查看>>
c++拷贝构造函数详解
查看>>
C语言博客作业03--函数
查看>>
使用urllib和http.cookiejar获取python老男孩学员成绩
查看>>
双 MySQL 启动、停止脚本
查看>>
node.js 中的全局对象
查看>>
Oracle(限定查询1)
查看>>
Python 国际化
查看>>
C#网络编程
查看>>
jquery 图片自动切换
查看>>
【HDOJ】1224 Free DIY Tour
查看>>
企业架构框架体系
查看>>
css3动画(从上、左下、左、右进入页面)
查看>>
再写点看到的东西
查看>>