解释析因方法中的递归

时间:2013-11-20 22:51:10

标签: java methods factorial

我是计算机科学的新手,也是学习递归方法的人。可以简单地解释一下这个方法。

 import java.util.Scanner;

public class factorial {

    public static void main(String args[]) {

        Scanner scan = new Scanner(System.in);

        int n = scan.nextInt();

        System.out.print(factorial(n));

    }

    private static long factorial(int n) {      // HERE I DON'T UNDERSTAND HOW 
                                               //  THE MACHINE NOWS WHAT IS "factorial"
        if (n == 1)
            return 1;
        else
            return n * factorial(n - 1);               // ??
    }

}

9 个答案:

答案 0 :(得分:8)

机器不知道 factorial是什么,那里的代码告诉它如何计算阶乘。这是通过说"你给我的数字是1?"直到它为止,返回n - 1函数返回的次数,基本上这将级联到阶乘的计算中。

如果你举一个例子,这很容易看出:

3! = 3*2*1

3! = 3*2!

返回方法在表单中提供的内容如下:

factorial(n) = n * factorial(n-1)

给出的计划:

factorial(3);

将通过以下内容:

  1. 3等于1?
  2. 不是这样,它会返回3*factorial(2)
  3. 为了获得3*factorial(2),它会计算factorial(2)
  4. 现在检查:2等于1?
  5. 不是这样,它返回2*factorial(1),因为它返回到第三步,整体返回现在将是3*2*factorial(1)
  6. 接下来程序检查:1等于1?
  7. 它返回1。
  8. 这会在第五步中返回到我们的通话:2*factorial(1)变为2*1 = 2,它会返回第3步的来电,我们的第一个电话,给我们3*2 = 6,这就是功能将全面返回。
  9. 这种方法可以做一些调整。想象一下,你提供了0?它会在无限递归时不断调用阶乘方法,因为序列0,-1,-2,-3,-4,...永远不会到达1。一个更好的方法可能如下所示:

    private static long factorial(int n) {
    
        if (n == 1 || n == 0) {
            return 1;
        } else if (n < 0) {  // factorials are not defined below 0, they can be interpolated
            return null;     // though, see note below
        } else {
            return n * factorial(n - 1);
        }
    }
    

    此函数现在将涵盖整数范围的阶乘,使用空数解为负数。因子n的定义定义为1和n之间整数的乘积; see this。负整数,浮点数和复数值的因子也被定义或者可以如先前的序列中的链接中所述进行插值,但是这些比简单的递归因子要复杂得多。

答案 1 :(得分:2)

它知道什么是因子,因为你将它定义为阶乘。

您已经创建了一个private static long factorial(int n),这意味着“一个名为factorial的方法,其中包含一个返回long的单个参数n,在factorial类上是静态可用的,并且是私有的那个班。

您可以从有权访问它的任何地方调用factorial,在这种情况下,它位于factorial类本身内。这意味着您可以从main方法调用它,或者您可以从factorial方法本身调用它。它只是一个函数调用,恰好称之为自己。

我们知道阶乘的定义,1 * 2 * ... (n-1) * n。我们也可以将其定义为n! = n * (n - 1)!或换句话说,factorial(n) = n * factorial(n-1),这正是您在最后一行中看到的内容。

答案 2 :(得分:1)

所有这些都是将问题分解为自身的较小版本。

什么是 1!

1

由以下代码

表示
    if (n == 1)
        return 1;

如果你知道(n-1)!,你能找到 n!吗?当然可以!

将其乘以 n

由代码的其他部分代表。

    else
        return n * factorial(n - 1); 

你正在做的是从内部调用函数,最终n将为1,循环将停止。

答案 3 :(得分:1)

只需拿一张纸并追踪你的代码:

factorial(5):
5!=1:
    return 5*factorial(4):
    4!=1:
        return 4*factorial(3):
        3!=1:
            return 3*factorial(2):
            2!=1:
                return 2*factorial(1):
                1==1:
                return 1;

所以,最后我们有: return 5*4*3*2*1声明

答案 4 :(得分:0)

您的代码:

private static long factorial(int n) {
    if (n == 1)
        return 1;
    else
        return n * factorial(n - 1);
}

定义了一个名为factorial的方法。它可以被命名为funcfred或任何你喜欢的名字;它不会改变它的行为。

它的行为如下:

  • 如果参数n等于1,则它只返回1
  • 否则,它返回n的乘积,其结果是调用factorial,其参数等于n - 1。这是递归步骤。请注意,该函数可以调用自身,并且在递归调用返回之前不会返回。调用链被压入堆栈,每个调用都在等待下一个调用返回产品并返回之前返回。

稍作思考,您应该能够看到上述行为与阶乘函数的常见教科书定义完全匹配。

假设使用大于0的参数调用factorial,则递归最终将始终以factorial的调用结束,参数等于1.如上所述,此函数将失败并返回如果使用小于1的值n调用它,则会发生堆栈溢出异常。

答案 5 :(得分:0)

你的其余代码是无关紧要的,让我们分解你的递归函数:

private static long factorial(int n) {     
    if (n == 1)
        return 1;
    else
        return n * factorial(n - 1);
}

