在Fibonacci序列中,我看到了传统的实现,它们递归地调用了两次相同的方法:
public void fibonacci(int i)
{
fibonacci(1) + fibonacci(2);
}
现在这个方法不是我所看到的或者解决问题的正确方法的确切副本,但我已经看到了两个方法如上所述加在一起。因此,该方法不是递归调用的,而是递归调用两次。在C#中编写这样的代码到底发生了什么?这两种方法是在单独的线程上运行的吗?引擎盖下发生了什么?
答案 0 :(得分:8)
答案 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
值,此实现也可能没用。如果你需要性能,最好通过自己处理状态来避免递归调用。