为什么我超出了内存限制? C#

时间:2019-02-03 17:38:07

标签: c# memory limit fibonacci

任务是:

  1. Tribonacci序列是一个序列,其中每个下一个元素由该序列中前三个元素的总和构成。
  2. 编写一个计算机程序,查找Tribonacci序列的第N个元素(如果给定该序列的前三个元素和数字N)。
  3. 我已将约束条件包括在程序中。此问题是在系统中提交的,并且有时间限制。我在过去2种情况下都超过了内存限制。

请帮助。

        BigInteger a = BigInteger.Parse(Console.ReadLine());
        BigInteger b = BigInteger.Parse(Console.ReadLine());
        BigInteger c = BigInteger.Parse(Console.ReadLine());

        var fibonacciNumbers = new List<BigInteger> { a, b, c };
        BigInteger N = BigInteger.Parse(Console.ReadLine());    
        if ((a < -2000000000) || (b < -2000000000) || (c < -2000000000) || (a > 2000000000) || (b > 2000000000) || (c > 2000000000) || (N > 15000) || (N < 1))
        {
            throw new Exception("Argument out of range");
        }

        while (fibonacciNumbers.Count <= N)
        {
            var previous = fibonacciNumbers[fibonacciNumbers.Count - 1];
            var previous2 = fibonacciNumbers[fibonacciNumbers.Count - 2];
            var previous3 = fibonacciNumbers[fibonacciNumbers.Count - 3];
            fibonacciNumbers.Add(previous + previous2 + previous3);
        }

        Console.WriteLine((fibonacciNumbers[(int)N - 1]));

3 个答案:

答案 0 :(得分:2)

如果我们假设您需要在列表中存储以前的斐波那契结果(如果有任何目的)?

在默认配置下,即使在64位上,CLR对象的最大大小也为2GB。

您正在将斐波那契结果存储在占用内存的List中。当您达到2GB时,您将获得OutOfMemoryException

您需要超过2GB的限制。为此,您需要将gcAllowVeryLargeObjects添加到app.config

<runtime>
  <gcAllowVeryLargeObjects enabled="true" />
</runtime>

另一方面,如果您不需要斐波那契数列的所有先前值,那么

    BigInteger f2 = BigInteger.Parse(Console.ReadLine());
    BigInteger f1 = BigInteger.Parse(Console.ReadLine());
    BigInteger f = BigInteger.Parse(Console.ReadLine());

    BigInteger N = BigInteger.Parse(Console.ReadLine());    
    if ((a < -2000000000) || (b < -2000000000) || (c < -2000000000) || (a > 2000000000) || (b > 2000000000) || (c > 2000000000) || (N > 15000) || (N < 1))
    {
        throw new Exception("Argument out of range");
    }

    while (fibonacciNumbers.Count <= N)
    {
        var fn = f2 + f1 + f;

        f2 = f1;
        f1 = f;
        f = fn;
    }

    Console.WriteLine(fn);

答案 1 :(得分:1)

您不必存储所有先前的序列值,因为只需要存储最后3个数字即可计算下一个。

BigInteger prevPrev = BigInteger.Parse(Console.ReadLine());
BigInteger prev = BigInteger.Parse(Console.ReadLine());
BigInteger current = BigInteger.Parse(Console.ReadLine());

BigInteger N = BigInteger.Parse(Console.ReadLine());

for(int i = 3; i < N; i++)
{
    // calculate next number
    var next = prevPrev + prev + current;

    // shift all numbers
    prevPrev = prev;
    prev = current;
    current = next;
}

return current;

答案 2 :(得分:1)

您的代码中有一些需要注意的地方:

  • 为什么要将所有前面的数字存储到数组中。正如@Vadim Martynov已经提到的那样,您只需要前面的三个数字(不是斐波那契)。
  • 您使用BigInteger存储计数。它可能应该适合32位带符号整数,因为它已经超过20亿次迭代。使用BigInteger结构会占用太多内存。在当前程序的最后,您已经回退到int,因此此处无需使用BigInteger

如果您确实想将所有项目存储在列表中(不要问我为什么),那么请确实将列表预先分配给正确的编号(您事先知道)并使用数组,这样您就可以无需重新分配和复制的高效存储。

    var a = BigInteger.Parse(Console.ReadLine());
    var b = BigInteger.Parse(Console.ReadLine());
    var c = BigInteger.Parse(Console.ReadLine());

    var N = int.Parse(Console.ReadLine());
    if ((a < -2000000000) || (b < -2000000000) || (c < -2000000000) || (a > 2000000000) || (b > 2000000000) || (c > 2000000000) || (N > 15000) || (N < 1))
        throw new Exception("Argument out of range");

    var fibonacciNumbers = new BigInteger[N];
    fibonacciNumbers[0] = a;
    fibonacciNumbers[1] = b;
    fibonacciNumbers[2] = c;

    for (var i=3; i < N; ++i)
    {
        var previous = fibonacciNumbers[i - 1];
        var previous2 = fibonacciNumbers[i - 2];
        var previous3 = fibonacciNumbers[i - 3];
        fibonacciNumbers[i] = previous + previous2 + previous3;
    }

    Console.WriteLine(fibonacciNumbers[N - 1]);

但是最好还是不要将这些项目存储在数组/列表中。我只是想对其他问题发表评论,但是请使用@Vadim Martynov的答案。