Почему быстрая сортировка лучше, чем другие алгоритмы сортировки на практике?


308

В стандартном курсе алгоритмов нас учат, что быстрая сортировка в среднем составляет а в худшем случае . В то же время изучаются другие алгоритмы сортировки: в худшем случае (например, mergesort и heapsort ) и даже линейное время в лучшем случае (например, сортировка пузырьков ), но с некоторыми дополнительными потребностями в памяти.O ( п 2 ) О ( п войти п )O(nlogn)O(n2)O(nlogn)

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

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

Почему же тогда быстрая сортировка превосходит другие алгоритмы сортировки на практике? Связано ли это со структурой реальных данных ? Это связано с тем, как работает память в компьютерах? Я знаю, что некоторые воспоминания намного быстрее, чем другие, но я не знаю, является ли это реальной причиной этой нелогичной работы (по сравнению с теоретическими оценками).


Обновление 1: канонический ответ говорит, что константы, включенные в среднего случая, меньше, чем константы, включенные в другие алгоритмы . Тем не менее, мне еще предстоит увидеть правильное обоснование этого, с точными расчетами вместо интуитивных идей.O ( n log n )O(nlogn)O(nlogn)

В любом случае кажется, что реальная разница возникает, как предполагают некоторые ответы, на уровне памяти, где реализации используют преимущества внутренней структуры компьютеров, используя, например, кэш-память быстрее, чем ОЗУ. Обсуждение уже интересно, но я все же хотел бы получить более подробную информацию относительно управления памятью, так как кажется , что ответ должен делать с ней.


Обновление 2: есть несколько веб-страниц, предлагающих сравнение алгоритмов сортировки, некоторые из которых более привлекательны, чем другие (в первую очередь sorting-algorithms.com ). Помимо представления хорошего визуального пособия, этот подход не отвечает на мой вопрос.


2
Сортировка слиянием - это в худшем случае, и сортировка массива целых чисел, для которого существует известная граница размера целых чисел, может быть выполнена за раз с помощью сортировки с подсчетом. O ( n )O(nlogn)O(n)
Карл Маммерт,

13
У sorting-algorithms.com есть довольно тщательное сравнение алгоритмов сортировки.
Джо

2
Обновление объявления 1: Я предполагаю, что вы можете провести тщательный анализ или реалистичные предположения. Я не видел обоих. Например, в большинстве формальных анализов учитываются только сравнения.
Рафаэль

9
Этот вопрос выиграл недавний конкурс на программистов. SE !
Рафаэль

3
Интересный вопрос. Некоторое время назад я провел несколько тестов со случайными данными и наивной реализацией быстрой сортировки и сортировки слиянием. Оба алгоритма работали довольно хорошо для небольших наборов данных (до 100000 элементов), но после этого сортировка слиянием оказалась намного лучше. Это, кажется, противоречит общему предположению, что быстрая сортировка настолько хороша, и я до сих пор не нашел объяснения этому. Единственная идея, которую я могу придумать, состоит в том, что обычно термин быстрая сортировка используется для более сложных алгоритмов, таких как intro sort, и что наивная реализация быстрой сортировки со случайным поворотом не так уж хороша.
Джорджио

Ответы:


215

Краткий ответ

Аргумент эффективности кеша уже подробно объяснен. Кроме того, существует внутренний аргумент, почему быстрая сортировка выполняется быстро. Если реализовано как с двумя «указателями пересечения», например, здесь , внутренние петли имеют очень маленькое тело. Поскольку этот код выполняется чаще всего, это окупается.

Длинный ответ

Прежде всего,

Среднее Дело не существует!

Поскольку наилучшие и наихудшие случаи часто являются крайностями, редко встречающимися на практике, проводится анализ среднего случая. Но любой анализ среднего случая предполагает некоторое распределение входных данных ! Для сортировки типичным выбором является модель случайной перестановки (подразумеваемая в Википедии).

