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

Каковы варианты использования, когда конкретный алгоритм сортировки предпочтительнее других - merge sort vs quick sort vs heap sort vs intro sort и т.д.

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

Ответ 1

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

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

Быстрая сортировка:. Если вам не нужна стабильная сортировка, а средняя производительность по делу имеет значение, более высокая производительность. Быстрая сортировка - это 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). Вот некоторые примеры, когда стоит попробовать:

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

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

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

Ответ 2

Набор анимаций для различных видов данных и алгоритмов можно найти на sorting-algorithms.com

Ответ 3

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

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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

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

Вы всегда можете получить значения max и min в качестве эвристики эффективности в линейном времени.
Кроме того, для промежуточного массива вам нужно как минимум 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 максимальный размер?

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