我正在计算Fibonacci序列,偶然发现了这段代码,我看了很多:
int Fibonacci (int x)
{
if (x<=1) {
return 1;
}
return Fibonacci (x-1)+Fibonacci (x-2);
}
我不明白它是如何工作的,特别是最后的返回部分:它是否再次调用Fibonacci函数?有人可以引导我完成这个功能吗?
答案 0 :(得分:16)
是的,该函数调用自身。例如,
Fibonacci(4)
= Fibonacci(3) + Fibonacci(2)
= (Fibonacci(2) + Fibonacci(1)) + (Fibonacci(1) + Fibonacci(0))
= ((Fibonacci(1) + Fibonacci(0)) + 1) + (1 + 1)
= ((1 + 1) + 1) + 2
= (2 + 1) + 2
= 3 + 2
= 5
请注意,Fibonacci函数在此处调用了9次。一般来说,天真的递归斐波纳契函数有exponential running time,这通常是一件坏事。
答案 1 :(得分:6)
这是一个recursive function的经典例子,这是一个自称的函数。
如果你仔细阅读,你会发现它会一遍又一遍地调用自己,或者 recurse ,直到它到达所谓的基本情况 ,当x <= 1
时,它将开始“回溯”并总结计算值。
以下代码清楚地打印出算法的痕迹:
public class Test {
static String indent = "";
public static int fibonacci(int x) {
indent += " ";
System.out.println(indent + "invoked with " + x);
if (x <= 1) {
System.out.println(indent + "x = " + x + ", base case reached.");
indent = indent.substring(4);
return 1;
}
System.out.println(indent + "Recursing on " + (x-1) + " and " + (x-2));
int retVal = fibonacci(x-1) + fibonacci(x-2);
System.out.println(indent + "returning " + retVal);
indent = indent.substring(4);
return retVal;
}
public static void main(String... args) {
System.out.println("Fibonacci of 3: " + fibonacci(3));
}
}
输出如下:
invoked with 3
Recursing on 2 and 1
invoked with 2
Recursing on 1 and 0
invoked with 1
x = 1, base case reached.
invoked with 0
x = 0, base case reached.
returning 2
invoked with 1
x = 1, base case reached.
returning 3
Fibonacci of 3: 3
跟踪的树状描述看起来像
fib 4
fib 3 + fib 2
fib 2 + fib 1 fib 1 + fib 0
fib 1 + fib 0 1 1 1
1 1
编写递归函数时要考虑的重要部分是:
<强> 1。照顾基本案例
如果我们在上面的示例中忘记了if (x<=1) return 1;
,会发生什么?
<强> 2。确保递归调用以某种方式向基本情况减少
如果我们不小心修改了算法以返回fibonacci(x)+fibonacci(x-1);
答案 2 :(得分:4)
返回Fibonacci(x-1)+ Fibonacci(x-2);
这非常低效。我建议采用以下线性替代方案:
unsigned fibonacci(unsigned n, unsigned a, unsigned b, unsigned c)
{
return (n == 2) ? c : fibonacci(n - 1, b, c, b + c);
}
unsigned fibonacci(unsigned n)
{
return (n < 2) ? n : fibonacci(n, 0, 1, 1);
}
斐波那契序列可以在函数式语言中更简洁地表达。
fibonacci = 0 : 1 : zipWith (+) fibonacci (tail fibonacci)
> take 12 fibonacci
[0,1,1,2,3,5,8,13,21,34,55,89]
答案 3 :(得分:3)
这是经典的函数递归。 http://en.wikipedia.org/wiki/Recursive_function应该让你入门。基本上如果x小于或等于1则返回1.否则它会减少x在每一步运行Fibonacci。
答案 4 :(得分:3)
由于你的问题标记为C ++,我觉得有必要指出,如果你有一个编译时变量可以在编译时使用它,这个函数也可以在编译时实现。
template<int N> struct Fibonacci {
const static int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
};
template<> struct Fibonacci<1> {
const static int value = 1;
}
template<> struct Fibonacci<0> {
const static int value = 1;
}
自从我写这篇文章以来已经有一段时间了,所以它可能会有点过时,但应该是它。
答案 5 :(得分:2)
是的,再次调用Fibonacci函数,这称为递归。
就像你可以调用另一个函数一样,你可以再次调用相同的函数。由于函数上下文是堆叠的,因此可以调用相同的函数而不会干扰当前执行的函数。
请注意,递归很难,因为您可以无限地再次调用相同的函数并填充调用堆栈。这个错误称为“堆栈溢出”(这里是!)
答案 6 :(得分:1)
在C和大多数其他语言中,允许函数像任何其他函数一样调用自身。这称为递归。
如果它看起来很奇怪,因为它与您要编写的循环不同,那么你是对的。这不是一个非常好的递归应用,因为找到 n 的Fibonacci数需要两倍的时间来找到 n -1th,导致中的运行时指数>名词的
迭代Fibonacci序列,记住之前的Fibonacci数字,然后继续下一步将 n 中的运行时间改为线性,应该是这样。
递归本身并不可怕。实际上,我刚刚描述的循环(以及任何循环)可以实现为递归函数:
int Fibonacci (int x, int a = 1, int p = 0) {
if ( x == 0 ) return a;
return Fibonacci( x-1, a+p, a );
} // recursive, but with ideal computational properties
答案 7 :(得分:0)
或者,如果你想更快,但使用更多内存,请使用此功能。
int *fib,n;
void fibonaci(int n) //find firs n number fibonaci
{
fib= new int[n+1];
fib[1] = fib[2] = 1;
for(int i = 3;i<=n-2;i++)
fib[i] = fib[i-1] + fib[i-2];
}
并且对于例如n = 10,您将拥有: fib [1] fib [2] fib [3] fib [4] fib [5] fib [6] fib [7] fib [8] fib [9] fib [10] 1 1 2 3 5 8 13 21 34 55``