2010-01-19 3 views
2

Так что я сам пытался реализовать quicksort, просто чтобы узнать что-то из него, но также генерирует исключение stackoverflowexception, но я не могу найти причину.Еще один Quicksort stackoverflow

Может ли кто-нибудь дать мне ключ?

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; 

     } 
+0

не это лучше всего, чтобы найти, просто давая ему некоторые небольшие данные для сортировки и шагая с отладчиком через него, чтобы увидеть, где логика неверна? – Toad

+4

Я не думаю, что любой алгоритм сортировки, основанный на создании множества коллекций и копировании множества значений, можно назвать «быстрым». Вы должны переименовать его, чтобы «медленная память» была гарантирована как можно медленнее ». – Will

+0

@reinier: Опираясь на отладчик, чтобы найти логические ошибки, довольно ленив. Иногда это неизбежно, но гораздо лучше найти ошибки без помощи отладчика. –

ответ

2

Вы не прикладывая каких-либо условий на ваших рекурсивных вызовов DoQuicksort, поэтому он никогда не зайду рекурсии, что приводит к переполнению стека. Вы должны только называть DoQuicksort в списке, если он содержит более одного элемента.

Редактировать: Как будет сказано в его комментарии, это очень медленный подход к «Quicksort». Вы должны посмотреть на алгоритмы локального разбиения, как указано в Википедии Quicksort article.

5

вы делаете бесконечный цикл прямо

DoQuickSort(great); 

вам нужен способ, чтобы выйти из этого цикла с флагом или состояния

Edit
Я добавлю что в режиме отладки с настройкой по умолчанию вы можете достичь только от 10 000 до 16 000 рекурсивных вызовов до того, как будет выбрано исключение, и от 50 000 до 80 000, когда в режиме деблокирования все зависит от фактический код выполнен.

Если вы играете с огромным количеством значений, вам может понадобиться управлять этим рекурсивным вызовом с помощью объекта Stack.

пример кода, чтобы узнать, сколько звонков перед его сбоем;
(отладка; 14210 вызова, отпустите 80,071 вызов)

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

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

Вправо - потому что стержень ставится как первая запись в 'great', поэтому вы будете каждый раз использовать один и тот же поворот. –

+0

Да, в методе DoQuickSort нет никаких проверок условий. Метод Partition достаточно умен, чтобы знать, когда прекратить работу, но этот тип проверки не выполняется в вызывающем. – Will

1

Я думаю, что одна из проблем вашего кода, что вы сохраняете значение поворота при разбиении списка. Это означает, что вы столкнетесь с ситуацией, когда все значения разделяются на большее или меньшее, а разбиение перестанет работать. Это эффективно не позволит вам разбить один из списков anylonger, поэтому условие выхода в методе Partition никогда не выполняется.

Вы должны выбрать значение поворота, удалить опорный элемент из списка (эта часть отсутствует в вашем коде), parition его в больших и меньших списках, вроде тех, (рекурсивно), а затем сцепить меньше списка , элемент поворота (это также, естественно, отсутствует в вашем коде) и больший список.

я могу опубликовать обновленный, рабочий, образец кода, но так как вы находитесь в «режиме обучения», я буду держать это в себе, пока вы не попросите его :)

+0

+1 спасибо за объяснение! –

+0

Должен ли я каждый раз удалять новое значение поворота? и добавить его снова в нужное место @ в конце раздела? Смущенный?!? –

+0

@ Тони: Я думаю, что образцы псевдокода в статье в Википедии могут выправить это для вас: http://en.wikipedia.org/wiki/Quicksort#Algorithm –