Я читал статьи, описывающие, как пространственная сложность quicksort может быть уменьшена с помощью хвостовой рекурсивной версии, но я не могу понять, как это происходит. Ниже приведены две версии:
QUICKSORT(A, p, r)
q = PARTITION(A, p, r)
QUICKSORT(A, p, q-1)
QUICKSORT(A, q+1, r)
TAIL-RECURSIVE-QUICKSORT(A, p, r)
while p < r
q = PARTITION(A, p, r)
TAIL-RECURSIVE-QUICKSORT(A, p, q-1)
p = q+1
(Источник - http://mypathtothe4.blogspot.com/2013/02/lesson-2-variations-on-quicksort-tail.html)
Насколько я понимаю, оба из них вызовут рекурсивные вызовы как в левой, так и в правой половине массива. В обоих случаях только одна половина обрабатывалась одновременно, и поэтому в любой момент только один рекурсивный вызов использовал бы пространство стека. Я не могу понять, как хвостовая рекурсивная quicksort экономит место.
Псевдо-код выше взят из статьи - http://mypathtothe4.blogspot.com/2013/02/lesson-2-variations-on-quicksort-tail.html Объяснение, приведенное в статье, меня еще больше смущает -
Quicksort разделяет данный подматрица и переходит к повторной обработке дважды; один в левой части и один справа. Каждый из них рекурсивным вызовам потребуется отдельный поток стека. Это пространство используется для хранения индексирующих переменных для массива в некоторый уровень рекурсии. Если представить, что это происходит с самого начала к завершению выполнения, мы видим, что пространство стека удваивается на каждом слой.
Итак, как Tail-Recursive-Quicksort исправить все это?
Ну, вместо того, чтобы рекурсировать на двух под-массивах, теперь мы только рекурсируем один. Это устраняет необходимость удвоения пространства стека на каждом уровне исполнения. Мы оборачиваем эту проблему, используя цикл while как итеративный элемент управления, выполняющий ту же задачу. Вместо того, чтобы стек для сохранения наборов переменных для двух рекурсивных вызовов, мы просто изменить один и тот же набор переменных и использовать один рекурсивный вызов на новые переменные.
Я не вижу, как пространство стека удваивается на каждом уровне выполнения в случае регулярной быстрой сортировки.
Примечание. - В статье не упоминается оптимизация компилятора.