zoukankan      html  css  js  c++  java
  • 普通递归与优化递归

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

     

    上面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n) 。

    如果改写成尾递归,只保留一个调用记录,复杂度 O(1) 。

    尾递归

    函数调用自身,称为递归。如果尾调用自身,就称为尾递归。

    递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误

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

    还有一个比较著名的例子,就是计算 Fibonacci 数列,也能充分说明尾递归优化的重要性。

    非尾递归的 Fibonacci 数列实现如下。

    function Fibonacci (n) {
      if ( n <= 1 ) {return 1};
     
      return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
     
    Fibonacci(10) // 89
    Fibonacci(100) // 堆栈溢出
    Fibonacci(500) // 堆栈溢出
    

    尾递归优化过的 Fibonacci 数列实现如下。

    unction Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
      if( n <= 1 ) {return ac2};
     
      return Fibonacci2 (n - 1, ac2, ac1 + ac2);
    }
     
    Fibonacci2(100) // 573147844013817200000
    Fibonacci2(1000) // 7.0330367711422765e+208
    Fibonacci2(10000) // Infinity
    

    由此可见,“尾调用优化”对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6 是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。这就是说,ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存。

     递归函数的改写

    function factorial(n, total = 1) {
      if (n === 1) return total;
      return factorial(n - 1, n * total);
    }
     
    factorial(5) // 120
    
  • 相关阅读:
    vue小项目总结与笔记【八】——keep-alive的使用
    vue小项目总结与笔记【七】——vuex实现数据共享
    vue小项目总结与笔记【六】——使用axios发送ajax请求
    安装SVN和汉化包及基本使用
    readhat6.5下安装weblogic10.3.6
    ssh连接不上vmware虚拟机centos7.5
    Oracle数据库基础操作语法
    Linux调整lvm逻辑分区大小
    win7安装oracle11g和oracle client和pl/sql
    linux常用命令--转载
  • 原文地址:https://www.cnblogs.com/calvin-dong/p/11235462.html
Copyright © 2011-2022 走看看