#ruby #algorithm
#рубин #алгоритм #ruby
Вопрос:
Итак, я пытаюсь реализовать быструю сортировку в ruby, и я получаю эту ошибку `quicksort’: уровень стека слишком глубокий (SystemStackError)
def quicksort(array)
if array.length <= 1
return array
end
less = Array.new
greater = Array.new
pivot = array[array.length/2]
array.each do |x|
if x < pivot
less << x
else
greater << x
end
end
return quicksort(less) << pivot << quicksort(greater)
end
Редактировать
Я изменил else
на elsif x > pivot
, и , кажется , это работает .
Комментарии:
1. Быстрая сортировка может использовать до n уровней стека (в патологических случаях), где n — количество входных элементов. Если этот случай достигнут, то только увеличение размера стека, выбор лучшего метода сводки (который только уменьшит патологически плохие случаи) или изменение реализации быстрой сортировки исправит это. Если это происходит для небольшого числа n, то, конечно, условие терминала неверно 🙂 Какой [наименьший] входной сигнал вызывает это исключение?
2. При каких условиях вы получаете эту ошибку?
3. Я изменил else => elsif x> pivot и, похоже, это работает.
Ответ №1:
У меня ваш алгоритм работает даже на уровне 1e7, когда я генерирую массив для тестирования.
quicksort Range.new(1,1e7).to_a.shuffle
Конечно, для завершения работы потребовалось около 4,5 ГБ оперативной памяти. Что касается очистки выходных данных…
ruby-1.9.3-p0 :018 > quicksort [1,3,2] # => [1, 2, [], 3, []]
ruby-1.9.3-p0 :019 > quicksort [1,4,2,3] # => [1, 2, [3, [4]]]
Измените эту строку:
return (quicksort(less) << pivot << quicksort(greater)).flatten.compact
И это делает все намного чище.
ruby-1.9.3-p0 :037 > quicksort [1,3,2] # => [1, 2, 3]
ruby-1.9.3-p0 :038 > quicksort [1,4,2,3] # => [1, 2, 3, 4]
Ответ №2:
вам нужно было удалить pivot из массива, потому что вы добавляете его обратно позже, поэтому вместо
pivot = array[array.length/2]
вы должны были сделать
pivot = array.delete_at(array.length/2)
Ответ №3:
В ruby размер стека по умолчанию установлен довольно маленьким. Так что не так уж сложно взорвать стек, выполняя рекурсивные функции с большими наборами данных.
Самый простой способ убедиться, что вы не повторяете бесконечно, — это выполнить quicksort
на очень маленьком наборе данных. Если он все еще взрывается, вы знаете, что повторяете бесконечно.
Вы можете найти некоторую информацию о размере стека в этом сообщении, на которое отвечает Matz.
Комментарии:
1. Но размер стека в Quicksort должен оставаться очень маленьким, если реализация не прерывается на уже отсортированных данных. Размер стека будет около lg (n) — намного меньше предела любого языка сценариев, даже если массив заполняет всю память!
Ответ №4:
Ваша функция повторяется бесконечно. Используйте ruby-debug, чтобы выяснить причину.
ПРАВКА1:
Я думаю, вы хотите, чтобы последняя строка функции была такой:
return quicksort(less) quicksort(greater)