【问题标题】:Factorial using Recursion in Java在 Java 中使用递归的阶乘
【发布时间】:2012-01-01 06:38:00
【问题描述】:

我正在使用 Java: The Complete Reference 一书学习 Java。 目前我正在研究递归主题。

请注意:stackoverflow 上有类似的问题。我搜索了他们,但我没有找到我的问题的解决方案。我对以下程序中的逻辑感到困惑。

如果我运行下面的程序,它会产生正确的输出,但我不明白其中的逻辑。

  • 我不明白下面这行的逻辑:result = fact(n-1) * n;
  • 据我所知,如果我们传递 n=4 的值,如下面的程序所示,
  • 然后,3 * 4 存储在结果中,即 12。
  • 再次调用 fact(n-1)。然后 n 变为 3。
  • 然后将 2 * 3 存储在结果中,替换之前的 12。
  • 我想你明白我的困惑/困惑。

  • 谢谢。

class Calculation
{
    int fact(int n)
    {
        int result;

       if(n==1)
         return 1;

       result = fact(n-1) * n;
       return result;
    }
}

public class Factorial
{
     public static void main(String args[])
     {
       Calculation obj_one = new Calculation();

       int a = obj_one.fact(4);
       System.out.println("The factorial of the number is : " + a);
     }
}

【问题讨论】:

  • 我的建议是,在深入研究 Java 之前,您首先需要了解递归背后的数学原理。如果你还没有这样做,这对你来说将是一个很好的开始 en.wikipedia.org/wiki/Recursion

标签: java recursion


【解决方案1】:

首先您应该了解阶乘的工作原理。

让我们拿4!举个例子。

4! = 4 * 3 * 2 * 1 = 24

让我们用上面的例子来模拟一下代码:

int fact(int n)
    {
        int result;
       if(n==0 || n==1)
         return 1;

       result = fact(n-1) * n;
       return result;
    }

在大多数编程语言中,我们有我们所说的function stack。它就像一副牌,每张牌都放在另一张牌的上方——每张牌都可以被认为是一个函数所以,传递方法fact

堆栈级别 1:fact(4) // n = 4 and is not equal to 1. So we call fact(n-1)*n

堆栈级别 2:fact(3)

堆栈级别 3:fact(2)

堆栈级别 4:fact(1) // 现在,n = 1。所以我们从这个函数返回 1。

返回值...

堆栈级别 3:2 * fact(1) = 2 * 1 = 2

堆栈级别 2:3 * fact(2) = 3 * 2 = 6

堆栈级别 1:4 * fact(3) = 4 * 6 = 24

所以我们得到了 24 个。

请注意以下几行:

result = fact(n-1) * n;
           return result;

或者简单地说:

return fact(n-1) * n;

这会调用函数本身。以4为例,

按照函数栈的顺序..

return fact(3) * 4;
return fact(2) * 3 * 4
return fact(1) * 2 * 3 * 4

替换结果...

return 1 * 2 * 3 * 4 = return 24

我希望你明白这一点。

【讨论】:

  • 我想你的意思是 // n = 4 并且不等于 1。不确定 12 是从哪里来的。
  • 我的意思是,4 = 4 * 3 * 2 * 1 的阶乘。我的问题,起初我认为值 4*3 将存储在结果中。
  • 是的.. 它将被存储在结果中.. 但是,我们再次调用该函数,因此它不是真正的结果.. 当我们返回值时将调用该结果...实际上,那是 4 * 事实(3)。然而,在 fact(3) 中,我们也有 3 * fact(2)。事实上(2),我们也有 2 * 事实(1)。现在我们最终得到 fact(1),因为 n=1。所以我们返回值。 2 * 1,然后是 3 * 2 * 1,最后是 4 * 3 * 2 * 1
【解决方案2】:

这是使用递归的阶乘计算如何工作的另一种解释。

让我们稍微修改一下源代码:

int factorial(int n) {
      if (n <= 1)
            return 1;
      else
            return n * factorial(n - 1);
}

这里是3!的详细计算:

来源:RECURSION (Java, C++) | Algorithms and Data Structures

