代码之家  ›  专栏  ›  技术社区  ›  beta Rob

这个函数真的是尾部递归的吗?

  •  1
  • beta Rob  · 技术社区  · 11 年前

    我在 节目采访曝光 (第三版),其中他们提出了以下递归 factorial 功能:

    int factorial(int n){
        if (n > 1) { /* Recursive case */
            return factorial(n-1) * n;
        } else {     /* Base case */
            return 1;
        }
    }
    

    在同一页(第108页)的底部,他们讨论了尾部递归函数:

    请注意,当递归调用返回的值本身立即返回时,如前面的定义 阶乘 ,函数为 尾递归 .

    但这里真的是这样吗?函数中的最后一个调用是 * 调用,那么这个堆栈帧不会被保留吗(如果我们不考虑编译器优化的话)?这真的是尾部递归吗?

    4 回复  |  直到 11 年前
        1
  •  5
  •   Eric Jablow    11 年前

    您可以将其重写为尾部递归:

    int factorial(int n){
        return factorial2(n, 1);
    }
    int factorial2(int n, int accum) {
        if (n < 1) {
           return accum;
        } else {
            return factorial2(n - 1, accum * n);
        }
    }
    
        2
  •  4
  •   cHao Hammerite    11 年前

    不,这不是尾部递归。返回的结果 factorial(n-1) 仍然需要乘以 n ,这就要求 factorial(n) 重新获得控制权(从而强制要求 阶乘(n-1) 是呼叫而不是跳跃)。

    话虽如此,即使它是尾部递归的,编译器也可能不会对它执行TCO。这取决于编译器和您要求它执行的优化。

        3
  •  1
  •   taocp    11 年前

    引用此链接: tail recursion using factorial as example

     factorial(n) {
        if (n == 0) return 1;
        return n * factorial(n - 1);
     }//equivalent to your code
    
     This definition is NOT tail-recursive since the recursive call to 
     factorial is not the last thing in the function 
     (its result has to be multiplied by n)
    
        4
  •  0
  •   Aatish Sai    11 年前

    Tail Recursive 是递归的一种特殊情况,其中函数的最后一个操作是递归调用。在尾部递归函数中,递归调用返回时不需要执行挂起的操作。 您提到的函数不是尾递归,因为有一个挂起的操作,即对递归调用的返回执行乘法。 如果你这样做了:

        int factorial(int n,int result)
        {
            if (n > 1)
            { /* Recursive case */
                 return factorial(n-1,n*result);
            }
            else
            {     /* Base case */
                return result;
            }
        }
    

    将是一个尾部递归函数。因为它在递归调用返回时没有挂起的操作。