非抢占式递归算法也可以是尾递归算法吗?

时间:2016-09-22 23:41:47

标签: algorithm recursion tail-recursion

根据定义:

非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的递归调用是否真的是一个尾递归调用?

1 个答案:

答案 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;
}