В приведённой реализации быстрой сортировки на Python найдите и объясните ошибку, оцените сложность алгоритма и предложите исправленный вариант: def quicksort(a): if len(a) <= 1: return a pivot = a[len(a)//2] left = [x for x in a if x pivot] return quicksort(left) + middle + quicksort(middle)
Ошибка - В строке возврата используется рекурсивный вызов для `middle` вместо `right`. Из-за этого при наличии более одного элемента, равного опорному, алгоритм рекурсивно вызывает `quicksort(middle)` бесконечно. Пример: a=[2,2,2]a=[2,2,2]a=[2,2,2], опорный элемент pivot=2pivot=2pivot=2, тогда left=[]left=[]left=[], middle=[2,2,2]middle=[2,2,2]middle=[2,2,2], right=[]right=[]right=[]. Условие len(a)≤1len(a)\le 1len(a)≤1 не выполняется, и вызов `quicksort(middle)` повторяет ту же ситуацию бесконечно. Сложность - Средняя временная: O(nlogn)O(n\log n)O(nlogn). - Худшая временная (плохой выбор опорного): O(n2)O(n^2)O(n2). - Дополнительная память: O(n)O(n)O(n) (создаются новые списки). - Глубина рекурсии: в среднем O(logn)O(\log n)O(logn), в худшем случае O(n)O(n)O(n). Исправленный вариант (минимальное исправление) def quicksort(a): if len(a) <= 1: return a pivot = a[len(a)//2] left = [x for x in a if x < pivot] middle = [x for x in a if x == pivot] right = [x for x in a if x > pivot] return quicksort(left) + middle + quicksort(right) Замечания и улучшения - Для устойчивого избежания худшего случая выбирайте случайный или медианный по трём пунктов pivot. - Для экономии памяти можно реализовать быструю сортировку in-place (разбиение Хоара).
- В строке возврата используется рекурсивный вызов для `middle` вместо `right`. Из-за этого при наличии более одного элемента, равного опорному, алгоритм рекурсивно вызывает `quicksort(middle)` бесконечно. Пример: a=[2,2,2]a=[2,2,2]a=[2,2,2], опорный элемент pivot=2pivot=2pivot=2, тогда left=[]left=[]left=[], middle=[2,2,2]middle=[2,2,2]middle=[2,2,2], right=[]right=[]right=[]. Условие len(a)≤1len(a)\le 1len(a)≤1 не выполняется, и вызов `quicksort(middle)` повторяет ту же ситуацию бесконечно.
Сложность
- Средняя временная: O(nlogn)O(n\log n)O(nlogn).
- Худшая временная (плохой выбор опорного): O(n2)O(n^2)O(n2).
- Дополнительная память: O(n)O(n)O(n) (создаются новые списки).
- Глубина рекурсии: в среднем O(logn)O(\log n)O(logn), в худшем случае O(n)O(n)O(n).
Исправленный вариант (минимальное исправление)
def quicksort(a):
if len(a) <= 1:
return a
pivot = a[len(a)//2]
left = [x for x in a if x < pivot]
middle = [x for x in a if x == pivot]
right = [x for x in a if x > pivot]
return quicksort(left) + middle + quicksort(right)
Замечания и улучшения
- Для устойчивого избежания худшего случая выбирайте случайный или медианный по трём пунктов pivot.
- Для экономии памяти можно реализовать быструю сортировку in-place (разбиение Хоара).