Имея достаточно большие массивы, вы в конечном итоге достигнете максимального размера стека и получите это исключение. Причина, по которой вы видите это на отсортированных массивах ранее, заключается в том, как вы выбираете свою опору.
Вы реализовали его с вашим сводным элементом как последним элементом массива, что означает, что ваш худший сценарий происходит, когда вы получаете отсортированный массив. Ваше значение поворота всегда является наибольшим значением (или наименьшим, если оно отсортировано в противоположном направлении), и, таким образом, каждый элемент меньше, чем ось, и ни один из них не больше. Таким образом, вместо того, чтобы разбивать массив на два примерно одинаковых подмассива, вы разбиваете его на один подмассив, который имеет только на один элемент меньше, чем вы начали.
Один из способов выбрать опору, чтобы избежать этого, состоит в том, чтобы выбрать опору случайным образом. Это делает маловероятным (но не невозможным) попадание в худший вариант, и поэтому в среднем будет работать хорошо. У него есть уязвимость, заключающаяся в том, что если кто-то знает алгоритм случайных чисел и начальное число, которое вы используете, то он может создать массив, который приведет вас к худшему случаю.
Идеальной опорой является среднее значение. Поэтому один из подходов - попытаться найти медиану или приблизиться к ней. Например, вы можете взять выборку из 3 случайных элементов массива и использовать медиану этих 3 в качестве своей оси. Это вряд ли будет точно медиана, но достаточно хорошо в большинстве случаев. Вы можете выбрать больше, чтобы получить лучшее приближение к медиане, но затем вы тратите больше времени на поиск точки, чем просто продвигаясь вперед по алгоритму; это немного компромисс.