经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » JavaScript » 查看文章
Javascript尾递归编程的实现
来源:jb51  时间:2022/6/20 12:22:26  对本文有异议

尾递归编程思想

递归是编程中必不可少的一环,在算法和工程上会经常使用,但是随着计算量的增大,函数堆栈会大量堆积上一函数上下文中的变量和方法,会导致主线程栈的空间不足而造成栈溢出错误,由于新的函数压入堆栈后,上一函数仍然在堆栈中未被释放,因此内存资源消耗会十分大,对性能也会有很大影响。

我们知道递归写起来确实方便,逻辑也容易理解,最简单的斐波那契数列问题,跳楼梯,一次只能1步或2步,跳n格有多少种方法

最容易的递归

  1. // 限制条件 countOfStep>0
  2. function jump(countOfStep) {
  3. if (countOfStep <= 0) return 0;
  4. function jumpRecursive(innerCountOfStep) {
  5. if (innerCountOfStep < 0) return 0;
  6. if (innerCountOfStep === 1 || innerCountOfStep === 0) return 1;
  7. return jumpRecursive(innerCountOfStep - 1) + jumpRecursive(innerCountOfStep - 2);
  8. }
  9. return jumpRecursive(countOfStep);
  10. }

很明显上述递归没有任何优化,利用函数堆栈来实现对上一结果的保存作为下一结果的支撑,函数开销大。

运用缓存结果思想解决函数开销

  1. function jumpWithoutFuncCost(countOfStep) {
  2. if(countOfStep<=0) return 0;
  3. const saves = new Array(countOfStep + 1).fill(0);
  4. [saves[0], saves[1]] = [1, 1];
  5. for (let i = 2; i <= countOfStep; i++) {
  6. saves[i] = saves[i - 1] + saves[i - 2];
  7. }
  8. return saves[countOfStep];
  9. }

是解决了数据过大栈溢出问题了,不过也同时带来空间开销

迭代方法

  1. function jumpIteritive(countOfStep) {
  2. if(countOfStep<=0) return 0;
  3. let [prefix, suffix] = [1, 1];
  4. for (let i = 2; i <= countOfStep; i++) {
  5. let temp = suffix;
  6. suffix += prefix;
  7. prefix = temp;
  8. }
  9. return suffix;
  10. }

如果是复杂点的问题迭代法是比较难想出来的。但凡可以实现迭代处理的方法可以用尾递归实现,递归的实现更具有可读性和简洁性。

尾递归实现

  1. function jumpTailRecursive(countOfStep, prev = 1, next = 1) {
  2. if(countOfStep<=0) return 0;
  3. if (countOfStep === 1) return next;
  4. return jumpTailRecursive(--countOfStep, next, prev + next);
  5. }

原理图解

关于Javascript没有实现尾递归优化

Javascript由于某些原因,JavaScript引擎实现者认为特性不合理,以及各大厂商的权力纠纷问题,TC39提案仍未落实尾递归优化方案。

如果要实现JavaScript尾递归优化,需要采用蹦床函数辅助实现,才能实现和迭代一样避免栈溢出情况。

trampoline实现

  1. function jumpTailRecursiveTrampolined(countOfStep, prev = 1, next = 1) {
  2. if (countOfStep <= 0) return 0;
  3. if (countOfStep === 1) return next;
  4. return () => jumpTailRecursiveTrampolined(--countOfStep, next, prev + next);
  5. }
  6.  
  7. function trampoline(F){
  8. return function(...args){
  9. F = F.bind(this, ...args);
  10. while (F instanceof Function) {
  11. F = F();
  12. }
  13. return F;
  14. }
  15. }
  16.  
  17. const uniformLog = (element) => console.log(JSON.stringify(element, undefined, 4));
  18. uniformLog(trampoline(jumpTailRecursiveTrampolined)(3));

到此这篇关于Javascript尾递归编程的实现的文章就介绍到这了,更多相关Javascript尾递归内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号