使用递归方法调用的因子计算

时间:2014-12-05 01:15:19

标签: c# recursion factorial

这段代码来自于书:" 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);
}

7 个答案:

答案 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列表中对递归进行更深入的研究。