Когда используется каждый алгоритм сортировки? [закрыто]

170

Каковы случаи использования, когда какой-то конкретный алгоритм сортировки предпочтительнее других - сортировка слиянием, QuickSort, heapsort, intro sort и т. Д.?

Существует ли рекомендуемое руководство по их использованию в зависимости от размера, типа структуры данных, доступной памяти и кэша, а также производительности процессора?

Сэм
источник
Набор анимаций для различных типов данных и алгоритмов можно найти по адресу <a href=" sorting-algorithms.com/"> sorting-algorithms.com </ a >
Chip Uni,
2
Руководством, подобным bigocheatsheet.com для этого материала, будет greaaaat
K - токсичность в SO растет.
@ChipUni вот фиксированная ссылка: toptal.com/developers/sorting-algorithms
eric
2
Почему этот вопрос закрыт !?
Арванд

Ответы:

316

Во-первых, определение, поскольку оно очень важно: стабильная сортировка - это та, которая гарантированно не переупорядочивает элементы с одинаковыми ключами.

Рекомендации:

Быстрая сортировка: когда вам не нужна стабильная сортировка, а средняя производительность важнее, чем худшая. Быстрая сортировка - это O (N log N) в среднем, O (N ^ 2) в худшем случае. Хорошая реализация использует O (log N) вспомогательное хранилище в форме стекового пространства для рекурсии.

Сортировка слиянием: если вам нужна стабильная сортировка O (N log N), это ваш единственный вариант. Единственным недостатком является то, что он использует O (N) вспомогательное пространство и имеет немного большую константу, чем быстрая сортировка. Есть несколько видов слияний на месте, но AFAIK все они либо нестабильны, либо хуже, чем O (N log N). Даже O (N log N) на месте сортировки имеют намного большую константу, чем обычная сортировка слиянием, что они скорее теоретические курьезы, чем полезные алгоритмы.

Сортировка кучи: когда вам не нужна стабильная сортировка, и вы больше заботитесь о производительности в худшем случае, чем в среднем. Он гарантированно равен O (N log N) и использует O (1) вспомогательное пространство, что означает, что вы не будете неожиданно исчерпывать пространство кучи или стека на очень больших входах.

Introsort: это быстрая сортировка, которая переключается на сортировку кучи после определенной глубины рекурсии, чтобы обойти O (N ^ 2) наихудшего случая быстрой сортировки. Это почти всегда лучше, чем обычная старая быстрая сортировка, поскольку вы получаете средний случай быстрой сортировки с гарантированной производительностью O (N log N). Вероятно, единственная причина использовать сортировку кучи вместо этого - в системах с жестким ограничением памяти, где пространство стека O (log N) практически значимо.

Вставка сортировки : когда N гарантированно будет небольшим, в том числе в качестве базового варианта быстрой сортировки или сортировки слиянием. Хотя это O (N ^ 2), оно имеет очень маленькую константу и является устойчивой сортировкой.

Сортировка по пузырям, сортировка по выбору : когда вы делаете что-то быстрое и грязное, и по какой-то причине вы не можете просто использовать алгоритм сортировки стандартной библиотеки. Единственное преимущество, которое они имеют перед сортировкой вставок, заключается в том, что их немного проще реализовать.


Несопоставимые сортировки: при некоторых довольно ограниченных условиях можно преодолеть барьер O (N log N) и отсортировать по O (N). Вот несколько случаев, когда стоит попробовать:

Подсчет сортировки: когда вы сортируете целые числа с ограниченным диапазоном.

Сортировка по корням: когда log (N) значительно больше, чем K, где K - количество радикальных цифр.

Сортировка по сегментам: когда вы можете гарантировать, что ваши входные данные распределены приблизительно равномерно.

