【问题标题】:Simple code to obtain n-th number of Fibonnaci获取第n个斐波那契数的简单代码
【发布时间】:2015-12-19 11:14:08
【问题描述】:

我只是想生成一段有效的代码来获得斐波那契数列的第 n 个数字,并使用下面的代码来执行此操作。但是,我收到错误 Expression: vector subscript out of range 并且不知道为什么会发生。

int Fib(int n)
{
    vector<int> output;
    output.reserve(n);
    output[0] = 1; output[1] = 2;
    for(int i = 2; i <=n; ++i)
    {
        output.push_back(output[i-1]+ output[i-2]);
    }
return output[n];
}

【问题讨论】:

  • output.reserve(n+1) 不应该受到伤害。
  • 为什么不在固定时间内做呢? stackoverflow.com/a/19892721/382471
  • 或者让你的编译器生成它goo.gl/jfZXKY 当然,这只有在你在编译时知道你想要斐波那克系列的哪一步时才有效。

标签: c++


【解决方案1】:

原始代码为 Fib(0)(1 而不是 0)https://en.wikipedia.org/wiki/Fibonacci_number 返回无效值。

以下代码修复了这个问题和向量初始化:

int fib(int n)
{
    vector<int> output;
    output.resize(n+1);
    output.clear();
    output.push_back(0);
    output.push_back(1);

    for (int i=2; i <= n; i++)
    {
        output.push_back(output[i-1] + output[i-2]);
    }

    return output[n];
}

还有更好的实现方式,不需要使用向量:

int fib(int n) 
{
    if ( n == 0 || n == 1 ) 
        return n;

    int fib1 = 0; 
    int fib2 = 1;
    int fib = 0;

    for ( int i = 2; i < n; i++ ) 
    {
        fib = fib1 + fib2;
        fib1 = fib2;
        fib2 = fib;
    }

    return fib;
}

【讨论】:

  • “更好”,如果你想要那个并且只想要那个数字,而向量可以让你保存你的工作。虽然我想他目前是这样写的,但也许不会总是这样?只是评论。
  • 我理解你的意思,但问题是“获取斐波那契第 n 个数的代码”.. 不是整个序列
  • 是的,我在写完之后意识到......我想我会把它留在那里以防它以后变成那个。
  • 切换到resize 不足以解决此问题,因为执行了push_backs。
  • 你说得对,我忘记了 .clear() 和前两个元素
【解决方案2】:

std::vector::reserve只是容器为数据预分配存储的性能提示;它实际上并没有用n 元素填充向量。因此,当您尝试访问 output[0] = 1 之类的元素时,您访问的是不存在的元素。

您可以简单地切换到std::vector::resize,它可以满足您的需求。请注意,在 std::vector::push_back 导致算法错误之后,您应该这样做

output[n] = output[n-1] + output[n-2];

顺便说一句,这种方法效率不高,至少由于不必要的内存分配。这样的事情应该更快:

int Fib(int n)
{
    int a = 0, b = 1;
    for(int i = 0; i < n; ++i)
    {
        int t = a + b;
        a = b;
        b = t;
    }
    return a;
}

