另一个Quicksort stackoverflow

时间:2010-01-19 13:04:31

标签: c# quicksort stack-overflow

所以我一直在努力实现一个快速入口,只是为了从中学到一些东西,但它也会产生一个stackoverflowexception,但我似乎无法找到原因。

有人能给我一些线索吗?

  public void Partition(List<int> valuelist, out List<int> greater, out List<int> lesser)
        {
            lesser = new List<int>();  // <-- Stackoverflow exception here!
            greater = new List<int>();

            if (valuelist.Count <= 1)
                return;

            pivot = valuelist.First();

            foreach (int Element in valuelist)
            {
                if (Element <= pivot)
                    lesser.Add(Element);
                else
                    greater.Add(Element);
            }
        }

        public List<int> DoQuickSort(List<int> list)
        {
            List<int> great;
            List<int> less;

            Partition(list, out great, out less);

            DoQuickSort(great);
            DoQuickSort(less);

            list.Clear();
            list = (List<int>)less.Concat(great);

            return list;

        }

3 个答案:

答案 0 :(得分:5)

你正在那里做一个无限循环

  DoQuickSort(great);

你需要一种方法来摆脱带有标志或条件的循环

修改
我将在调试模式中添加默认设置,在抛出异常之前只能达到10,000到16,000之间的递归调用,在释放模式下只能达到50,000到80,000之间,所有这些都取决于执行的实际代码。

如果您使用大量值,则可能需要使用Stack对象来管理自己的递归调用。

示例代码,查看崩溃前的调用次数;
(调试; 14,210通话,发布80,071通话)

   static int s = 1;
    static void Main(string[] args)
    {
        o();
    }

    static void o()
    {
        s++;
        Console.WriteLine(s.ToString());
        o();
    }

答案 1 :(得分:2)

您没有对DoQuicksort的递归调用设置任何条件,因此它将永远不会停止递归,从而导致堆栈溢出。如果它包含多个元素,您应该只在列表上调用DoQuicksort

编辑正如威尔在评论中所说,对于“Quicksort”来说这是一个非常缓慢的方法。您应该查看就地分区算法,如维基百科的Quicksort article所述。

答案 2 :(得分:1)

我认为代码中的一个问题就是在分区列表时保留了透视值。这意味着您将遇到所有值分区为更大或更小的情况,并且分区将停止工作。这实际上不会让你拆分其中一个列表,因此永远不会满足分区方法中的退出条件。

您应该选择一个数据透视值,从列表中移除数据元素(代码中缺少此部分),将其分成更多和更少的列表,对它们进行排序(递归),然后连接较少的列表,枢轴元素(当然,代码中也缺少这个元素)和更大的列表。

我可以发布一个更新的,有效的代码示例,但由于你处于“学习模式”,我会自己保留它直到你要求它:)