Quicksort - это концептуально два цикла: внутренний цикл разделения, который повторяется по всему массиву, и внешний цикл деления, обычно выражаемый через рекурсию.Здесь у вас есть часть деления, выполненная классическим способом, но ваше разбиение немного сложнее.
Ваш внешний цикл for
перемещает счетчик на один шаг влево (при условии, что вы записываете массив слева направоправо).Ваша внутренняя петля for
перемещает ось на один шаг вправо (за исключением особого случая, когда счетчик почти достиг опоры и вы совершаете последний своп).Там нет ничего, что перемещает счетчик назад вправо или поворот назад влево.Таким образом, вы не выполняете дополнительную работу из-за двух циклов, это вопрос ясности, а не эффективности.
Обычный способ записи разбиения - это использование одного цикла с двумя счетчиками вместо одного.Один счетчик тот, который вы использовали: все слева от него меньше, чем стержень.Другой счетчик играет симметричную роль: все справа от него больше, чем стержень.Тело цикла выполняет следующие действия:
, если target[left_counter]
и target[right_counter]
неуместны, меняйте их местами;после этого и target[left_counter]
, и target[right_counter]
находятся на нужной стороне массива, поэтому увеличивайте left_counter
и уменьшайте right_counter
;
в противном случае: если target[left_counter]
включенжелаемая сторона, приращение left_counter
;если target[right_counter]
находится на желаемой стороне, уменьшите right_counter
.
Цикл завершается, когда счетчики пересекаются.Это в конечном итоге завершится, потому что по крайней мере один из счетчиков перемещается на каждой итерации.