这段代码来自于书:" C#5.0 in a Nutshell"并且是LinqPad上的一个示例。在第39页上它说:
"此方法是递归的,这意味着它会调用自身。每次输入方法时, 在堆栈上分配一个新的int,每次方法退出时,int都是 解除分配的"
使用文字5的产量和答案120(3产量6)
有人可以解释这是如何工作的吗?我是一名VB程序员,正在尝试学习C#,并希望了解这样的结构。我已经多次单步执行它并且无法理解在x == 0
和1返回之后会发生什么。在x
等于零之前,执行流程很容易理解。之后,最后一个return语句似乎重复执行(神奇地),直到x
增加回原来的值,然后返回到最初调用它的位置,并产生前面提到的(神奇的)数字结果
static void Main()
{
Console.WriteLine (Factorial(5));
}
static int Factorial (int x)
{
if (x == 0) return 1;
return x * Factorial (x-1);
}
答案 0 :(得分:7)
Call Factorial(3) (which returns 3 * 2)
x doesn't == 0
return 3 * Factorial(2)
Calls Factorial(2) (which returns 2 * 1)
x doesn't == 0
return 2 * Factorial(1)
Calls Factorial(1) (which returns 1 * 1)
x doesn't == 0
return 1 * Factorial(0)
Calls Factorial(0) (which returns 1)
x == 0 so return 1
重要的一点是,递归函数必须具有终止条件,否则它将无限地调用自身(直到它用完堆栈空间)。在您的示例中,if (x == 0) return 1;
是终止条件。由于函数调用自身的参数值比调用的值少一个,最终它最终会调用自身为0,这就是递归结束的时候。
这会导致此代码出现问题。如果你使用负数进行调用,它将以递增的数字递归调用自身,并且永远不会达到0,并且最终会耗尽堆栈空间。但是如何最好地处理这个问题可能超出了你的问题的范围。
答案 1 :(得分:2)
递归的概念并不仅限于任何特定语言。该函数自称的背后的想法。
让我们考虑你的例子:阶乘函数。但是现在让我们把实现放在一边,用更抽象的术语来思考它。该功能由两个元素组成:
i)指导如何计算元素'n'。
ii)指导如何计算初始元素
那么我们如何计算因子的元素n
?我们选择n
并将其乘以前一个元素的阶乘:n-1
:
n * Factorial(n-1)
并且只有一个初始项目:0
。那是n == 0
结果为1
或换句话说Factorial(0)
给出1
。
您提供的算法实际上包含这两个步骤
if (x == 0)
return 1; // Do this when calculating Factorial of 0
else
return x * Factorial (x-1); // Do this when calculating an element n
确定。现在当我们想要计算4的阶乘时会发生什么?让我们分解为具体的步骤。
Factorial(4) -> 4 * Factorial(4-1) -> 4 * Factorial(3)
我们调用了4
的阶乘。所以我们将4乘以4-1的阶乘。为了获得4-1的阶乘,我们再次调用阶乘函数:
Factorial(3) -> 3 * Factorial(3-1) -> 3 * Factorial(2)
现在我们需要计算2的阶乘。
Factorial(2) -> 2 * Factorial(2-1) -> 2 * Factorial(1)
和1
Factorial(1) -> 1 * Factorial(1-1) -> 1 * Factorial(0)
注意,现在我们必须计算阶乘为0.但是这里我们有一个特殊的指令:如果参数为0,结果必须是1.让我们回过头计算:
Factorial(0)
是1.将计算结果替换为阶乘1。
Factorial(1) -> 1 * Factorial(1-1) -> 1 * 1
也是1
Factorial(2) -> 2 * Factorial(1) -> 2 * 1 -> 2
Factorial(3) -> 3 * Factorial(2) -> 3 * 2 -> 6
Factorial(4) -> 4 * Factorial(3) -> 4 * 3 -> 12
您提到了以下解释:
每次进入该方法时,都会在堆栈上分配一个新的int, 每次退出时,都会释放出int。
当我们进入Factorial
函数来计算前一个数字的阶乘时,这些步骤是必须在堆栈上分配新的int时:对于阶乘4,数字4进入堆栈并且算法计算阶乘3,依此类推。
当我们到达0的阶乘结束时,我们终于可以开始取消分配数字了。我们得到因子0,将结果乘以1.返回1的因子,并且1被解除分配。同样的情况发生在2,3和最后4。
希望澄清整个概念。我知道解释是广泛的,但另一方面,在开始时把握它是很棘手的,所以我宁愿过于彻底。
答案 2 :(得分:1)
这是递归的,因为这里的陈述:
return x * Factorial (x-1);
返回x *的结果,调用Factorial(X-1)的结果......它正在调用自己来获得答案。只需返回值1,它就会在x == 0时突破循环。
但有一点需要注意,x == 0的对象是谁?答案很可能就是积累价值的循环。
答案 3 :(得分:1)
Factorial方法再次调用自身,从5开始,并递减参数(x-1),直到传递的参数x为0.
因此,对Factorial的第一次调用传递5次,第二次调用4,3,2,1,0。
完成的数学运算是:5 * 4 * 3 * 2 * 1 = 120。
答案 4 :(得分:0)
它正在做的是反复呼唤自己。
以下是有效发生的事情。
我们输入因为 x 等于5的因子,因为我们大于0,我们将我们的5乘以5 - 1即4的调用我们的自我(因子)的结果。这个递归调用我们发现我们自己用4 - 1做另一个递归调用,这是3.我们反复这样做直到我们调用Factorial 0,然后返回1.然后那1返回到递归,它将它乘以2,返回到递归,它将它乘以3,然后是下一个乘以4,然后是下一个乘以5.
最后返回1 * 2 * 3 * 4 * 5的结果,即120。
答案 5 :(得分:0)
每次打电话给Factorial都会有一个电话回复。这些是在x == 0之后展开的递归调用。
我认为如果你稍微修改你的代码,可能会更容易看到,如果只是暂时的话:
static int Factorial (int x)
{
if (x == 0) return 1;
else
{
int y = x * Factorial (x-1);
return y;
}
}
答案 6 :(得分:0)
感谢所有对我的问题的回复。我现在对这段代码的工作有了更好的理解,并且我需要在我的TO-DO列表中对递归进行更深入的研究。