这个C ++代码有什么问题

时间:2013-10-10 10:38:21

标签: c++

有人可以告诉我以下代码是否有问题... 在一个问题中,我被问到以下斐波纳契数函数是否有任何问题。

int fib(int n)
{
  if (n <= 1) return n;
  return fib (n-1) + fib(n-2);
}

其中n为0 ... 100

所以我的回答是什么,因为我看不到任何明显的东西。语法似乎很好,逻辑上这是计算斐波那契数。我做出这个假设是否正确?

2 个答案:

答案 0 :(得分:7)

这取决于您询问的问题类型。我在这里看到两个问题:

  • 递归。没有理由。只需使用迭代。
  • 范围溢出。 int类型无法保存范围[0,100]
  • 中的所有斐波那契数字

这是在Python中使用迭代进行fib实现的一个例子(仅仅因为它可以将fib(100)保留在盒子外面):

In [16]: def fib(n):
   ....:     curr, next = 0, 1
   ....:     for x in range(n):
   ....:         curr, next = next, curr
   ....:         next += curr
   ....:     return curr
   ....: 

In [17]: fib(100)
Out[17]: 354224848179261915075L

答案 1 :(得分:3)

很抱歉,如果答案太晚了,你还应该研究这个函数的复杂性,以便更好地理解为什么它不能正常工作。

因为对于函数的每个吸引力,您调用 fib(n-1) fib(n-2) fib执行的操作数(n)将在 2 ^ n 附近。检查以下程序,该程序计算 fib()被调用的次数:

#include <iostream>
using namespace std;

int cnt = 0;

int fib(int n) {
    cnt++;
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}

int main() {
    cout << fib(15) << '\n';
    cout << cnt << '\n';
}

因此,如果您想调用 fib(100),它将执行大约 10 ^ 18 操作,并假设您的计算机很快就会使 1秒中的> 10 ^ 9 操作,完成此操作需要 33年

但是这会更早地导致堆栈溢出错误。

fib(100)确实会超过 19位,这是(aprox。) long long 可以保留,但这不是您的功能 “sticky”的主要原因

这里有一个好的(也许是最好的)替代方案就像@soon上面所说的那样,使用迭代函数/算法,它具有线性复杂度(你的函数)是指数,请阅读更多here)。

以下是使用 C ++ 中的大数字实现的斐波那契函数代码(实际上还有更多 C ,但是,无论如何):

#include <iostream>
using namespace std;

const int maxsize = 10000; // number of digits
int n;

// note that the digits are keep reversed in the vector
// the bigsum function is as you would use add in math
// a = a + b
void bigsum(int a[], int b[]) { // in a[0] I hold the number of digits of 'a'
    int i, t = 0;
    for (i = 1; i <= a[0] || i <= b[0] || t; ++i) { // while you still have digits to add
        t = t + a[i] + b[i]; 
        a[i] = t % 10;
        t /= 10;
    }
    a[0] = i - 1; // the new a[0]
}

int zero[maxsize];

// a = b
void copy(int a[], int b[]) {
    for (int i = 0; i <= b[0]; ++i) {
        a[i] = b[i];
    }
}

void fib(int n) {
    if (n < 0) {
        cout << "NA";
    } else if (n == 0) {
        cout << 0;
    } else if (n == 1 || n == 2) {
        cout << 1;
    } else if (n == 3) {
        cout << 2;
    } else {
        int first[maxsize], second[maxsize], third[maxsize];
        copy(first, zero); copy(second, zero); copy(third, zero);
        first[0] = first[1] = second[0] = second[1] = 1; // initializing the numbers with 1
        third[0] = 1; third[1] = 2; // initializing with 2

        for (int i = 4; i <= n; ++i) {
            copy(first, second);
            copy(second, third); // if you don't understand why these 3, try to do it on a paper
            bigsum(third, first);
        }

        for (int i = third[0]; i >= 1; --i) { // because the digits are reversed
            cout << third[i];
        }
    }
    cout << '\n';
}

int main() {
    cin >> n;
    fib(n);
}

现在 fib 功能适用于更高的数字( 10000 数字,如果您想要更高,只需更改 maxsize 值)和总数操作是 n * NUMBER_OF_DIGITS ,大​​约是 n ^ 2 (小于 2 ^ n )。

另一个非常好的解决方案是使用 2x2矩阵,它允许您计算aprox中的余数 fib(n)%SOME_NUMBER log2(n)操作(您可以通过平方“使用”取幂,参见this)。阅读有关矩阵解决方案here的更多信息。

总之,你的程序不好,因为它以指数复杂度运行,并且它使用了太多的堆栈内存(即使它返回正确的值)。

希望您现在了解您的功能问题。如果这篇文章不应该在这里,请再次抱歉。

一切顺利!