Почему примечание?O

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

Есть два выхода:

  1. Исправить некоторые модели машин.

    Это сделано в серии книг Дона Кнута «Искусство компьютерного программирования» для искусственного «типичного» компьютера, изобретенного автором. В томе 3 вы найдете точные средние результаты для многих алгоритмов сортировки, например

    • Быстрая сортировка: 11,66711.667(n+1)ln(n)1.74n18.74
    • Слияние:12.5nln(n)
    • Heapsort: 16nln(n)+0.01n
    • Сортировка вставок: [ источник ]2.25n2+7.75n3ln(n) Время выполнения нескольких алгоритмов сортировки

    Эти результаты показывают, что быстрая сортировка является самой быстрой. Но это доказано только на искусственной машине Кнута, это не обязательно подразумевает что-то, скажем, ваш x86 ПК. Также обратите внимание, что алгоритмы по-разному относятся к небольшим входам:
    Время выполнения нескольких алгоритмов сортировки для небольших входов
    [ источник ]

  2. Проанализируйте абстрактные основные операции .

    Для сортировки на основе сравнения это, как правило, свопы и ключевые сравнения . В книгах Роберта Седжвика, например, «Алгоритмы» , этот подход используется. Вы найдете там

    • Быстрая сортировка: сравнений и перестановок в среднем12nln(n)13nln(n)
    • Mergesort: сравнений, но до обращений к массиву (mergesort не основан на swap, поэтому мы не можем это посчитать).1.44nln(n)8.66nln(n)
    • вставки: сравнения и в среднем.14n214n2

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

Другие входные распределения

Как отмечалось выше, средние значения всегда относятся к некоторому входному распределению, поэтому можно рассмотреть случаи, отличные от случайных перестановок. Например, исследование было выполнено для Quicksort с равными элементами, и есть хорошая статья о стандартной функции сортировки в Java.


8
Результаты типа 2. могут быть преобразованы в результаты типа 1. путем вставки машинно-зависимых констант. Поэтому я бы сказал, 2. это превосходный подход.
Рафаэль

2
@ Рафаэль +1. Я полагаю, вы предполагаете, что машинно-зависимый также зависит от реализации, верно? Я имею в виду, что быстрая машина + плохая реализация, вероятно, не очень эффективна.
Яном

2
@Janoma Я предполагал, что анализируемый алгоритм будет дан в очень подробной форме (так как анализ детален), а реализация будет как можно более буквальной. Но да, реализация также будет учитывать.
Рафаэль

3
На самом деле, анализ типа 2 уступает на практике. Реальные машины настолько сложны, что результаты типа 2 невозможно реально перевести на тип 1. Сравните это с типом 1: построение графика экспериментального времени выполнения занимает 5 минут работы.
Жюль

4
@Jules: «график экспериментального времени выполнения» не является типом 1; это не формальный анализ, и он не может быть перенесен на другие машины. Вот почему мы проводим формальный анализ, в конце концов.
Рафаэль

78

По этому вопросу можно сделать несколько замечаний.

Быстрая сортировка обычно быстрая

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

В частности, даже если мы выберем опорную точку, которая создает 10% -90% -ое разделение каждые 10 разделений (что является разделением по meh), и 1 элемент - разделение в противном случае (что является худшим разделением, которое вы можете получить) наше время выполнения все еще равно (обратите внимание, что это увеличит константы до такой степени, что сортировка слиянием, вероятно, будет быстрее).n1O(nlogn)

Быстрая сортировка обычно быстрее большинства сортов

Быстрая сортировка обычно быстрее, чем сортировки, которые медленнее, чем (скажем, сортировка вставкой со временем выполнения ), просто потому, что при больших их время взрыва увеличивается.O(nlogn)O(n2)n

