在Return中调用自己两次 - Tail Recursive or Not?

时间:2014-09-19 23:02:13

标签: c++ fibonacci tail-recursion

我理解尾递归但是我被分配编写代码来查看N&#39斐波纳契数是多少。 首先,这段代码确实有效。这不是最好的方式,但它只是一种方式 - 但是我开始担心它不是尾递归。代码在这里:

static int fib_tail_helper(int n, int result) {
if (n == 0) {
    return result;
}   
else if (result == 0) {
    return fib_tail_helper(n - 1, result + 1);
}
else {
    return fib_tail_helper(n - 1, result + fib_tail_helper(n - 1, 0));
}
}

int fib_tail(int n) {
/*
// REQUIRES: n >= 0
// EFFECTS: computes the Nth Fibonacci number
//          fib(0) = 0
//          fib(1) = 1
//          fib(n) = fib(n-1) + fib(n-2) for (n>1).
// MUST be tail recursive
*/
return fib_tail_helper(n, 0);
}

我主要担心"返回fib_tail_helper(n - 1,结果+ fib_tail_helper(n - 1),0 "。 我觉得好像会使用另一个堆栈,因此是非尾递归的...任何人都可以给出一些输入吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

不,它不是尾递归的。

编译器需要首先评估fib_tail_helper参数,这意味着它会在继续调用最后一个fib_tail_helper作为返回值之前创建n-1个调用堆栈。

答案 1 :(得分:1)

为了表明它不是尾递归,转换可能会有所帮助:

static int fib_tail_helper(int n, int result) {
    if (n == 0) {
        return result;
    }   
    else if (result == 0) {
        return fib_tail_helper(n - 1, result + 1);
    }
    else {
        int tailrecursivePreventingValue = fib_tail_helper(n - 1, 0);
        return fib_tail_helper(n - 1, result + tailrecursivePreventingValue);
    }
}

它与您的代码完全相同,但引入了一个解释变量。你可以看到在最后一个else块中有2次调用fib_tail_helper()。这意味着指数运行时间,因为第二个值取决于第一个值。

答案 2 :(得分:0)

尾递归是一种巧妙的递归实现,它不使用堆栈空间。

它的工作原理如下:
如果一个函数调用自身,就像它的最后一个动作一样,则称为"尾递归"。
在这种特殊情况下,编译器可以放弃进行实际的函数调用。它可以执行goto回到函数的开头。该函数的代码将再次运行,就像它已被调用一样。当函数终止时,它将返回堆栈的最后一个地址,这是最初调用递归函数的函数。

无论递归有多深,这种方法都可以保证堆栈不会溢出。这就是尾递归的好处。

坏消息是C ++不会自动支持尾递归。

好消息是实现尾递归非常容易 您只需将goto的最终函数调用替换回函数的开头即可 (这只是你编写编译器所支持的goto,如果它支持尾递归的话。)