请在下面的代码中解释递归语句的工作原理。
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个人会去哪里呢?
然后,该方法将调用自身,这次< code>n-1变为4,然后乘以< code>n,如果值为“6”,则4*6=24,我认为这是错误的。因为如果我们以这种方式进行,那么在下一次调用中,过程将类似于,< code>n-1将变成3*n,如果它保持相同的值,即6,那么它将变成3*6= 18。然后下一个调用发生,并且如果我们相乘并且假设< code>n保存值6,那么2*6= 12,并且最后一个调用< code>n-1= 1 * n = 6,则< code>n-1变成2。我的观点是,很明显< code>n-1将减少< code>n-1的值,即6-1=5,然后5-1=4,然后4-1=3,然后3-1=2,2-1=1。但问题是,当方法每次调用自己时,要乘以的< code>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
?
如果我放置另一个语句,在方法每次以这种方式调用自身时检查变量< code>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从何而来?我想我已经严重地陷入了代码的工作中。
在java中,我们有一个叫做堆栈的东西。
每次一个方法被另一个方法调用时,它都会被添加到堆栈中。
________
|factR(1)| = <prints nothing>
________
|factR(2)| = 2
________
|factR(3)| = 6
________
|factR(4)| = 24
________
|factR(5)| = 120
________
|factR(6)| = 720
这基本上意味着,要完成 factR(6)
方法,factR(5)
必须完成,factR(5)
必须完成,factR(4)
必须完成等等。
在factR(6)
中,调用factR(5)
,然后等待它完成,因为结果取决于它。
但是,事实上R(5)
,你也做了一个递归调用,你必须等待。
依此类推,直到我们达到极限 factR(1),
它将只返回 1。
完成< code>factR(1)后,< code>factR(2)可以打印出结果并将结果返回给其父方法,依此类推,直到< code>factR(6)打印出并返回其结果
这里您可能忽略了< code>n是函数的局部变量。这意味着对你的函数的每一次调用(无论是否通过递归)都会得到一个新的变量< code>n,其中包含该函数的参数。因为它是值类型,所以它是复制的,而不是对原始值的引用。因此,在一个调用中对它的任何更改都不会影响其他(递归)调用中的变量。
结果,您的函数首先获得6
的副本,并将其减少为1
作为函数下一次调用的副本。该调用获得6-1=5
的“副本”并再次减少它-依此类推。当它到达1
时,它还返回1
。然后它在调用堆栈中再次向上工作,并将最后一次调用的结果与此调用中的局部变量相乘。因此1
与2
相乘并返回。该结果与3
相乘,依此类推。最后你得到阶乘。
该函数一直扩展到终止语句(< code>n == 1)。所以假设< code>n = 6,那么我们有< code > factR(n-1)* n = factR(5)* 6 ,但是什么是< code>factR(5)?它只是< code>factR(4) * 5,所以我们看到< code > factR(5)* 6 =(factR(4)* 5)* 6 。现在注意< code>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
我几乎理解了尾递归是如何工作的,以及它与普通递归之间的区别。我只是不明白为什么它不要求堆栈记住它的返回地址。 在尾递归函数中调用函数本身后没有什么可做的,但对我来说这没有意义。
问题内容: 请以最简单的方式说明递归的工作方式。 问题答案: 这是一个递归方法的简单示例:-
该方法的规范声称,该方法,从根开始,将移除最左侧的节点,并修复树结构。它还指出,如果最左侧节点没有左子节点,则将右子节点(可能为)作为左子节点附加到最左侧节点的父节点(我在代码中看不到这种情况发生的地方)。代码如下: 我只是不明白它是如何返回整个树和返回最左边的节点。主要是第一部分让我感到困惑,它说如果返回右边的子项。如果我深入到树中(由于递归调用),返回右不就会切断树的很多部分吗?
我理解递归的逻辑,一个函数调用一个基例的函数然后终止,我在这里有一个代码,它记录一个简单的递归,我没有得到的是它开始记录达到条件,条件满足:0? 我希望这段代码首先记录输出,最后达到条件?
我有两个函数:< code>functionA()和< code>functionB(),都有一个返回类型< code>boolean。 如果它们中的任何一个返回true,并且如果函数A返回true,我想继续执行,我不希望函数B执行。 像 上面的代码能满足我的要求吗?
假设我们有一个名为托管在tomcat上的服务提供商应用程序,用户单击指向SP a的链接。SP a没有看到提供的令牌,因此它会将用户重定向到IdP进行身份验证(通过某种方式提供SAML Authn请求)。然后,IdP将用户重定向到提供凭据的某个公共登录页面,假设这些凭据正确,IdP将创建一个SAML响应,其中包含一个令牌和一些关于主题的断言,并将其发送回SP a。SP a看到了这一点,并允许用户访问