在C Primer Plus (6th edition)中,它定义了tail recursion concept 以这种方式:
在最简单的递归形式中,递归调用位于函数的末尾,就在return语句之前。这称为尾递归或结束递归,因为递归调用最后会发生。尾递归是最简单的形式,因为它就像一个循环。
它给出了一个以尾递归方式计算阶乘的例子:
long rfact(int n) {
long ans;
if (n > 0)
ans = n * rfact(n - 1);
else
ans = 1;
return ans;
}
它也是一个侧面说明,在我看来这是不正确的:
注意虽然对rfact()的递归调用不是函数中的最后一行,但它是n>时执行的最后一个语句。 0,所以它是尾递归。
可以清楚地看到最后一个语句是n * rfact(n - 1)
,如果你递归扩展,它将导致一系列延迟乘法。该过程本质上是递归的,因此实现不能像here所描述的那样是尾递归的。
这个例子具有误导性。你有什么意见?
答案 0 :(得分:4)
至于一本好的C编程书,我使用的是C编程语言。
你说这不是尾递归是正确的。阶乘的典型尾递归示例是:
int factorial(int x) {
return tailfactorial(x, 1);
}
int tailfactorial(int x, int multiplier) {
if (x <= 0) {
return multiplier;
}
return tailfactorial(x - 1, x * multiplier);
}
我想你的书没有解释尾递归的目的。尾递归用于不增加堆栈深度&#34;。编译器可以用&#34; goto&#34;替换递归调用。不增加堆栈深度的命令。只有在直接返回递归值时才会进行此编译器修改。您将在示例中注意到情况并非如此。
答案 1 :(得分:2)
给定的定义和示例都具有误导性。 tail recursion的定义是:
如果函数返回后除了返回其值之外没有任何操作,则称函数调用是尾递归的。
递归调用不应该在函数的return语句或last语句之前。查看示例:
function foo(data) {
a(data);
return b(data);
}
在这种情况下,a
就在return
语句之前,但b
处于尾部位置。
function bar(data) {
if ( a(data) ) {
return b(data);
}
return c(data);
}
在此示例中,b
和c
都处于尾部位置,但b
不在函数bar
的末尾。
在你给出的例子中,最后一个函数在返回乘法之前执行
ans = n * rfact(n - 1);
因此,它不是尾递归函数。
尾递归函数的例子是
factorial1(n, accumulator) {
if (n == 0) return accumulator;
return factorial1(n - 1, n * accumulator); // The last thing, before return, performed
// by factorial1 is to call itself.
}
factorial(n) {
return factorial1(n, 1);
}
可以由编译器优化
factorial1(n, accumulator) {
while (n != 0) {
accumulator *= n;
n -= 1;
}
return accumulator;
}