Хорошая причина, почему Quicksort на практике так быстр по сравнению с большинством других алгоритмов , таких как Heapsort, заключается в том, что он относительно эффективен в кеше. Время его выполнения на самом деле , где - размер блока. У Heapsort, с другой стороны, нет такого ускорения: он вообще не обеспечивает эффективный доступ к кэш-памяти.O(nlogn)O(nBlog(nB))B

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

Эффективность кэша может быть улучшена до , где - это размер нашей основной памяти , если мы используем -way Quicksort. Обратите внимание, что Mergesort также обладает той же эффективностью кэширования, что и Quicksort, и его версия k-way на самом деле имеет лучшую производительность (благодаря более низким постоянным коэффициентам), если память является серьезным ограничением. Это приводит к следующему пункту: нам нужно сравнить Quicksort с Mergesort по другим факторам.МкO(nBlogMB(nB))Mk

Быстрая сортировка обычно быстрее, чем Mergesort

Это сравнение полностью о постоянных факторах (если мы рассмотрим типичный случай). В частности, выбор между субоптимальным выбором сводки для быстрой сортировки и копией всего ввода для Mergesort (или сложностью алгоритма, необходимого, чтобы избежать этого копирования). Оказывается, первый более эффективен: за этим нет теории, просто он работает быстрее.

Обратите внимание, что Quicksort будет делать больше рекурсивных вызовов, но выделение стекового пространства обходится дешево (на самом деле почти бесплатно, если вы не выбрасываете стек), и вы используете его повторно. Выделяя гигантский блок в куче (или на жестком диске, если является действительно большой) совсем немного дороже, но оба накладные расходы, бледные по сравнению с работы , упомянутой выше.O ( log n ) O ( n )nO(logn)O(n)

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

Используйте вид, который соответствует вашим потребностям

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


3
Ваше последнее замечание особенно ценно. Мой коллега в настоящее время анализирует реализации Quicksort при различных входных распределениях. Например, некоторые из них разбиваются на множество дубликатов.
Рафаэль

4
O(n2)

8
«[T] здесь нет никакой теории, просто это происходит быстрее». Это утверждение крайне неудовлетворительно с научной точки зрения. Представьте себе, что Ньютон говорит: «Бабочки взлетают, яблоки падают: за этим нет теории, яблоки просто падают».
Дэвид Ричерби

2
@ Алекс тен Бринк, что вы имеете в виду под «В частности, алгоритм не обращает внимания на кеш »?
Hibou57

4
@ Дэвид Ричерби, «Это утверждение крайне неудовлетворительно с научной точки зрения»: он может быть просто свидетелем факта, не делая вид, что мы должны быть довольны им. Некоторые семейства алгоритмов страдают от отсутствия полной формализации; хеш-функции являются примером.
Hibou57

45

В одном из учебников по программированию в моем университете мы попросили студентов сравнить производительность быстрой сортировки, сортировки слиянием, сортировки вставкой и встроенной в Python list.sort (называемой Timsort ). Результаты эксперимента меня сильно удивили, поскольку встроенная сортировка list.sort работала намного лучше, чем другие алгоритмы сортировки, даже в случаях, когда легко выполнялась быстрая сортировка, сбой слияния. Поэтому преждевременно делать вывод, что обычная реализация быстрой сортировки является лучшей на практике. Но я уверен, что есть гораздо лучшая реализация быстрой сортировки или какая-то гибридная версия.

Это хорошая статья в блоге Дэвида Р. Макивера, объясняющая Timsort как форму адаптивного слияния.


17
@Raphael Проще говоря, Timsort - это сортировка слиянием для асимптотики, а также сортировка вставки для коротких входных данных и некоторая эвристика, позволяющая эффективно справляться с данными, которые иногда имеют уже отсортированный пакет (что часто случается на практике). Dai: в дополнение к алгоритму, вы list.sortполучаете преимущества встроенной функции, оптимизированной профессионалами. Более справедливое сравнение будет иметь все функции, написанные на одном языке, с одинаковым уровнем усилий.
Жиль

