请在以下代码中解释递归语句的工作原理。
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将GO去哪里?
然后该方法将调用自身,此时n-1
变为4,然后乘以n
,其中IF保持值“6”,然后4 * 6 = 24,我认为这是错误的。因为如果我们通过这种方式然后在下一个电话中
过程将是这样的,n-1
将成为3 * n,其中IF保持相同的值,即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来自哪里?我认为我严重陷入了代码的工作中。
答案 0 :(得分:7)
该函数会扩展,直到达到终止语句(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
答案 1 :(得分:1)
您可能错过的是n
是您的函数本地变量。这意味着对函数的每次调用(可能通过递归与否)都会获得一个新变量n
,其中包含该函数的参数。因为它是值类型,所以它被复制而不是对原始值的引用。因此,在一次调用中对它的任何更改都不会影响其他(递归)调用中的变量。
因此,您的函数首先会获得6
的副本,并将其减少1
作为副本,以便下次调用您的函数。那个电话得到一个"副本" 6-1=5
并再次减少 - 依此类推。当它达到1
时,它也会返回1
。然后它再次通过调用堆栈向上运行,并将最后一次调用的结果与此调用中的局部变量相乘。因此1
与2
相乘并返回。该结果与3
相乘,依此类推。最后你最终得到了阶乘。
答案 2 :(得分:0)
在java中,我们有一个名为 stack 的东西。
每次方法被另一个方法调用时,它都会被添加到堆栈中。
________
|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)
然后等待它完成,因为结果取决于它。
但是,在factR(5)
中,您也会进行递归调用,而您必须等待。
依此类推,直到我们达到限制factR(1)
,这将返回1.
完成factR(1)
后,factR(2)
可以打印出结果并将结果返回到其父方法,依此类推,直到factR(6)
打印出来并返回其结果
答案 3 :(得分:-1)
该方法应该像这样构造,以找到n
:
int factorial(int n)
{
if (n == 1)
return 1;
return n * factorial(n - 1);
}
在我看来,在递归函数中实例化新变量并不是一个好主意,因为它们只是因为范围而每次调用都会被重置。