dsimcha
источник
1
Насколько я помню, сортировка кучи также имеет очень предсказуемое время выполнения, поскольку между различными входами одного и того же размера есть небольшие различия, но это менее интересно, чем постоянная граница пространства. Я также считаю, что сортировку вставками проще всего реализовать из n ^ 2, но, возможно, это только я. Наконец, вы можете также упомянуть сортировку Shell, которая почти так же проста в реализации, как сортировка вставкой, но имеет лучшую производительность, хотя все еще не n log n.
JaakkoK
29
Не забудь Богосорт ! ;-)
Алекс Брасетвик
2
+1 Очень интересно. Не могли бы вы объяснить, как вы можете "гарантировать ... примерно равномерно распределены". для сортировки ведра?
Сэм Овертон
2
Почему интросортировка будет существенно медленнее, чем быстрая сортировка? Единственные накладные расходы - это подсчет глубины рекурсии, которая должна быть незначительной. Он переключается только после того, как рекурсия намного глубже, чем должна быть в хорошем случае быстрой сортировки.
dsimcha
2
Вы не упомянули, что лучший вариант сортировки по пузырькам - O (n)!
Тара
33

Быстрая сортировка, как правило, самая быстрая в среднем, но она имеет довольно неприятные наихудшие варианты поведения. Так что, если вы должны гарантировать, что плохие данные вам не предоставлены O(N^2), вам следует их избегать.

Сортировка слиянием использует дополнительную память, но особенно подходит для внешней сортировки (то есть огромных файлов, которые не помещаются в память).

Сортировка кучи может сортировать на месте и не имеет худшего квадратичного поведения, но в среднем медленнее, чем быстрая сортировка в большинстве случаев.

Там, где задействованы только целые числа в ограниченном диапазоне, вы можете использовать некоторую сортировку по осям, чтобы сделать это очень быстро.

В 99% случаев вы будете в порядке с сортировками библиотек, которые обычно основаны на быстрой сортировке.

Эли Бендерский
источник
6
+1: для «В 99% случаев вы будете в порядке с сортировками библиотек, которые обычно основаны на быстрой сортировке».
Джим Г.
Рандомизированное вращение дает Quicksort время выполнения O (nlogn) для всех практических целей, без необходимости каких-либо гарантий в отношении неверных данных. Я действительно не думаю, что кто-то реализует быструю сортировку O (n ^ 2) для любого производственного кода.
МАК
2
MAK, кроме, скажем, стандартной библиотеки C qsort? ( google.com/codesearch/… ) - на который опирается большинство видов «производственного кода»
Эли Бендерский,
Библиотечная сортировка обычно не основана на быстрой сортировке, потому что она нестабильна. Почти все более высокие языки (кроме C) обеспечивают стабильную сортировку. В большинстве случаев я знаю, что вам нужна стабильная или, по крайней мере, детерминированная сортировка.
12431234123412341234123
3

То, что предоставленные ссылки на сравнения / анимации не учитывают, - это когда объем данных превышает доступную память - в этот момент количество проходов по данным, т. Е. Затраты на ввод-вывод, преобладают во время выполнения. Если вам нужно это сделать, ознакомьтесь с «внешней сортировкой», которая обычно охватывает варианты сортировки слиянием и кучей.

http://corte.si/posts/code/visualisingsorting/index.html и http://corte.si/posts/code/timsort/index.html также содержат несколько интересных изображений, сравнивающих различные алгоритмы сортировки.

Алекс Брасетвик
источник
0

@dsimcha wrote: Подсчет сортировки: когда вы сортируете целые числа с ограниченным диапазоном

Я бы изменил это на:

Подсчет сортировки: когда вы сортируете положительные целые числа (0 - Integer.MAX_VALUE-2 из-за отверстия)

Вы всегда можете получить максимальные и минимальные значения в качестве эвристики эффективности и за линейное время.
Также вам нужно как минимум n дополнительного пространства для промежуточного массива, и он, очевидно, стабилен.

/**
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

(хотя это на самом деле позволит MAX_VALUE-2) увидеть: максимальный размер массивов Java?

Также я бы объяснил, что сложность радикальной сортировки равна O (wn) для n ключей, которые являются целыми числами размера слова w. Иногда w представляется как константа, что делает радикальную сортировку лучше (для достаточно большого n), чем лучшие алгоритмы сортировки на основе сравнения, которые все выполняют O (n log n) сравнений для сортировки n ключей. Тем не менее, в общем случае w нельзя считать константой: если все n ключей различны, то для того, чтобы машина с произвольным доступом могла хранить их в памяти, w должен иметь как минимум log n, что в лучшем случае дает сложность O (п лог п). (из википедии)

Чайная Droid
источник