Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的递归如何工作?_Java_Recursion - Fatal编程技术网

Java中的递归如何工作?

Java中的递归如何工作?,java,recursion,Java,Recursion,请在下面的代码中解释递归语句的工作原理 int factR(int n) { int result; if(n==1) return 1; result = factR(n-1) * n; return result; } 我的理解是: 在上面的语句中,factR(n-1)方法调用自己直到结束。假设我们想要得到6的阶乘,它将作为参数发送到此方法。它将作为参数n接收,然后检查n的值;如果为1,则返回1。但是如果它不是1,就像我们的例子中的6,那么递归语句将运行

请在下面的代码中解释递归语句的工作原理

int factR(int n) {
    int result;

    if(n==1) return 1;

    result = factR(n-1) * n;
    return result;
}
我的理解是:

在上面的语句中,
factR(n-1)
方法调用自己直到结束。假设我们想要得到6的阶乘,它将作为参数发送到此方法。它将作为参数
n
接收,然后检查
n
的值;如果为1,则返回1。但是如果它不是1,就像我们的例子中的6,那么递归语句将运行

现在我面临的问题是,第一次
n-1
变为5,然后乘以n,保持值6,然后变为30。那30块钱去哪了

然后该方法将调用自身,这次
n-1
变为4,然后与
n
相乘,如果该值为“6”,则4*6=24,我认为这是错误的。因为如果我们通过这条路,那么在下一次通话中 该过程类似于,
n-1
将变为3*n,如果保持相同的值,即6,则将变为3*6=18。然后发生下一次调用,
n-1
变为2,如果我们相乘并假设
n
保持值6,那么2*6=12,最后一次调用
n-1
=1*n=6。我的观点是,很明显,
n-1
将减小值
n-1
,即6-1=5,然后5-1=4,然后4-1=3,然后3-1=2和2-1=1。但问题是
n
的值是多少,每次该方法调用自身时,该值将相乘

如果您说当第一次乘法发生时,即“n-1”变为5,然后乘以6=30,30存储在“n”,那么在下一次调用中,5-1=4*30=120,然后4-1=3*120=360,然后3-1=2*360=720,最后1*720=720,那么Java如何确定将结果值放回变量
n

如果我放置另一条语句来检查变量
result
的值,每次方法以这种方式调用自身时,该值是多少,如下所示:

int factR(int n) { 
    int result; 

    if(n==1) return 1; 

    result = factR(n-1)*n ;
    System.out.println(result);
    return result; 
}
然后我得到这个输出:

2
6
24
120
720
Factorial of 6 is 720

我不明白它如何在第一次调用中生成2。值2和6、24、120和720从何而来?我想我在代码的工作中遇到了严重的问题。

该方法的结构应该是这样的,以便找到
n
的阶乘:

int factorial(int n)
{
    if (n == 1)
        return 1;

    return n * factorial(n - 1);
}

在我看来,在递归函数中实例化新变量不是一个很好的主意,因为它们在每次调用时都会因为作用域而重置。

这里您可能遗漏的是,
n
是函数的局部变量。这意味着对函数的每次调用(无论是否通过递归)都会得到一个新变量
n
,该变量包含该函数的参数。因为它是值类型,所以它是复制的,而不是对原始值的引用。因此,在一个调用中对它的任何更改都不会影响其他(递归)调用中的变量


因此,您的函数首先获得
6
的副本,并将其减少
1
作为下一次调用函数的副本。该调用获取
6-1=5的“副本”,并再次减少它,以此类推。当它到达
1
时,它也返回
1
。然后它通过调用堆栈再次向上运行,并将最后一次调用的结果与此调用中的局部变量相乘。因此
1
2
相乘并返回。该结果与
3
相乘,依此类推。最后以阶乘结束。

函数将展开,直到到达终止语句(
n==1
)。所以假设
n=6
,那么我们有
factR(n-1)*n=factR(5)*6
,但什么是
factR(5)
?好的,它只是
factR(4)*5
,所以我们看到
factR(5)*6=(factR(4)*5)*6
。现在注意,
factR(1)=1
,我们得到

factR(6) = factR(5) * 6 
         = (factR(4) * 5) * 6 
         = ((factR(3) * 4) * 5) * 6 
         = (((factR(2) * 3) * 4) * 5) * 6 
         = ((((factR(1) * 2) * 3) * 4) * 5) * 6 
         = ((((1 * 2) * 3) * 4) * 5) * 6
         = (((2 * 3) * 4) * 5) * 6
         = ((6 * 4) * 5) * 6
         = (24 * 5) * 6
         = 120 * 6
         = 720

在java中,我们有一种称为堆栈的东西

每次一个方法被另一个方法调用时,它都会被添加到堆栈中

 ________
|factR(1)| = <prints nothing>
 ________
|factR(2)| = 2
 ________
|factR(3)| = 6
 ________
|factR(4)| = 24
 ________
|factR(5)| = 120
 ________
|factR(6)| = 720
________
|事实(1)|=
________
|因子(2)|=2
________
|因子(3)|=6
________
|因子(4)|=24
________
|因子(5)|=120
________
|系数(6)|=720
这基本上意味着要完成
factR(6)
方法,
factR(5)
必须完成,
factR(5)
要完成,
factR(4)
必须完成,依此类推

factR(6)
中,您可以调用
factR(5)
,然后等待它完成,因为结果取决于它

但是,在factR(5)
中,您也要进行递归调用,并且必须等待

依此类推,直到我们到达极限值
factR(1)
,它只返回1


factR(1)
完成后,
factR(2)
可以打印出结果并将结果返回到其父方法,依此类推,直到
factR(6)
打印出并返回其结果

您尝试调试代码了吗?您的做法是错误的。在您的情况下,它不会先得到
30
。它将以
1*2
->将结果传递给调用方method
*3
->将结果传递给调用方method
*4
,依此类推。递归调用的每个调用都放在堆栈上,当它到达不再执行任何进一步递归的点时,堆栈从顶部(最后一个调用)一直返回到底部(第一个调用)。2不是第一个调用,而是第二个调用,只是第一个调用在println之前返回,因为:1)你有if(n==1)返回1;在Syste.out.println之前,这意味着没有打印第一个调用2)您的System.out.println在递归调用之后,这意味着将调用第一个递归,然后输出==>输出将是“从后面到开始”。Soooo:第一次调用跳过(1),第二次调用为1+2=2,第三次调用为1*2*3=6等
if(n==1)返回1是一个wr