第一行或签名是什么,“我是一个私有方法(private),它没有附加到返回{{1}的特定对象实例(static) }(这是一个长整数值)。我被命名为'factorial',因为推测输出是输入的阶乘。作为输入,我得long,我命名为{{1}为了我的目的。

我们知道阶乘被定义为int。写这个的另一种方法是:

n

或者:

f(n) = n*(n-1)*...*1

等等。但你什么时候停止?何时f(n) = n * f(n-1) 。我们在方法中看到了这一点:

f(n) = n * (n-1) * f(n-2)
f(n) = n * (n-1) * (n-2) * f(n-3)

这里的递归调用是在最后一行:它使用相同的函数来找出一个离散量较小的问题的解决方案。毕竟,我们知道如果我们将n == 1乘以这个较小问题的结果,我们会得到正确的答案。

答案 6 :(得分:0)

数字的底数 (n =数字)是所有小于或等于n的正整数的乘积。 n的阶乘可以表示为n!
前/
5 = 5的阶乘!
100的阶乘= 100!

 factorial of 5 means (5!) -> 5 * 4 * 3 * 2 * 1

ex /根据此方法

  1   private static long factorial(int n) {                                      
  2     if (n == 1){
  3       return 1;
  4     } else{
  5       return n * factorial(n - 1);
  6     }
  7   }

如果我们需要找到5个! -(阶乘为5)必须使用数字5调用上述方法。
ex /

factorial(5)
第2行中的

if (n == 1)条件检查您传递的数字是否等于1(因为1!等于1),我们以此行作为基本情况(递归函数停止的位置)< / p>

基本案例
当我们调用递归函数时,它会不断地反复调用,直到我们的堆栈溢出为止。因此,我们需要一个递归函数的“停止点”。该端点称为基本情况

主要目标是理解这一行-

return n * factorial(n - 1);

在我们的第一次迭代中,n = 5和n-1 = 4(根据我们的示例)

想象这样的函数调用

第一次迭代5! = 5 * factorial(4)-在这一行中,我们分别保留5,然后*我们再次调用factorial(4)

第二次迭代4! = 4 * factorial(3)-在此行中,我们再次调用factorial(3)

第3次迭代3! = 3 * factorial(2)-在这一行中,我们再次调用factorial(2)

第4次迭代2! = 2 * factorial(1)-在此行中,我们再次调用factorial(1)

第5次迭代1! = 1-开始返回1

想象一下这样的返回值

ex /
return 5 * factorial(4)-> 5 * [接收(4 * 3 * 2 * 1)] = 5 *(24)
factorial(4)-4 * factorial(3)-> 4 * [receive(3 * 2 * 1)= 4 *(6)
factorial(3)-------> 3 * factorial(2)-> 3 * [接收(2 * 1)] = 3 *(2)
factorial(2)---------------> 2 * factorial(1)-> 2 * [return 1] = 1
this image will helpful (image I got from quora.com)
它一直在调用直到我们的n等于1 一旦我们的函数满足n = 1的基本情况,它将开始返回1。

(请记住,在遇到基本情况之前,它将一直调用函数factorial(n),直到遇到基本情况,我们的函数才不返回任何内容)

答案 7 :(得分:0)

我们需要了解调用堆栈的工作原理才能理解这一点。

让我试着按照你的代码解释:

  1. System.out.print(factorial(n)); /*在这一行,假设n=3;一旦我们调用 factorial(3) ,这个方法就会存储在 Stack */

  2. 上一行将调用方法; private static long factorial(int n) { ... } //n=3 i)它进入内部并检查是否 n==1 //false ii) 它转到 else 块 : 3 * factorial(2) /* 再次在这里 3 * factorial(2) 将存储在 factorial(3) 顶部的堆栈中 */ i) 如果 n==2 //false,它会再次检查 ii)goes to else : 2 * factorial(1) // 存储在栈中 3 * factorial(2) 的顶部 i) 如果 n==1 // True ,它会再次检查,这将返回值 1。

堆栈按 LIFO 顺序如下所示:

2 *阶乘(1)

3 *阶乘(2)

阶乘(3)

现在问题来了,这个返回值 1 会去哪里,它会去栈顶调用。 即 ;2 * factorial(1)--> 返回 2 * 1

值 2 将进入 3 * factorial(2) 的堆栈 --> 其中 3 * 2 =6

最终值 6 将转到被调用的方法:factorial(3)。

答案 8 :(得分:0)

def factorial(n):
    if n < 2:
        return 1
    else:
        return n * factorial(n-1)
factorial(4) # = 24
#You can replace code with your prefered language

这是它的工作原理

  • 如果值小于 2,则实际上不返回两个数字的乘法,而是函数返回数字的乘法函数调用返回的数字n * factorial(n-1))
  • 最后我们返回 1

示例(4 的因子)

  • 首先它返回 4 * factorial (3)

  • 然后它返回4 * 3 * factorial(2)

  • 然后它返回 4 * 3 * 2 * factorial(1)。这里函数的 else 部分结束

  • 最后它返回4 * 3 * 2 * 1 = 24