为什么这个尾递归?

时间:2011-03-17 09:29:14

标签: scala tail-recursion

查看此Scala代码:

def rec(n: Int) {
  if (n > 1) {
    val d = n / 2
    rec(d)
//    if (d > 1)  // abort loop
      rec(n/d)
  }
}

此代码将导致无限循环。由于尾递归优化,我没有得到StackOverflowError。

用jad编译我得到了这个Java代码:

public void rec(int n)
{
    int d;
    for(; n > 1; n /= d)
    {
        int i = n;
        d = i / 2;
        rec(d);
    }
}

在循环的最后一行,该方法调用自身,因此我不理解尾调用位置。有谁可以解释这个?

2 个答案:

答案 0 :(得分:9)

rec(d)的情况下没有尾调用。对于rec(N)(其中N > 1)堆栈在log2(N)调用后不再增长(因为此后n永远等于2或3,d是1)。之后,它只是无限循环,内部rec(1)调用,每次都会立即返回。这就是没有堆栈溢出的原因。

答案 1 :(得分:3)

在您的方法的递归形式中,您有两个递归调用。 StackOverflowError是由最后一个引起的。

由于尾​​递归优化,最后一次调用变为循环(第一次调用保持递归),因此你有无限循环而不是无限递归,并且StackOverflowError不会发生。