【问题标题】:StackOverflowException with large lists带有大列表的 StackOverflowException
【发布时间】:2009-06-18 02:51:20
【问题描述】:

我想做一个非常简单的任务,不知何故导致程序崩溃。

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

示例 : 5, 16, 11, 3, 8, 4 -> 5, 16, 11, 4, 8, 3 当使用 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。

我 100% 确定不存在像 VS 声称的无限循环。我尝试了其他方法,例如直接获取项目范围,for 和 foreach 循环而不是 while,最终都会崩溃。数据量似乎太大了。而且它只会变得更大(高达 20,000)。

证明(?):即使这样也会使程序抛出异常: List newPath = new List(oldPath);

知道是什么原因造成的/如何解决它吗?

-来自初学者。

【问题讨论】:

    标签: c# list


    【解决方案1】:

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

    普通的旧无限循环不会导致 StackOverflowException。为此,您需要有一个不会结束的递归,直到您的堆栈耗尽为止。

    【讨论】:

      【解决方案2】:

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

      作为旁注,List 中的 6,000 个ints 不算什么。我刚刚运行了一些测试代码,它在列表中添加了多达 6700 万个整数,然后我得到了 OutOfMemoryException

      【讨论】:

        【解决方案3】:

        我可能会这样解决:

        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;
        }
        

        【讨论】:

          【解决方案4】:

          我必须同意@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();
              }
          }
          

          【讨论】:

            【解决方案5】:

            感谢您的回答,它帮助我发现了问题

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

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

            (搜索的效果在很大程度上取决于其他数千行代码给出的数据——尽管代码确实适用于较小的问题。)

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

            同时(只要需要)
            --ArrayOfParameters.Last().ShiftPath
            --换班有用吗?
            ----是 -> 退出循环
            ----否 -> 我们可以转移更多吗?
            -------是 -> 将当前参数添加到 ArrayofParameters
            -------否 -> 回溯 - 删除 ArrayOfParameters.Last()

            【讨论】:

            • 注意:使用栈数据结构。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-30
            • 2013-05-15
            • 2016-01-21
            • 2019-11-01
            相关资源
            最近更新 更多