递归调用两次相同的方法

时间:2008-12-26 00:55:06

标签: c# .net fibonacci

在Fibonacci序列中,我看到了传统的实现,它们递归地调用了两次相同的方法:

public void fibonacci(int i)
{
fibonacci(1) + fibonacci(2);
}

现在这个方法不是我所看到的或者解决问题的正确方法的确切副本,但我已经看到了两个方法如上所述加在一起。因此,该方法不是递归调用的,而是递归调用两次。在C#中编写这样的代码到底发生了什么?这两种方法是在单独的线程上运行的吗?引擎盖下发生了什么?

4 个答案:

答案 0 :(得分:8)

不,他们被称为一个接一个。除非您明确要求(使用System.Threading的东西),否则不会创建其他线程。我不确定他们的命令是什么,但我猜是从左到右。 C#规范肯定有它。

答案 1 :(得分:5)

这是考虑计算机运行方式的有用时间之一。

让我们从这个功能开始吧。我将用Python风格的伪代码编写它,因为我希望你不要再考虑LANGUAGE了一秒钟。

def fib(n):
    if n == 0: return 0
    if n == 1: return 1
    if n >  1: return fib(n-2) + fib(n-1)

现在让我们来看看fib(2)

fib(2) n> 1 ,所以需要第三个分支,

   return fib(2-2) + fib(2-1)

所以它用0调用 fib(),这是0

   return 0 + fib(2-1)

使用1

调用 fib()
   return 0 + 1

我们看到结果1.现在考虑fib(3):

n> 1,所以

return fib(3-2)+fib(3-1)

并且由于3-2是1,我们得到第一项的fib(1),即1:

return 1 + fib(3-1)

现在我们称之为fib(3-1),也就是说fib(2),我们还没有直接回答; N'大于1。所以它变成

return 1 +
    return fib(2-2) + fib(2-1)

成为

    return 0 + 1

我们回到之前的电话

return 1 + 1

并获取值2.所以,你看,没有单独的线程,它只是在表达式中运行。我将把它作为练习来制定一个例子(4);我打赌,如果你这样做,你会把它钉在上面。

流行测验:为什么是迭代版本,效率会大大提高?

答案 2 :(得分:0)

它们是有序的。即在fibonacci(1)之前评估fibonacci(2)。如果你想要将它可视化,那就是在第二个调用树之前进行调整(使用它自己的“拆分递归”),然后再回到第二个调用树。

另外,这通常用作如何使用递归的示例,因为它是评估斐波那契序列的一种明显但低效的方式。首选方案是迭代方法(计算出第一个数字,然后是下一个数字等,直到所需数字),或者更好的是闭合形式方程。

答案 3 :(得分:0)

在C#中,您可以按照建议轻松实现该方法 - 它可能看起来像这样

public static int Fib(int i) {
   if (i == 0) return 0;
   if (i == 1) return 1;
   return Fib(i - 2) + Fib(i - 1);
}

然而,这里没有魔力。它只是一次递归调用,然后是另一次。即所有代码在同一个线程上顺序运行。

由于每次迭代的两次递归调用,性能也非常糟糕,因此即使对于非常小的i值,此实现也可能没用。如果你需要性能,最好通过自己处理状态来避免递归调用。