1
@Dai: Вы могли бы по крайней мере описать, с какими входами (соответственно их распределением), при каких обстоятельствах (низкий объем ОЗУ, параллелизация одной реализации, ...), вы получили свои результаты.
Рафаэль

7
Мы проверили список случайных чисел, и частично отсортированы, полностью отсортированы и обратно отсортированы. Это был вводный курс 1-го года обучения, так что это не было глубокое эмпирическое исследование. Но тот факт, что он теперь официально используется для сортировки массивов в Java SE 7 и на платформе Android, действительно что-то значит.
Дай

3
Это также обсуждалось здесь: cstheory.stackexchange.com/a/927/74
Юкка Суомела

34

Я думаю, что одна из основных причин, почему QuickSort так быстро по сравнению с другими алгоритмами сортировки, заключается в том, что он кеш-памяти. Когда QS обрабатывает сегмент массива, он обращается к элементам в начале и конце сегмента и перемещается к центру сегмента.

Таким образом, при запуске вы получаете доступ к первому элементу в массиве, и часть памяти («местоположение») загружается в кэш. И когда вы пытаетесь получить доступ ко второму элементу, он (скорее всего) уже находится в кеше, поэтому он очень быстрый.

Другие алгоритмы, такие как heapsort, не работают таким образом, они много скачут в массиве, что делает их медленнее.


5
Это спорное объяснение: кеш слияние дружественного тоже.
Дмитрий Кордубан

2
Я думаю, что этот ответ в основном правильный, но вот некоторые детали youtube.com/watch?v=aMnn0Jq0J-E
rgrig

3
Вероятно, мультипликативная константа для средней сложности по времени в случае быстрой сортировки также лучше (независимо от упомянутого вами коэффициента кэширования).
Каве

1
Упомянутый вами пункт не так важен по сравнению с другими хорошими свойствами быстрой сортировки.
MMS

1
@Kaveh: «мультипликативная константа для среднего времени сложность быстрой сортировки также лучше» У вас есть какие-либо данные по этому поводу?
Джорджио

29

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

O(nlogn)

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

k10


20

O(nlgn)

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

Смотрите также:


3
@Janoma, это вопрос того, какой язык и компилятор вы используете. Почти все функциональные языки (ML, Lisp, Haskell) могут выполнять оптимизацию, которая препятствует росту стека, и умные компиляторы для императивных языков могут делать то же самое (GCC, G ++, и я полагаю, что все MSVC делают это). Заметным исключением является Java, которая никогда не будет выполнять эту оптимизацию, поэтому в Java имеет смысл переписать вашу рекурсию как итерацию.
Rafe Kettler

4
@JD, вы не можете использовать оптимизацию хвостового вызова с быстрой сортировкой (по крайней мере, не полностью), потому что она вызывает себя дважды. Вы можете оптимизировать второй звонок, но не первый звонок.
svick

1
@Janoma, тебе не нужна рекурсивная реализация. Например, если вы посмотрите на реализацию функции qsort в C, она не использует рекурсивные вызовы, и, следовательно, реализация становится намного быстрее.
Каве

1
Heapsort также на месте, почему QS часто быстрее?
Кевин

6
23240

16

Θ(n2)Θ(nlogn)

Вторая причина заключается в том, что он выполняет in-placeсортировку и очень хорошо работает со средами виртуальной памяти.

ОБНОВЛЕНИЕ:: (после комментариев Яномы и Свика)

Чтобы проиллюстрировать это лучше, позвольте мне привести пример с использованием сортировки слиянием (поскольку сортировка слиянием является следующим широко распространенным алгоритмом сортировки после быстрой сортировки, я думаю) и рассказать вам, откуда берутся дополнительные константы (насколько мне известно и почему я думаю, Быстрая сортировка лучше)

Рассмотрим следующую последовательность:

12,30,21,8,6,9,1,7. The merge sort algorithm works as follows:

