【问题标题】:Recursive Fibonacci递归斐波那契
【发布时间】:2010-12-03 20:58:30
【问题描述】:

我很难理解为什么

#include <iostream>

using namespace std;

int fib(int x) {
    if (x == 1) {
        return 1;
    } else {
        return fib(x-1)+fib(x-2);
    }
}

int main() {
    cout << fib(5) << endl;
}

导致分段错误。一旦 x 降到 1,它最终不应该返回吗?

【问题讨论】:

  • 这个算法的时间复杂度是O(2^n)。太糟糕了。例如,f(30) 计算需要大约 10 亿次操作。在您的情况下使用动态编程。
  • @Alexey,我确定 OP 只是想学习。如果性能是一个问题,元编程确实是要走的路。
  • @Alexey Malistov:不,改用迭代方法。
  • @Gumbo:不,用力卢克!
  • 我喜欢开玩笑(或不开玩笑)这个算法的时间复杂度是 O(fib(n))。

标签: c++ recursion fibonacci


【解决方案1】:

我认为所有这些解决方案都是低效的。它们需要大量递归调用才能得到结果。

unsigned fib(unsigned n) {
    if(n == 0) return 0;
    if(n == 1) return 1;
    return fib(n-1) + fib(n-2);
}

此代码需要 14 次调用才能获得 fib(5) 的结果,fin(10) 需要 177 次调用,fib(30) 需要 2.7kk。

你最好使用this 方法,或者如果你想使用递归试试这个:

unsigned fib(unsigned n, unsigned prev1 = 0, unsigned prev2 = 1, int depth = 2)     
{
    if(n == 0) return 0;
    if(n == 1) return 1;
    if(depth < n) return fib(n, prev2, prev1+prev2, depth+1);
    return prev1+prev2;
}

此函数需要 n 次递归调用来计算 n 的斐波那契数。您仍然可以通过调用 fib(10) 来使用它,因为所有其他参数都有默认值。

