Что делает плохой случай для быстрой сортировки?

10

Я узнаю о быстрой сортировке и хочу проиллюстрировать различные массивы, для которых быстрой сортировке будет сложно. Имеющаяся в виду быстрая сортировка не имеет начального случайного перемешивания, делает 2 разбиения и не вычисляет медиану.

До сих пор я придумал три примера:

[1,2,3,4,5,6,7,8,9,10] - when the array is sorted
[10,9,8,7,6,5,4,3,2,1] - when the array is reversed
[1,1,1,1,1,1,1,1,1,1] - when the array is the same values
[1,1,1,2,2,2,3,3,3,3] - when there are few and unique keys

Например, я не слишком уверен в этом:

[1,3,5,7,9,10,8,6,4,2]

Так что же делает массив с быстрой сортировкой по сравнению с тем, где он (почти) идеален?

mrQWERTY
источник
2
Как выбирается пивот? Вы указали два способа, по которым он не был выбран, но не как он был выбран.
Уинстон Эверт
Пожалуйста, дайте наихудший случай для быстрой сортировки - когда это может произойти? на StackOverflow чтение. Я также нахожу sorting.at хорошей визуализацией алгоритмов сортировки.
@WinstonEwert Pivot выбирается первым элементом.
mrQWERTY
@ Renren29 Я немного изменил вопрос, пытаясь переместить его, чтобы сосредоточиться на причине, почему быстрая сортировка будет иметь трудности с заданным массивом, вместо того, чтобы искать примеры массивов (я не хочу, чтобы люди давали вам ответы, [2,1,2,1,2,1,2,1]и это в целом ответ). В идеале целью этого вопроса будет то, куда другие люди могут прийти и узнать больше о причинах (у которых есть ответ), а не о примерах (которых существует бесчисленное множество).
Вы запускаете быструю сортировку на куски из 2 элементов? Потому что в реальных реализациях, как правило, используются более простые сортировки для маленьких кусков. Например, сравнение и замена намного проще, чем быстрая сортировка для N = 2.
MSalters

Ответы:

9

Каждый алгоритм сортировки имеет наихудший случай, а во многих случаях наихудший случай действительно плохой, поэтому его стоит проверить. Проблема в том, что не существует ни одного худшего случая только потому, что вы знаете основной алгоритм.

Распространенные наихудшие случаи: уже отсортированы; отсортировано в обратном порядке; почти отсортирован, один элемент не в порядке; все значения одинаковы; все равно кроме первого (или последнего) выше (или ниже). Когда-то у нас был такой случай, когда наихудшим случаем был конкретный пилообразный паттерн, который было очень трудно предсказать, но довольно распространенный на практике.

Наихудший случай для быстрой сортировки - тот, который заставляет ее всегда выбирать наихудший возможный круг, так что один из разделов имеет только один элемент. Если pivot - это первый элемент (неправильный выбор), то худшие случаи - это уже отсортированные или обратно отсортированные данные. Для медианы из трех сводных данных, которые все одинаковы или только первое или последнее отличается, делает трюк.


Для быстрой сортировки средняя сложность равна nlogn, а худший - n ^ 2. Причина, по которой стоит вызывать поведение в худшем случае, заключается в том, что это также тот случай, который дает наибольшую глубину рекурсии. Для простой реализации глубина рекурсии может быть n, что может вызвать переполнение стека. Тестирование других экстремальных ситуаций (в том числе в лучшем случае) может оказаться целесообразным по аналогичным причинам.

david.pfx
источник
Понятно, поэтому стандартное отклонение от среднего действительно определяет результат разбиения.
mrQWERTY
«... и почти в каждом случае наихудший случай действительно плохой, поэтому его стоит проверить». , Это спорно. Когда я смотрю на эту таблицу: en.wikipedia.org/wiki/… я делаю вывод, что для большинства «хороших» алгоритмов сортировки (т. Е. Со средней O(NlogN)производительностью или лучше) худшие и средние случаи имеют одинаковую сложность. Это говорит о том, что обычно не стоит тестировать наихудшие случаи. (Учитывая, что тест, вероятно, O(N)... или хуже.)
Стивен С.
@ Renren29: Медиана 3 пивота будет первой или последней, только если 2 или 3 значения совпадают. SD не входит в это.
david.pfx
@StephenC: Многие «хорошие» алгоритмы, включая быструю сортировку, имеют n ^ 2 сложности в худшем случае. Но смотрите редактировать.
david.pfx
@ david.pfx - "Некоторые" ... ДА. «Почти каждый» ... НЕТ.
Стивен С.
0

Алгоритм выходит из большинства плохих случаев с использованием рандомизированной сводки, исключающей непрерывные элементы, равные сводке от разбиения, и асимметричного поиска. Он ищет элемент больше или равен точке поворота и ищет элемент назад меньше точки поворота.
Я благодарю MichaelT, Асимметричный поиск разработан для разрешения [2,1,2,1,2,1,2,1].

Следующий результат генерируется моей функцией qsort_random (). N = 100 000

usec    call   compare   copy    pattern
80132   62946  1971278   877143  random
47326   57578  1606067   215155  sorted : 0,1,2,3,...,n-1
49927   63578  1628883   338715  sorted in reverse : n-1,n-2,...,2,1,0
55619   63781  1596934   377330  nearly reverse : n-2,n-1,n-4,n-3,...,2,3,0,1
54714   66667  1611454   290392  median-3-killer : n-1,0,1,2,...,n-2
1491    1      99999     4       all values the same : n,n,n,...
1577    1      99999     4       first is higher : n,1,1,1,...
2778    2      156159    10      last is lower : n,n,n,...,n,1
2994    3      199996    100009  a few data : n,...,n,1,...,1
3196    3      199996    50012   zigzag : n,1,n,1,...,n,1
917796  56284  67721985  673356  valley(sawtooth?) : n-1,n-3,...,0,...,n-4,n-2

Большинство случаев быстрее, чем случайный образец. Схема долины - плохой случай для большинства опорных точек.

qsort(3)       usec = 14523   call = 0      compare = 884463    copy = 0
qsort_head()   usec = 138609  call = 99999  compare = 8120991   copy = 1214397
qsort_middle() usec = 664325  call = 99999  compare = 52928111  copy = 1036047
qsort_trad()   usec = 118122  call = 99999  compare = 6476025   copy = 1337523
qsort_random() usec = 295699  call = 58806  compare = 19439952  copy = 732962
qsort_log2()   usec = 66411   call = 63987  compare = 1597455   copy = 944821

qsort_log2 () выходит из плохого случая, выбирая стержень в элементах log2 (N).
qsort (3) использует библиотеку GNU, которая является сортировкой индекса слиянием.
qsort_trad () выбирает стержень в первом, среднем и последнем элементах.
qsort_random () и qsort_log2 () не используют обмен.
Программы и скрипты Source C размещены на github .

Леорге Такеучи
источник