(a) 12,30,21,8    6,9,1,7  //divide stage
(b) 12,30   21,8   6,9   1,7   //divide stage
(c) 12   30   21   8   6   9   1   7   //Final divide stage
(d) 12,30   8,21   6,9   1,7   //Merge Stage
(e) 8,12,21,30   .....     // Analyze this stage

Если вам нужно полностью посмотреть, как происходит последняя стадия, первые 12 сравниваются с 8, а 8 меньше, поэтому они идут первыми. Теперь 12 СНОВА по сравнению с 21 и 12 идут дальше и так далее, и так далее. Если вы возьмете окончательное слияние, то есть 4 элемента с 4 другими элементами, это приведет к большому количеству дополнительных сравнений в качестве констант, которые НЕ происходят в быстрой сортировке. Это причина, почему быстрая сортировка предпочтительнее.


1
Но что делает константы такими маленькими?
svick

1
@svick Потому что они отсортированы, in-placeт. е. дополнительная память не требуется.
0x0

Θ(nlgn)

15

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

Еще в 2008 году я отследил зависание программного обеспечения вплоть до использования быстрой сортировки. Некоторое время спустя я написал простые дополнения сортировки вставкой, быстрой сортировки, сортировки кучи и сортировки слиянием и протестировал их. Моя сортировка слияний превзошла все остальные при работе с большими наборами данных.

С тех пор сортировка слиянием - мой предпочтительный алгоритм сортировки. Это элегантно. Это просто реализовать. Это стабильный сорт. Он не вырождается в квадратичное поведение, как быстрая сортировка. Я переключаюсь на сортировку вставок для сортировки небольших массивов.

Во многих случаях я думал, что данная реализация на удивление хорошо работает для быстрой сортировки, только чтобы выяснить, что она на самом деле не является быстрой сортировкой. Иногда реализация переключается между быстрой сортировкой и другим алгоритмом, а иногда она вообще не использует быструю сортировку. Например, функции qsort () GLibc на самом деле используют сортировку слиянием. Только в случае неудачного выделения рабочего пространства оно возвращается к быстрой сортировке на месте, которую кодовый комментарий называет «более медленным алгоритмом» .

Редактировать: языки программирования, такие как Java, Python и Perl, также используют сортировку слиянием или, точнее, производную, такую ​​как сортировка слиянием или сортировка слиянием для больших наборов и сортировка вставкой для небольших наборов. (Java также использует быструю сортировку с двойным поворотом, которая быстрее, чем простая быстрая сортировка.)


Я видел нечто похожее на это, потому что мы постоянно добавляли / прибегали к вставке в пакет уже отсортированных данных. Вы можете обойти это в среднем, используя рандомизированную быструю сортировку (и удивляться редкой и случайной ужасно медленной сортировке), или можете терпеть всегда более медленную сортировку, которая никогда не занимает удивительное количество времени, чтобы закончить. Иногда требуется стабильность сортировки. Java перешла от использования сортировки слиянием к варианту быстрой сортировки.
Роб

@Rob Это не точно. В Java до сих пор используется вариант слияния (Timsort). Он также использует вариант быстрой сортировки (двойная круговая сортировка).
Эрван Легран

14

1 - Быстрая сортировка на месте (не требует дополнительной памяти, кроме постоянной суммы.)

2 - Быстрая сортировка проще в реализации, чем другие эффективные алгоритмы сортировки.

3 - Быстрая сортировка имеет меньшие постоянные факторы во время выполнения, чем другие эффективные алгоритмы сортировки.

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


3
Вы видели расширенные итеративные реализации Quicksort? Это много вещей, но не "легко".
Рафаэль

2
Номер 2 вообще не отвечает на мой вопрос, а номера 1 и 3, по моему мнению, нуждаются в надлежащем обосновании.
Яном

@ Рафаэль: Они легки. Гораздо проще реализовать быструю сортировку на месте с использованием массива вместо указателей. И это не должно быть итеративным, чтобы быть на месте.
MMS

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