【讨论】:

    【解决方案3】:

    resultfact 方法的局部变量。因此,每次调用 fact 方法时,结果都会存储在与上一次调用 fact 不同的变量中。

    所以当 fact 以 3 作为参数调用时,你可以想象它的结果是

     result3 = fact(2) * 3
     result3 = result2 * 3
     result3 = 1 * 2 * 3
    

    【讨论】:

      【解决方案4】:

      我相信,您的困惑源于您认为只有一个 result 变量,而实际上每个函数调用都有一个 result 变量。因此,旧的结果不会被替换,而是被返回。

      详细说明:

      int fact(int n)
      {
          int result;
      
         if(n==1)
           return 1;
      
         result = fact(n-1) * n;
         return result;
      }
      

      假设调用fact(2)

      int result;
      if ( n == 1 ) // false, go to next statement
      result = fact(1) * 2; // calls fact(1):
      |    
      |fact(1)
      |    int result;  //different variable
      |    if ( n == 1 )  // true
      |        return 1;  // this will return 1, i.e. call to fact(1) is 1
      result = 1 * 2; // because fact(1) = 1
      return 2;
      

      希望现在更清楚了。

      【讨论】:

        【解决方案5】:
        public class Factorial {
        
            public static void main(String[] args) {
                System.out.println(factorial(4));
            }
        
            private static long factorial(int i) {
        
                if(i<0)  throw new IllegalArgumentException("x must be >= 0"); 
                return i==0||i==1? 1:i*factorial(i-1);
            }
        }
        

        【讨论】:

        • 可能是因为你没有解释任何事情,但我喜欢你的解决方案,我已经投了赞成票。
        【解决方案6】:

        递归调用本身会导致进一步的递归行为。如果你把它写出来,你会得到:

         fact(4)
         fact(3) * 4;
         (fact(2) * 3) * 4;
         ((fact(1) * 2) * 3) * 4;
         ((1 * 2) * 3) * 4;
        

        【讨论】:

          【解决方案7】:

          您在这里遗漏的关键点是变量“result”是一个堆栈变量,因此它不会被“替换”。详细地说,每次调用 fact 时,都会在解释器内部创建一个名为“result”的新变量,并链接到该方法的调用。这与链接到对象实例而不是特定方法调用的对象字段形成对比

          【讨论】:

            【解决方案8】:

            使用三元运算符的递归解决方案。

            public static int fac(int n) {
                return (n < 1) ? 1 : n*fac(n-1);
            }
            

            【讨论】:

            • 返回 n == 1 || n==0 ? 1 : n * fac(n - 1);
            • 返回 (n
            • @martynas 赚到了钱 - 无需检查 n == 1。在你的脑海中运行它 - 如果你通过 1,它会返回 1。
            【解决方案9】:

            虽然它已经过时了,但它仍然在谷歌中不断出现。所以我想我会提到这一点。 x = 0 时没有人提到要检查。

            0!和1!两者都 = 1。

            这不会与之前的答案一起检查,如果 fact(0) 运行,会导致堆栈溢出。无论如何简单的修复:

            public static int fact(int x){
                if (x==1 | x==0)
                    return 1;
                return fact(x-1) * x;
            }// fact
            

            【讨论】:

              【解决方案10】:

              要理解它,您必须尽可能以最简单的方式声明该方法,而 martynas 在 5 月 6 日的帖子中指出了它:

              int fact(int n) {
                  if(n==0) return 1;
                  else return n * fact(n-1);
              }
              

              阅读上面的实现,你就会明白。

              【讨论】:

              • 我喜欢这个解决方案,因为它最简洁,还包括对 0 和 1 的检查。如果您不认为它会检查 1,请在脑海中运行 n = 1。
              【解决方案11】:

              在我看来,并且这是具有 java 初级知识的人的意见,我建议将 n == 1 更改为 n

              【讨论】:

                【解决方案12】:

                正确的是:

                int factorial(int n)
                {
                    if(n==0||n==1)
                        return 1;
                    else 
                        return n*factorial(n-1);
                }
                

                这将为阶乘 0 返回 1。相信我吗?我已经学会了这个艰难的方式。 只因为不保持0的条件无法通过面试。

                【讨论】:

                  【解决方案13】:

                  恕我直言,理解递归相关动作的关键是:

                  1. 首先,我们递归地深入堆栈,每次调用我们 以某种方式修改一个值(例如,func(n-1); 中的 n-1),它决定了 递归应该越来越深。
                  2. 一次 满足 recursionStopCondition(例如n == 0),递归停止, 和方法做实际工作并将值返回给调用者方法 上层堆栈,从而冒泡到堆栈顶部。
                  3. 它是 以某种方式捕获从更深的堆栈返回的值很重要 修改它(在你的情况下乘以 n ),然后返回这个 修改后的值在堆栈顶部。常见的错误是 来自最深堆栈帧的值直接返回到顶部 堆栈,以便忽略所有方法调用。

                  当然,方法在深入递归之前(从堆栈的顶部到底部)或返回时可以做有用的工作。

                  【讨论】:

                    【解决方案14】:

                    使用 Java 8 及更高版本,使用递归本身

                      UnaryOperator<Long> fact = num -> num<1 ? 1 : num * this.fact.apply(num-1);
                    

                    并像使用它

                      fact.apply(5); // prints 120
                    

                    在内部计算类似于

                    5*(4*(3*(2*(1*(1)))))
                    

                    【讨论】:

                      【解决方案15】:
                      import java.util.Scanner;
                      
                      public class Factorial {
                          public static void main(String[] args) {
                              Scanner keyboard = new Scanner(System.in);
                              int n; 
                              System.out.println("Enter number: ");
                              n = keyboard.nextInt();
                              int number = calculatefactorial(n);
                              System.out.println("Factorial: " +number);
                          }
                          public static int calculatefactorial(int n){
                              int factorialnumbers=1;
                              while(n>0){
                               factorialnumbers=(int)(factorialnumbers*n--);   
                              }
                              return factorialnumbers;
                          }
                      }
                      

                      【讨论】:

                        【解决方案16】:
                        public class Factorial2 {
                            public static long factorial(long x) {
                                if (x < 0) 
                                    throw new IllegalArgumentException("x must be >= 0");
                                if (x <= 1) 
                                    return 1;  // Stop recursing here
                                else 
                                   return x * factorial(x-1);  // Recurse by calling ourselves
                            }
                        }
                        

                        【讨论】:

                          【解决方案17】:
                          public class Factorial {
                          public static void main(String[] args) {
                             int n = 7;
                             int result = 1;
                             for (int i = 1; i <= n; i++) {
                                 result = result * i;
                             }
                             System.out.println("The factorial of 7 is " + result);
                          }
                          }
                          

                          【讨论】:

                          • 添加一些解释,说明此答案如何帮助 OP 解决当前问题
                          猜你喜欢
                          • 2016-01-28
                          • 2013-09-18
                          • 1970-01-01
                          • 1970-01-01
                          • 2017-03-17
                          • 1970-01-01
                          • 1970-01-01
                          • 2015-04-19
                          • 2019-07-24
                          相关资源
                          最近更新 更多