根据定义:
非Premptive Recursion :如果函数从其中一个参数调用自身,则此类递归称为非Premptive Recursion。示例:Ackermann的函数是非抢先递归的示例
private static int Foo(int i)
{
if (i == 1000000)
return i;
if (i % 100 == 0)
Console.WriteLine(i);
return Foo(Foo(i+1));//last statement of the function
}
这里对Foo
的递归调用是函数的最后一个语句,并不是表达式的一部分,这使得它成为尾递归调用。但另一方面,因为Foo
函数已被调用为参数,因此它将导致创建调用堆栈帧,在达到终止条件之前不能将其丢弃。
在尾递归中,编译器可以优化尾递归调用,因为它不需要维护调用堆栈帧。所以我的问题是 - 我在上面的代码片段中对Foo
的递归调用是否真的是一个尾递归调用?
答案 0 :(得分:1)
非抢占式递归算法也可以是尾递归算法吗?
是
我在上面的代码片段中对
Foo
的递归调用是否真的是一个尾递归调用?
哪一个?有两个递归调用:
…(Foo(i+1))…
- 不是尾递归return Foo(…);
- tail-recursive 可以优化外部尾递归:
private static int Foo(int i) {
while (i != 1000000) {
if (i % 100 == 0) Console.WriteLine(i);
i = Foo(i+1);
}
return i;
}
编译器可能推断Foo
总是返回1000000
(如果它返回),因此进一步将该方法重写为另一个尾递归,但这需要高级推理并不是一个简单的转变:
private static int Foo(int i) {
if (i != 1000000) {
if (i % 100 == 0) Console.WriteLine(i);
} else {
return i;
}
return Foo(i+1);
}
然后可以通过尾递归规则转换为
private static int Foo(int i) {
while (i != 1000000) {
if (i % 100 == 0) Console.WriteLine(i);
i = i+1;
}
return i;
}