@ 1 Mergesort также может быть на месте. @ 2 Что определяет эффективность? Мне нравится сортировка слиянием, потому что она очень проста и, на мой взгляд, эффективна. @ 3 Не имеет значения, когда вы сортируете большие объемы данных, и требует эффективной реализации алгоритма.
Оскар Ског

11

При каких условиях конкретный алгоритм сортировки является самым быстрым?

Θ(log(n)2)Θ(nlog(n)2)

Θ(nk)Θ(nm)k=2#number_of_Possible_valuesm=#maximum_length_of_keys

3) состоит ли основная структура данных из связанных элементов? Да -> всегда используйте место сортировки слиянием. Существуют как простые в реализации фиксированные размеры, так и адаптивные (то есть естественные) восходящие операции на месте с различными типами слияния для связанных структур данных, и, поскольку им никогда не требуется копировать все данные на каждом шаге, и они также никогда не требуют рекурсий, они быстрее, чем любые другие общие сортировки на основе сравнения, даже быстрее, чем быстрая сортировка.

Θ(n)

5) Может ли размер базовых данных быть привязан к небольшому или среднему размеру? Например, n <10 000 ... 100 000 000 (в зависимости от базовой архитектуры и структуры данных)? Да -> использовать битовую сортировку или нечетно-четную сортировку по Батчеру. Перейти к 1)

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

Θ(log(n))Θ(n)Θ(n)Θ(log(n))Θ(n2)Θ(n)Θ(n)Θ(log(n))Θ(nlog(n))

Θ(nlog(n))

Советы по реализации быстрой сортировки:

Θ(n)Θ(log(n))Θ(nlogk(k1))

2) Существуют итеративные варианты быстрой сортировки снизу вверх, но AFAIK, они имеют то же асимптотическое пространство и границы времени, что и нисходящие, с дополнительными недостатками, которые трудно реализовать (например, явное управление очередью). Мой опыт показывает, что для любых практических целей это никогда не стоит рассматривать.

Реализация советов по слиянию:

1) сортировка по принципу «снизу вверх» всегда быстрее, чем «сортировка сверху вниз», так как она не требует рекурсивных вызовов.

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

3) Для многих реальных данных адаптивная сортировка слиянием выполняется намного быстрее, чем сортировка с фиксированным размером.

Θ(k)Θ(log(k))Θ(1)Θ(n)

Из того, что я написал, ясно, что быстрая сортировка часто не самый быстрый алгоритм, за исключением случаев, когда все следующие условия применяются:

1) существует более чем «несколько» возможных значений

2) основная структура данных не связана

3) нам не нужен стабильный заказ

4) данные достаточно велики, чтобы небольшое субоптимальное асимптотическое время работы битонного сортировщика или нечетно-четного слияния Бэтчера

5) данные почти не отсортированы и не состоят из больших уже отсортированных частей

6) мы можем получить доступ к последовательности данных одновременно из нескольких мест

Θ(log(n))Θ(n)

PS: Кто-то должен помочь мне с форматированием текста.


(5): реализация сортировки Apple проверяет один запуск в порядке возрастания или убывания в начале и в конце массива в первую очередь. Это очень быстро, если таких элементов не так много, и может очень эффективно обрабатывать эти элементы, если их более n / ln n. Объедините два отсортированных массива и отсортируйте результат, и вы получите слияние
gnasher729

8

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

ab


5
Ваш аргумент о быстрой сортировке против сортировки слиянием не выдерживает критики. Быстрая сортировка начинается с большого движения, затем делает все меньшие и меньшие движения (примерно вдвое больше на каждом шаге). Сортировка слиянием начинается с небольшого движения, затем выполняется большее и большее движение (примерно в два раза больше на каждом шаге). Это не означает, что один из них более эффективен, чем другой.
Жиль
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.