【讨论】:

    【解决方案3】:

    Reserving != Resizing

    您没有插入稍后可以使用下标operator[] 访问的默认构造元素,而是提示分配仅影响容量而不影响大小的未初始化内存 的容器。因此,以这种方式访问​​元素是无效的。

    即使是这些循环前的行也是无效的

    output.reserve(n);
    output[0] = 1; output[1] = 2;
    

    您应该使用resize() 并注意push_back 会增加向量的维度(所以要么在代码中一直使用push_backs,要么使用resize() 并使用下标访问)。

    int Fib(int n)
    { // Lacks error checking if n < 2
      vector<int> output;
      output.resize(n);
      output[0] = 1; output[1] = 2;
      for (int i = 2; i < n; ++i)
      {
        output[i] = output[i - 1] + output[i - 2];
      }
      return output[n-1];
    }
    

    额外提示

    • 如果您只对n-th 斐波那契数感兴趣,您不需要完整的带有向量的历史记录,您可以只缓存序列中的最后两个数字

      李>
    • 对于大的n,这种方法可能行不通,在对数时间内运行的更智能的方法(尽管您仍然需要做一些简单的矩阵乘法)可能是以下[Linear recurrence relations]

    【讨论】:

      【解决方案4】:

      这一行

      output.reserve(n);
      

      不会向向量中添加元素——它只是在内存中为该数量的项目保留空间。它不会用任何东西填充向量 - 您可以通过在将返回零的向量上调用 size() 来验证这一点。所以这里

      output[0] = 1; output[1] = 2;
      

      您正在尝试修改特定索引处的值 - 但这些索引处没有任何内容,并且您的索引超出了向量数组的范围(如消息所示)。在尝试读取或写入特定索引之前,您实际上应该填充向量。

      在您的情况下,只需添加

      output.push_back(1);
      output.push_back(2);
      

      在您的循环之前将解决此问题(或者使用 resize 作为其他答案的建议)。

      【讨论】:

        【解决方案5】:
        int fib()
        {
        cout<<"Enter the term";
        cin>>n;
        int f=0,f1=1,f2=0;
        for(i=1;i!=n;i++)
        {
        f=f1+f2;
        f1=f2;
        f2=f;
        }
        if(i==n)
        cout<<n<<"'th term is"<<f;
        }
        

        如果我错了,是否足够简单,请纠正我

        【讨论】:

          【解决方案6】:

          std::vector::reserve 只会增加向量的容量(即分配的空间) - 它实际上不会增加​​向量的大小(即项目数)。

          所以:

          output[0] = 1; output[1] = 2;
          

          不合法,因为您试图访问大小为 0 的向量中的前两项。

          相反,这样做:

          output.push_back(1);
          output.push_back(2); // this should probably push back 1 though, if you want the Fibonacci sequence
          

          此外,您尝试在向量中添加一个过多的项目,因此将循环更改为:

          for(int i = 2; i < n; ++i)
          

          (即使用&lt; 而不是&lt;=)。

          您还必须相应地修改 return 语句:

          return output[n - 1];
          

          【讨论】:

          • 使用这个 F(0) 将导致越界访问 --> output[-1]
          • @redobot :没有第 0 个斐波那契数这样的东西,所以调用无效。
          • 斐波那契数列的数学定义从0开始:en.wikipedia.org/wiki/Fibonacci_number
          • @redobot :它可以从索引 0 或 1 开始(如您的支持链接中所示),但在这两种情况下,您仍将其称为第一个,而不是第 0 个。
          • 是的,没错。在这种情况下,最好有支持这两种情况的代码:)
          【解决方案7】:

          你应该这样做:

          std::vector<int> output;
                  output.resize(n+1); // resize not reserv  & n+1 because the <=n
                  output[0] = 1; output[1] = 2;
                  for (int i = 2; i <= n; ++i)
                  {
                      output[i]=(output[i - 1] + output[i - 2]); // indexing not push_back
                  }
          

          顺便说一句,如果您真的想使用似乎不是最佳选择的向量,您最好执行以下操作:

          std::vector<unsigned long long> output;
          output.resize(n+1);
          output[0] = 1; output[1] = 2;
          const auto end_of_output(std::end(output));
          for (auto& it = std::begin(output) + 2; it < end_of_output; ++it){
              *it = *(it - 1) + *(it - 2);
          }
          

          【讨论】:

            【解决方案8】:

            由于您为n 变量保留了空间,因此您的向量可以被索引到n-1,而您返回output[n],从而导致错误:vector subscript out of range。要为最后一个变量留出空间,您应该使用reserve(n+1)。但是请注意,这将是n+1 斐波那契数。

            另外,vector.reserve() 将内存分配给向量而不对其进行初始化。所以你不能访问像output[0] 这样的元素。相反,您应该 push_back 索引 0 和 1 处的值(以及其他值),或者使用 vector.resize() 然后按索引访问所有元素,而不是使用 push_back

            关于resizereserve的区别的解释,参考this SO线程。

            【讨论】:

              猜你喜欢
              • 2022-12-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-10-12
              • 1970-01-01
              • 2021-09-15
              • 2015-04-17
              • 1970-01-01
              相关资源
              最近更新 更多