Я читал статьи, описывающие, как пространственная сложность 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 как итеративный элемент управления , который выполняет ту же задачу. Вместо того чтобы нуждаться в стеке для сохранения наборов переменных для двух рекурсивных вызовов, мы просто изменяем один и тот же набор переменных и используем один рекурсивный вызов для новых переменных.
Я не вижу, как пространство стека удваивается на каждом уровне выполнения в случае обычной быстрой сортировки.
Примечание: - В статье не упоминается оптимизация компилятора.
Эта статья не имеет смысла. Нет никакого преимущества в рекурсии только с одной стороны по сравнению с рекурсией в обоих. И BTW, показ кода не является хвостовым рекурсивным. – salva
@salva: Это не совсем точно. Есть преимущество в рекурсии с одной стороны только до тех пор, пока вы осмысленно выбираете, с какой стороны следует возвращаться. Я объяснил это в своем ответе. Между тем, версия, которая безоговорочно рекурсирует на «левой» стороне (как в коде выше), не имеет большого смысла. – AnT
Возможный дубликат [Оптимизация быстрого и хвостового рекурсивов] (http://stackoverflow.com/questions/19094283/quicksort-and-tail-recursive-optimization) –