具有大型列表的StackOverflowException

时间:2009-06-18 02:51:21

标签: c# list

我想做的任务很简单,不知何故会让程序崩溃。

我有一个包含在其中的数字列表,都是唯一的。过了一定数,我想颠倒顺序。

示例:5,16,11, 3,8,4 - >使用3作为支点时,5,16,11, 4,8,3

以下是我尝试过的众多方法之一。

private List<int> ShiftPath(List<int> oldPath, int shift)
{
    List <int> newPath = new List<int>();
    int counter = 0;
    // Start reordering
        // Forwards
    while (oldPath[counter] != shift)
    {
        newPath.Add(oldPath[counter]);
        counter++;
    }
        // Backwards
    counter = oldPath.Count - 1;
    while (oldPath[counter] != shift)
    {
        newPath.Add(oldPath[counter]);
        counter--;
    }
        // New endpoint
    newPath.Add(shift); 

    // Update

    return newPath;
}

现在这个有效。它可能不是最佳解决方案,但它确实有效。我已经使用这种方法已经有一段时间了,但是现在我已经达到了列表中的项目数量变得非常大(超过6,000)的程度。最后,当我尝试向newPath添加内容时,我得到了一个StackOverFlowException。

我百分百肯定没有像VS声称的无限循环。我已经尝试过其他方法,例如直接获取项目范围,for和foreach循环而不是while,最终都会崩溃。似乎数据量太大了。而且它会变得更大(超过20,000)。

证明(?):即使这会使程序抛出异常:List&lt; int&gt; newPath = new List&lt; int&gt;(oldPath);

有关导致此问题/如何解决问题的任何想法?

- 从初学者开始。

5 个答案:

答案 0 :(得分:3)

堆栈溢出不能出现在您向我们展示的代码中,因为那里没有递归。查找代码执行递归的位置。更好的是,当您获得StackOverflowException时,您获得的堆栈跟踪是什么?这将告诉你在递归中你的代码将进入无限递归循环。

普通的旧无限循环不会导致StackOverflowException。为了实现这一点,您需要进行不会结束的递归,直到堆栈耗尽为止。

答案 1 :(得分:2)

StackOverflowException没有出现,因为List中的项目太多(可能是OutOfMemoryException),当你进行太多的方法调用时会发生这种情况,通常是因为递归。

作为旁注,int中的6,000 List s无效。我刚刚运行了一些测试代码,在获得OutOfMemoryException之前,它在列表中添加了多达6700万个整数。

答案 2 :(得分:0)

我可能会解决这个问题:

List<int> reverseMe = new List<int>();
List<int> reversedList = new List<int>();

reverseMe.Add(5);
reverseMe.Add(16);
reverseMe.Add(11);
reverseMe.Add(3);
reverseMe.Add(8);
reverseMe.Add(4);

int pivotPoint = 3;

for (int c = 0; c < reverseMe.Count; c++)
{
    if (c >= pivotPoint)
    {
        reversedList.Add(reverseMe[reverseMe.Count - c + pivotPoint - 1]);
    }
    else
    {
        reversedList.Add(reverseMe[c]);
    }
} 

这使用原始列表空间的两倍,但是20k并不是真正的问题,对我来说至少它更具可读性 - 并且不应该遇到任何StackOverflow异常

修改我的算法(不像第一个那样经过测试,并且没有多少想法进入计算for条件的最佳方法)

int temp;
for (int c2 = pivotPoint; c2 < reverseMe.Count - ((reverseMe.Count - pivotPoint) / 2); c2++)
{
    temp = reverseMe[reverseMe.Count - c2 + pivotPoint - 1];
    reverseMe[reverseMe.Count - c2 + pivotPoint - 1] = c2;
    reverseMe[c2] = temp;
}

答案 3 :(得分:0)

我必须同意@Eddie - 看起来你没有向我们展示导致堆栈溢出的代码 - 你向我们展示的代码不会导致堆栈溢出。

使用.NET 3.5的另一种解决方案:

class Program
{
    static void Main(string[] args)
    {
        const int where = 5;
        var aList = new List<int>();
        for (var i=0; i < 100; i++)
            aList.Add(i);

        var reversed = aList.Take(where).Concat(Enumerable.Reverse(aList)
            .Take(aList.Count - where));

        Console.WriteLine(String.Join(",",
            reversed.Select(i => i.ToString()).ToArray()));
        Console.ReadLine();
    }
}

答案 4 :(得分:0)

感谢您的回答,这有助于我确定问题

之前我确实有一个递归。但我肯定它不是无限的(这就是为什么我不认为这是问题,特别是因为它不是溢出发生的地方)。它大致可以描述为:

搜索(参数)
--SomeParameters.ShiftPath
- 转移有用吗?
----是 - &gt;退出递归
----否 - &gt;我们可以转移更多吗?
------是 - &gt;搜索(新参数)
------否 - &gt;回溯

(搜索的效果在很大程度上取决于数千个其他代码行提供的数据 - 但代码确实适用于较小的问题。)

因为在找到答案之前它可以非常深入,我想这是导致溢出的原因吗?所以我想我会尝试另一种方法,比如使用堆:

虽然(只要需要)
--ArrayOfParameters.Last()。ShiftPath
- 转移有用吗?
----是 - &gt;退出循环
----否 - &gt;我们可以转移更多吗?
-------是 - &gt;将当前参数添加到ArrayofParameters
-------否 - &gt; Backtrack - 删除ArrayOfParameters.Last()