【讨论】:

    【解决方案2】:

    我认为这是使用递归的最佳斐波那契解决方案。

    #include<bits/stdc++.h>
    typedef unsigned long long ull;
    typedef long long ll;
    ull FIBO[100005];
    using namespace std;
    ull fibo(ull n)
    {
        if(n==1||n==0)
            return n;
        if(FIBO[n]!=0)
            return FIBO[n];
        FIBO[n] = (fibo(n-1)+fibo(n-2));
        return FIBO[n];
    }
    int main()
    {
        for(long long  i =34;i<=60;i++)
            cout<<fibo(i)<<" " ;
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      我的解决办法是:

      #include <iostream>
      
      
          int fib(int number);
      
          void call_fib(void);
      
          int main()
          {
          call_fib();
          return 0;
          }
      
          void call_fib(void)
          {
            int input;
            std::cout<<"enter a number\t";
            std::cin>> input;
            if (input <0)
            {
              input=0;
              std::cout<<"that is not a valid input\n"   ;
              call_fib();
           }
           else 
           {
               std::cout<<"the "<<input <<"th fibonacci number is "<<fib(input);
           }
      
          }
      
      
      
      
      
          int fib(int x)
          {
           if (x==0){return 0;}
           else if (x==2 || x==1)
          {
               return 1;   
          }
      
          else if (x>0)
         {
              return fib(x-1)+fib(x-2);
          }
          else 
           return -1;
          }
      

      如果为负则返回 fib(0)=0 和错误

      【讨论】:

        【解决方案4】:

        这是我用递归解决斐波那契问题的方法。

        #include <iostream>
        using namespace std;
        
        int fibonacci(int n){
            if(n<=0)
                return 0;
            else if(n==1 || n==2)
                return 1;
            else
                return (fibonacci(n-1)+fibonacci(n-2));
        }
        
        int main() {
            cout << fibonacci(8);
            return 0;
        }
        

        【讨论】:

          【解决方案5】:

          根据定义,斐波那契数列的前两个数字是1和1,或者0和1。因此,你应该处理它。

          #include <iostream>
          using namespace std;
          
          int Fibonacci(int);
          
          int main(void) {
              int number;
          
              cout << "Please enter a positive integer: ";
              cin >> number;
              if (number < 0)
                  cout << "That is not a positive integer.\n";
              else
                  cout << number << " Fibonacci is: " << Fibonacci(number) << endl;
          }
          
          int Fibonacci(int x) 
          {
              if (x < 2){
               return x;
              }     
              return (Fibonacci (x - 1) + Fibonacci (x - 2));
          }
          

          【讨论】:

            【解决方案6】:
            if(n==1 || n==0){
                return n;
            }else{     
                return fib(n-1) + fib(n-2);
            }
            

            但是,使用递归来获取斐波那契数是不好的做法,因为调用函数的次数大约是接收到的数的 8.5 次。 例如。获得 30 的斐波那契数 (1346269) - 函数被调用 7049122 次!

            【讨论】:

              【解决方案7】:

              我认为这个解决方案很简短,看起来不错:

              long long fib(int n){
                return n<=2?1:fib(n-1)+fib(n-2);
              }
              

              编辑:正如 jweyrich 所说,真正的递归函数应该是:

              long long fib(int n){
                    return n<2?n:fib(n-1)+fib(n-2);
                  }
              

              (因为 fib(0) = 0。但基于上述递归公式,fib(0) 将为 1)

              要理解递归算法,你应该在你的论文上画画,最重要的是:“Think normal as often”。

              【讨论】:

              • fib(0) 错误地导致 1。这将解决:return x &lt; 2 ? x : fibonnaci(x-1) + fibonnaci(x-2);。这里专门针对fib(2) 的额外条件只会减慢函数的速度。
              • 通常 fibonnaci 函数 n 通过递归调用最多只能运行到大约 50。我认为其他条件不会减慢recursive call
              • 我的意思是您的fib 函数为fib(0) 返回了错误的结果。请忽略其余的:-)
              【解决方案8】:
              int fib(int x) 
              {
                  if (x < 2)
                    return x;
                  else 
                    return (fib(x - 1) + fib(x - 2));
              }
              

              【讨论】:

              • 完美!我只是删除了其他。
              【解决方案9】:
              int fib(int x) 
              {
                  if (x == 0)
                    return 0;
                  else if (x == 1 || x == 2) 
                    return 1;
                  else 
                    return (fib(x - 1) + fib(x - 2));
              }
              

              【讨论】:

              • 对这个问题也有答案吗(请参阅下面的为什么)?
              【解决方案10】:
              int fib(int n) {
                  if (n == 1 || n == 2) {
                      return 1;
                  } else {
                      return fib(n - 1) + fib(n - 2);
                  }
              }
              

              在斐波那契数列中,前 2 个数字始终为 1,然后每次值变为 1 或 2 时,它必须返回 1

              【讨论】:

                【解决方案11】:

                为什么不使用迭代算法?

                int fib(int n)
                {
                    int a = 1, b = 1;
                    for (int i = 3; i <= n; i++) {
                        int c = a + b;
                        a = b;
                        b = c;
                    }           
                    return b;
                }
                

                【讨论】:

                • 这是最好的方法。但他要求递归解决方案。
                • @Gumbo,毫无疑问,“最佳”方法是元编程。
                • 我从没说过,我知道元编程是什么,而且它根本不涉及运行时计算
                • 元编程方法基本上可以归结为递归解决方案......计算将简单地从运行时转移到编译时。声称这将是一个更好的方法是无意义的,因为我们不知道 OP 要求:如果他只需要运行一次程序,那么拥有巨大的编译时间和短的运行时间并不比拥有短的编译时间更好并且运行时间长。类似地,如果他需要将“n”参数作为输入,则元编程是不可用的(除非你明确地为这个数字设置了一个上限)。此外,编译器有一个有限的......
                • ...递归深度,所以这可能是个问题。总而言之,元编程是一个非常强大的工具,但应该明智地使用,只有当它真正适合问题时。
                【解决方案12】:

                x==2 你打电话给fib(1)fib(0):

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

                考虑评估fib(0) 时会发生什么...

                【讨论】:

                • +1 表示不直接给出答案,而是指出问题出在哪里。对于正在学习的人来说更好。
                • +1,我对我最大的孩子 (9) 使用相同的技术,它可以激发他解决问题的能力。
                【解决方案13】:

                原因是因为斐波那契数列以 两个 已知实体 0 和 1 开头。您的代码只检查其中一个(是否为一个)。

                把你的代码改成

                int fib(int x) {
                    if (x == 0)
                        return 0;
                
                    if (x == 1)
                        return 1;
                
                    return fib(x-1)+fib(x-2);
                }
                

                同时包含 0 和 1。

                【讨论】:

                • 系列不是从1,1开始的吗?
                • 这不是我所学的,也不是维基百科的建议 - en.wikipedia.org/wiki/Fibonacci_number
                • @Aviator:取决于您如何定义斐波那契数列。 ;)
                • @Spoike,@LiraNuna:谢谢 :) 现在知道了。已经看到一些以 1、1、2 等开头的实现。所以很困惑!
                • 或者将两行都改为if (x &lt;= 1) return x。 :-)
                猜你喜欢
                • 2014-04-02
                • 2017-11-18
                • 2014-01-08
                • 2011-12-14
                • 2012-11-29
                • 2018-04-10
                • 2016-02-21
                • 2012-02-15
                相关资源
                最近更新 更多