【问题标题】:The Ackermann Function and Recursion阿克曼函数和递归
【发布时间】:2012-01-31 10:02:19
【问题描述】:

我尝试用 Java 编写递归 Ackermann 函数。但我想我在某个地方走错了!任何人都可以看看,检查并指出我纠正代码的正确方向吗?谢谢!

我对代码的问题是,在我写完它之后,我想,如果 n == 0 和 m == 0,没有这个区域怎么办?这会属于 if (m == 0) 还是需要它自己的 if 语句?

我的以下解决方案是否正确?如果我以不同的顺序给它相同的数字,它会给出不同的结果,我不确定这是否是这种情况。

public static int ackermann(int m, int n) {

        if (m == 0) {

            return n + 1;

        } else if ((m > 0) && (n == 0)) {

            return ackermann(m-1, n);

        } else if ((m > 0) && (n > 0)) {

            return ackermann(m-1, ackermann(m,n-1));

        } else {

            return 0;

        }

    }

我想了更多,我认为我错得更大。如果你不知道我做了什么,我给每个 if 语句一个相反的,因为我认为如果 m 和 n 值以不同的方式给出,下面的代码将起作用。它显然没有,但有人可以尝试解释我哪里出错了吗?

public static int ackermann(int m, int n) {

        if (m == 0) {

            return n + 1;

        } else if (n == 0) {

            return m + 1;

        } else if ((m > 0) && (n == 0)) {

            return ackermann(m-1, n);

        } else if ((n > 0) && (m == 0)) {

            return ackermann(n-1, m);

        } else if ((m > 0) && (n > 0)) {

            return ackermann(m-1, ackermann(m,n-1));

        } else if ((n > 0) && (m > 0)) {

            return ackermann(n-1, ackermann(n, m-1));

        } else {

            return 0;

        }

    }

【问题讨论】:

  • 你的最终else 应该抛出一个InvalidArgumentException

标签: java function recursion if-statement ackermann


【解决方案1】:

“如果 m = 0”规则适用于 n 的所有值,因此 A(0, 0) 为 1。

'else' 子句只能在 m 和 n 在进入函数时都为负数时使用,这可以被诊断为异常。事实上,如果 m 或 n 为负数,您应该诊断错误。或者,由于 A(m, n) 在其他情况下永远不会返回零,因此可以将 0 视为错误信号。

请注意,评估 A(m, n) 所需的堆栈深度与答案相同 - 并且 A(m, n) 很快就会变得非常大。不要费心尝试评估 A(4, 4);您的计算机内存不足。

【讨论】:

  • 实际上,Ackermann 函数仅针对非负参数定义。 (例如,对于 m == 0,n == -1,它没有定义。)
  • 同意:但是 Java 代码采用有符号整数,因此在调用它时可能会被误用 - 也许代码应该对此进行诊断。
  • 我的意思很简单,当使用 (0, -1) 调用代码时,它会很高兴地返回 0。更改 else 子句不足以解决此问题。
【解决方案2】:

这部分错了:

    } else if ((m > 0) && (n == 0)) {
        return ackermann(m-1, n);

应该是A(m - 1, 1)

【讨论】:

    【解决方案3】:

    第一个 sn-p 是可以的,只是在第二种情况下它返回 ackermann(m-1, n) 而不是 ackermann(m-1, 1)。默认情况下,不应该发生,应该抛出一个IllegalStateException,以防它真的发生。

    【讨论】:

      【解决方案4】:

      我认为您的第一个版本几乎是正确的。我会稍微修改一下:

      public static int ackermann(int m, int n) {
          if (m < 0 || n < 0) {
              throw new IllegalArgumentException("Non-negative args only!");
          }
      
          if (m == 0) {
              return n + 1;
          } else if (n == 0) {
              return ackermann(m-1, 1); // Corrected!
          } else {
              // perforce (m > 0) && (n > 0)
              return ackermann(m-1, ackermann(m,n-1));
          }
      }
      

      m == 0 &amp;&amp; n == 0 案例应包含在 m == 0 案例中。

      编辑:请注意,Ackermann function 仅针对非负参数定义。特别是,ackermann(0, -1) 应该抛出异常。因此,您不能只将最后一个 else 子句转换为 throw

      【讨论】:

        【解决方案5】:

        有趣的是,您的问题的所有答案都指出了您在第一个版本中的错误,但对第二个版本中的大错误只字未提

         else if (n == 0) {
                return m + 1;
            } 
        

        对于正整数,在条件上等价于

        else if ((m > 0) && (n == 0)) {
                return ackermann(m-1, n);
            } 
        

        因此,您的函数将返回 m+1 而不是 ackermann(m-1, 1) ,这应该适用于第二种情况 ((m > 0) && (n == 0)) 。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-03-04
          • 2010-11-28
          • 1970-01-01
          • 1970-01-01
          • 2015-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多