• 递归和尾递归的区别


    非尾递归,下一个函数结束以后此函数还有后续,所以必须保存本身的环境以供处理返回值。

    尾递归,进入下一个函数不再需要上一个函数的环境了,得出结果以后直接返回。

    递归(迭代):

    
    recsum(5)
    5 + recsum(4)
    5 + (4 + recsum(3))
    5 + (4 + (3 + recsum(2)))
    5 + (4 + (3 + (2 + recsum(1))))
    5 + (4 + (3 + (2 + 1)))
    5 + (4 + (3 + 3))
    5 + (4 + 6)
    5 + 10
    15
    
    
    
    tailrecsum(5, 0)
    tailrecsum(4, 5)
    tailrecsum(3, 9)
    tailrecsum(2, 12)
    tailrecsum(1, 14)
    tailrecsum(0, 15)
    15
    

    尾递归的判断标准是函数运行最后一步是否调用自身,而不是是否在函数的最后一行调用自身。

    这是尾递归:

    
    function f(x) {
       if (x === 1) return 1;
       return f(x-1);
    }
    

    这不是尾递归:

    function f(x) {
       if (x === 1) return 1;
       return 1 + f(x-1);
    }
    
    

    通常递归都是在栈上根据调用顺序依次申请空间进行运算,然后层层回调,这是基于上一层运算依赖于下一层的运算结果(或者说上一层的运算还没用做完,需要下一层返回的结果)
    而尾递归的情况是下层计算结果对上层“无用”(上一层运算已经做完,不依赖后续的递归),为了效率,直接将下一层需要的空间覆盖在上一层上。

    所以

    尾递归,比线性递归多一个参数,这个参数是上一次调用函数得到的结果;
    所以,关键点在于,尾递归每次调用都在收集结果,避免了线性递归不收集结果只能依次展开消耗内存的坏处。

    使用尾递归可以带来一个好处:因为进入最后一步后不再需要参考外层函数(caller)的信息,因此没必要保存外层函数的stack,递归需要用的stack只有目前这层函数的,因此避免了栈溢出风险。

  • 相关阅读:
    给JavaScript初学者的24条最佳实践
    高音符號的由來是怎樣的
    从零单排学JavaWeb
    数据库建表规则
    linux快捷键
    Linux 命令行快捷键
    DC综合及仿真验证和DFT测试
    verilog中include的用法
    <转>verilog hdl中常数声明
    <转>Verilog HDL宏定义define
  • 原文地址:https://www.cnblogs.com/jackson1/p/12682659.html
Copyright © 2020-2023  润新知