Почему quicksort лучше, чем mergesort?

Мне задали этот вопрос во время интервью. Они оба O (nlogn), и все же большинство людей используют Quicksort вместо Mergesort. Почему это?

Ответ 1

Quicksort имеет O (n 2) наихудшее время выполнения и O ( n log n) среднее время выполнения. Тем не менее, его превосходство по объему сортируется во многих сценариях, потому что многие факторы влияют на время выполнения алгоритмов, и, когда их все вместе, quicksort выигрывает.

В частности, часто цитируемое время выполнения алгоритмов сортировки относится к числу сравнений или количеству свопов, необходимых для сортировки данных. Это действительно хороший показатель производительности, тем более, что он не зависит от базового оборудования. Однако другие вещи, такие как локальность ссылки (то есть мы читаем много элементов, которые, вероятно, находятся в кеше?), Также играют важную роль на текущем оборудовании. Quicksort, в частности, требует небольшого дополнительного пространства и демонстрирует хорошую локальность кэша, и это во многих случаях ускоряет процесс сортировки.

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

На практике многие современные реализации quicksort (в частности, libstdС++ s std::sort) на самом деле introsort, теоретический худший -case - это O (n log n), то же, что и сортировка слияния. Он достигает этого, ограничивая глубину рекурсии и переключаясь на другой алгоритм (heapsort), когда он превышает log n.

Ответ 2

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

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

Поэтому, если данные необходимо сортировать на диске, вы действительно хотите использовать некоторые варианты для mergesort. (Как правило, вы быстро сортируете подсписки, а затем объединяете их вместе с порогом определенного размера.)

Кроме того, если вам нужно что-либо делать с наборами данных такого размера, подумайте о том, как избежать поиска на диске. Например, именно поэтому стандартным советом является то, что вы бросаете индексы перед выполнением больших нагрузок данных в базах данных, а затем перестраиваете индекс позже. Поддержание индекса во время загрузки означает постоянный поиск диска. В отличие от этого, если вы отбрасываете индексы, база данных может перестроить индекс, сначала отсортировав информацию, которую нужно обработать (используя слияние, конечно!), А затем загрузив ее в структуру данных BTREE для индекса. (BTREEs естественно сохраняются в порядке, поэтому вы можете загрузить один из отсортированного набора данных с небольшим количеством запросов на диск.)

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

Ответ 3

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

QuickSort более популярен, потому что он:

  • Является на месте (MergeSort требует дополнительной памяти, линейной по количеству элементов, подлежащих сортировке).
  • Имеет небольшую скрытую константу.

Ответ 4

Анимированные алгоритмы сортировки показывает ряд алгоритмов на 4 разных начальных условиях (случайные, почти отсортированные, обратные, мало уникальные) и может Помогите.

Ответ 5

", но большинство людей используют Quicksort вместо Mergesort. Почему это?"

Одна психологическая причина, которая не была дана, просто заключается в том, что Quicksort более остро назван. т.е. хороший маркетинг.

Да, Quicksort с тройным partioning, вероятно, является одним из лучших алгоритмов сортировки общего назначения, но theres не справляется с тем, что "Quick" sort звучит намного мощнее, чем сортировка "Merge".

Ответ 6

Как отмечали другие, наихудшим случаем Quicksort является O (n ^ 2), тогда как mergesort и heapsort остаются на O (nlogn). Однако в среднем случае все три являются O (nlogn); поэтому они для подавляющего большинства случаев сопоставимы.

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

Ответ 7

Я хотел бы добавить, что из трех перечисленных выше алгоритмов (mergesort, quicksort и heap sort) только mergesort стабилен. То есть порядок не изменяется для тех значений, которые имеют один и тот же ключ. В некоторых случаях это желательно.

Но, правда, в практических ситуациях большинству людей нужна только хорошая средняя производительность, а quicksort - это... quick =)

Все алгоритмы сортировки имеют свои взлеты и падения. См. статью Википедии для сортировки алгоритмов для хорошего обзора.

Ответ 8

Mu! Quicksort не лучше, он хорошо подходит для другого типа приложений, чем mergesort.

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

Вы заявили, что они "Они оба O (nlogn) [...]". Это не верно. "Quicksort использует примерно n ^ 2/2 сравнения в худшем случае". 1.

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

1 Sedgewick, Алгоритмы

Ответ 9

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

Гарантируется, что Heapsort будет работать в O (n * ln (n)) и требует только конечного дополнительного хранилища. Но есть много цитат из тестов на реальном мире, которые показывают, что гепсорт значительно медленнее, чем quicksort в среднем.

Ответ 10

Из запись в Википедии в Quicksort:

Quicksort также конкурирует с mergesort, другой рекурсивный вид алгоритма, но с выгодой наихудший Θ (nlogn) время работы. Mergesort - стабильный вид, в отличие от quicksort и heapsort, и может быть легко адаптируется для работы с списки и очень большие списки, хранящиеся на медленные для доступа среды, такие как диск хранилище или сетевое хранилище. Хотя quicksort можно записать в работать со связанными списками, часто страдают от неправильного выбора без случайный доступ. Основным недостатком of mergesort заключается в том, что при работе на массивах, требуется Θ (n) вспомогательное пространства в лучшем случае, тогда как вариант быстрой сортировки с на месте разбиение на разделы и использование хвостовой рекурсии только Θ (logn). (Обратите внимание, что когда работая по связанным спискам, mergesort требуется только небольшая, постоянная сумма дополнительного хранилища.)

Ответ 11

Объяснение Википедии:

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

Quicksort

Mergesort

Я думаю, что есть проблемы с объемом хранения, необходимым для Mergesort (который является Ω (n)), который не имеет реализации quicksort. В худшем случае они равны объему алгоритмического времени, но mergesort требует большего объема памяти.

Ответ 12

Quicksort НЕ лучше, чем mergesort. С O (n ^ 2) (худший случай, который редко случается), quicksort потенциально намного медленнее, чем O (nlogn) сортировки слияния. У Quicksort меньше накладных расходов, поэтому с небольшими n и медленными компьютерами это лучше. Но сегодня компьютеры настолько быстрые, что дополнительные накладные расходы на слияние незначительны, а риск очень медленной быстрой сортировки намного превосходит незначительные накладные расходы на объединение в большинстве случаев.

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

Ответ 13

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

Вне проблем с произвольным доступом есть два основных фактора, которые могут повлиять на производительность QuickSort, и оба они связаны с тем, как свод сравнивается с сортируемыми данными.

1) Небольшое количество ключей в данных. Набор данных с одинаковым значением будет сортироваться в n ^ 2 раза на ванильном 2-разделенном QuickSort, потому что все значения, за исключением точки поворота, помещаются с одной стороны каждый раз. Современные реализации обращаются к этому с помощью таких методов, как использование сортировки по 3 разделам. Эти методы выполняются в наборе данных с одинаковым значением в O (n) времени. Таким образом, использование такой реализации означает, что ввод с небольшим количеством клавиш фактически улучшает время работы и больше не вызывает беспокойства.

2) Чрезвычайно плохой выбор поворота может привести к худшему результату. В идеальном случае стержень всегда будет таким, чтобы на 50% данные были меньше, а на 50% больше данных, так что при каждой итерации вход будет разбит пополам. Это дает нам n сравнений и свопов времени log-2 (n) рекурсий для времени O (n * logn).

Сколько неэлементный выбор поворота влияет на время выполнения?

Рассмотрим случай, когда стержень последовательно выбирается таким образом, чтобы 75% данных находились на одной стороне стержня. Он все еще O (n * logn), но теперь база журнала изменилась на 1/0.75 или 1.33. Связь в производительности при смене базы всегда является константой, представленной log (2)/log (newBase). В этом случае эта константа равна 2,4. Таким образом, это качество выбора поворота занимает в 2,4 раза дольше, чем идеальный.

Как быстро это ухудшается?

Не очень быстро, пока выбор поворота не будет (последовательно) очень плохим:

  • 50% с одной стороны: (идеальный случай)
  • 75% с одной стороны: в 2,4 раза длиннее
  • 90% с одной стороны: в 6,6 раза
  • 95% с одной стороны: в 13,5 раз больше
  • 99% с одной стороны: 69 раз.

По мере приближения к 100% с одной стороны логарифмическая часть выполнения приближается к n, и все выполнение асимптотически приближается к O (n ^ 2).

В наивной реализации QuickSort такие случаи, как отсортированный массив (для элемента 1-го элемента) или массив с обратным сортированием (для последнего элемента), будут надежно создавать наихудшее время выполнения O (n ^ 2). Кроме того, реализации с предсказуемым выбором поворота могут быть подвергнуты DoS-атаке данными, предназначенными для выполнения наихудшего случая. Современные реализации избегают этого с помощью различных методов, таких как рандомизация данных до сортировки, выбор медианы из 3 случайно выбранных индексов и т.д. При этой рандомизации в миксе у нас есть 2 случая:

  • Небольшой набор данных. Наихудший случай возможен, но O (n ^ 2) не катастрофичен, так как n достаточно мало, что n ^ 2 также мало.
  • Большой набор данных. Наихудший случай возможен в теории, но не на практике.

Насколько мы можем видеть ужасную производительность?

Шансы исчезающе малы. Давайте рассмотрим несколько тысяч значений:

Наша гипотетическая реализация выберет стержень, используя медиану из 3 случайно выбранных индексов. Мы рассмотрим поворотные точки, которые находятся в диапазоне 25% -75%, чтобы быть "хорошими" и поворотными, которые находятся в диапазоне 0% -25% или 75% -100%, чтобы быть "плохим". Если вы посмотрите на распределение вероятности, используя медиану из 3 случайных индексов, каждая рекурсия имеет шанс 11/16 получить хороший стержень. Сделаем два консервативных (и ложных) предположения для упрощения математики:

  • Хорошие стержни всегда находятся на уровне 25%/75% и работают в 2.4 * идеальном случае. Мы никогда не получаем идеальный раскол или любой раскол лучше, чем 25/75.

  • Плохие опорные точки всегда худшие и по существу не способствуют решению.

Наша реализация QuickSort остановится при n = 10 и переключится на сортировку вставки, поэтому нам потребуется 22 25%/75% сводных разделов, чтобы сломать введенное значение 5000. (10 * 1.333333 ^ 22 > 5000) Или нам требуется 4990 наихудших аргументов. Имейте в виду, что если мы накапливаем 22 хороших опорных точки в любой момент, то сортировка завершится, поэтому худший случай или что-то рядом с ним требует крайне неудачного результата. Если нам потребовалось 88 рекурсий, чтобы на самом деле достичь 22 хороших опорных элементов, необходимых для сортировки до n = 10, это будет 4 * 2,4 * идеальный случай или примерно в 10 раз больше времени исполнения идеального случая. Насколько вероятно, что мы не достигнем требуемых 22 хороших опорных точек после 88 рекурсий?

Биномиальные распределения вероятности могут ответить на этот вопрос, а ответ - около 10 ^ -18. (n равно 88, k равно 21, p равно 0,6875). Ваш пользователь примерно в тысячу раз больше шансов поразить молнией за 1 секунду, чтобы щелкнуть [SORT], чтобы увидеть, что сортировка 5000 штук хуже чем 10 * идеальный случай. Этот шанс становится меньше по мере увеличения набора данных. Вот некоторые размеры массива и их соответствующие шансы работать дольше, чем 10 * ideal:

  • Массив из 640 предметов: 10 ^ -13 (требуется 15 хороших опорных точек из 60 попыток).
  • Массив из 5000 предметов: 10 ^ -18 (требуется 22 хороших поворота из 88 попыток).
  • Массив из 40 000 предметов: 10 ^ -23 (требуется 29 хороших опорных точек из 116).

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

Наконец, как отмечали другие, даже эти абсурдно маловероятные случаи могут быть устранены путем переключения на кучу сортировки, если рекурсивный стек идет слишком глубоко. Таким образом, TL;DR заключается в том, что для хороших реализаций QuickSort наихудший случай на самом деле не существует, потому что он был спроектирован и выполнение завершено в O (n * logn) времени.

Ответ 14

Ответ будет слегка наклонен к quicksort w.r.t к изменениям, внесенным с помощью DualPivotQuickSort для примитивных значений. Он используется в JAVA 7 для сортировки в java.util.Arrays

It is proved that for the Dual-Pivot Quicksort the average number of
comparisons is 2*n*ln(n), the average number of swaps is 0.8*n*ln(n),
whereas classical Quicksort algorithm has 2*n*ln(n) and 1*n*ln(n)
respectively. Full mathematical proof see in attached proof.txt
and proof_add.txt files. Theoretical results are also confirmed
by experimental counting of the operations.

Здесь вы можете найти имплантацию JAVA7 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/Arrays.java

Дальше Удивительное чтение на DualPivotQuickSort - http://permalink.gmane.org/gmane.comp.java.openjdk.core-libs.devel/2628

Ответ 15

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

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

Я больше поклонник Mergesort, чем я из Quicksort, по этим причинам.

Ответ 16

В то время как они оба находятся в одном классе сложности, это не означает, что обе они имеют одинаковое время выполнения. Quicksort обычно быстрее, чем mergesort, просто потому, что проще закодировать жесткую реализацию, и операции, которые она делает, могут идти быстрее. Это потому, что этот quicksort обычно быстрее, чем люди используют его вместо mergesort.

Однако! Я лично часто использую mergesort или вариант quicksort, который ухудшается до mergesort, когда quicksort делает плохо. Запомнить. Quicksort - это только O (n log n) в среднем. В худшем случае O (n ^ 2)! Mergesort всегда O (n log n). В тех случаях, когда производительность или быстродействие в реальном времени является обязательным, а ваши исходные данные могут исходить от злонамеренного источника, , вы не должны использовать простой quicksort.

Ответ 17

При прочих равных условиях, я ожидаю, что большинство людей будут использовать все, что наиболее удобно, и это, как правило, qsort (3). Известно, что, помимо того, что quicksort очень быстро работает в массивах, так же, как mergesort является общим выбором для списков.

Мне интересно, почему так редко можно увидеть radix или сортировку в виде корзины. Они O (n), по крайней мере, в связанных списках, и все, что требуется, это некоторый метод преобразования ключа в порядковый номер. (строки и поплавки работают очень хорошо.)

Я думаю, что причина связана с тем, как преподается информатика. Мне даже пришлось продемонстрировать моему преподавателю анализ алгоритмов, что действительно можно сортировать быстрее, чем O (n log (n)). (У него было доказательство того, что вы не можете сравнивать сортировку быстрее, чем O (n log (n)), что верно.)

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

Изменить: На самом деле, здесь еще более порочный способ сортировки float-as-integers: http://www.stereopsis.com/radix.html. Обратите внимание, что трюк с переворотом бит может использоваться независимо от того, какой алгоритм сортировки вы фактически используете...

Ответ 18

Это трудно сказать. Хуже всего MergeSort является n (log2n) -n + 1, что является точным, если n равно 2 ^ k (это уже доказано). И для любого n это между (n lg n - n + 1) и (n lg n + n + O (lg n)). Но для quickSort наилучшим является nlog2n (также n равно 2 ^ k). Если вы разделите Mergesort на quickSort, он равен единице, если n бесконечно. Так что, если худший случай MergeSort лучше, чем лучший случай QuickSort, почему мы используем quicksort? Но помните, что MergeSort не на месте, ему требуется 2n memeroy space.And MergeSort также необходимо сделать много копий массивов, которые мы не учитываем при анализе алгоритма. Одним словом, MergeSort на самом деле является более неустойчивым, чем quicksort в theroy, но на самом деле вам нужно рассмотреть пространство памяти, стоимость копии массива, слияние происходит медленнее, чем быстрый sort.I однажды сделал эксперимент, в котором я получил 1000000 цифр в java классом Random, и потребовалось 2610 мс путем слияния, 1370 мс с помощью quicksort.

Ответ 19

Быстрая сортировка - наихудший случай O (n ^ 2), однако, средний случай последовательно выходит, выполняет сортировку слияния. Каждый алгоритм O (nlogn), но вам нужно помнить, что, говоря о Big O, мы оставляем менее сложные факторы сложности. Быстрый сорт имеет значительные улучшения в отношении сортировки слияния, когда дело доходит до постоянных факторов.

Сортировка слияния также требует O (2n) памяти, в то время как быстрая сортировка может быть выполнена на месте (требуется только O (n)). Это еще одна причина того, что быстрый сортировка обычно предпочтительнее сортировки слияния.

Дополнительная информация:

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

[5, 4, 3, 2, 1]

Если стержень выбран как наименьшее или наибольшее число в группе, тогда быстрый сортировка будет выполняться в O (n ^ 2). Вероятность выбора элемента, который находится в наибольшем или минимальном 25% списка, равен 0,5. Это дает алгоритму 0,5 шанс быть хорошим стержнем. Если мы используем типичный алгоритм выбора опорных точек (например, выбираем случайный элемент), у нас есть 0,5 вероятность выбора хорошего стержня для каждого выбора стержня. Для коллекций большого размера вероятность всегда выбирать плохой стержень равна 0,5 * n. На основе этой вероятности быстрый сортировка эффективна для среднего (и типичного) случая.

Ответ 20

Почему Quicksort хорош?

  • QuickSort берет N ^ 2 в худшем случае и в среднем случае NlogN. Наихудший случай возникает при сортировке данных. Это может быть смягчено случайным перетасовкой до начала сортировки.
  • QuickSort не берет дополнительную память, которая берется с помощью сортировки слиянием.
  • Если набор данных большой и есть одинаковые элементы, сложность Quicksort уменьшается с помощью 3-х точечного раздела. Больше нет одинаковых предметов лучше сортировки. Если все элементы идентичны, он сортируется в линейном времени. [Это реализация по умолчанию в большинстве библиотек]

Является ли Quicksort всегда лучше, чем Mergesort?

Не совсем.

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

Примечание. В функции java функция Arrays.sort() использует Quicksort для примитивных типов данных и Mergesort для типов данных объектов. Поскольку объекты потребляют накладные расходы памяти, поэтому добавленная небольшая накладная плата для Mergesort может не быть проблемой для точки зрения производительности.

Ссылка. Посмотрите видеоролики QuickSort Неделя 3, курс алгоритмов Принстона в Курсере

Ответ 21

В отличие от Merge Sort Quick Sort не используется вспомогательное пространство. В то время как Merge Sort использует вспомогательное пространство O (n). Но Merge Sort имеет худшую временную сложность O (nlogn), тогда как наихудшая сложность Quick Sort - O (n ^ 2), которая происходит, когда массив уже отсортирован.

Ответ 22

Небольшие дополнения для быстрого сопоставления слияния.

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

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

Кроме того, в пользовательских контейнерах, таких как "связанный список", не выгодно быстро сортировать.
1. Объедините сортировку по связанному списку, не требуйте дополнительной памяти. 2. Доступ к элементам в быстрой сортировке не является последовательным (в памяти)

Ответ 23

В слиянии-сортировке общий алгоритм:

  • Сортировка левого суб-массива
  • Сортировка правого вспомогательного массива
  • Объединить 2 отсортированных подматрицы

На верхнем уровне слияние двух отсортированных подархивов включает в себя работу с N элементами.

На одном уровне ниже, каждая итерация шага 3 включает в себя работу с N/2 элементами, но вы должны повторить этот процесс дважды. Таким образом, вы все еще имеете дело с 2 * N/2 == N элементами.

На одном уровне ниже вы объединяете 4 * N/4 == N элементов и т.д. Каждая глубина рекурсивного стека включает объединение одного и того же количества элементов во всех вызовах этой глубины.

Рассмотрим вместо этого алгоритм быстрой сортировки:

  • Выберите точку опоры
  • Поместите точку поворота в нужное место в массиве, со всеми меньшими элементами слева и большими элементами вправо
  • Сортировка левого субарама
  • Сортировка правого подмашины

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

На одном уровне ниже, вы имеете дело с 2 подматрицами, которые имеют объединенный размер N-1 (т.е. вычитают более раннюю точку опоры). Вы выбираете опорную точку для каждого вспомогательного массива, который имеет до 2 дополнительных опорных точек.

На одном уровне ниже, вы имеете дело с 4 суб-массивами с комбинированным размером N-3 по тем же причинам, что и выше.

Тогда N-7... Тогда N-15... Тогда N-32...

Глубина рекурсивного стека остается примерно одинаковой (logN). При слиянии-сортировке вы всегда имеете дело с слиянием N-элементов на каждом уровне рекурсивного стека. Однако при быстром сортировке количество элементов, с которыми вы имеете дело, уменьшается, когда вы спускаетесь по стеку. Например, если вы посмотрите на глубину в середине рекурсивного стека, количество элементов, с которыми вы имеете дело, это N - 2 ^ ((logN)/2)) == N - sqrt (N).

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

Ответ 24

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

Ответ 25

Что-то, что нужно учитывать, это память. Для Mergesort требуется дополнительный массив, например "массив рабочих пространств". Если ваша память едва достаточна для хранения исходного массива, то слияние не будет работать.

Ответ 26

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

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

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

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

EDIT: я только выяснил, что случай слияния худшего/лучшего/avg-типа всегда является nlogn, но быстрый сортировка может варьироваться от n2 (худший случай, когда элементы уже отсортированы) до nlogn (avg/best case, когда pivot всегда делит массив в две половины).

Ответ 27

Это довольно старый вопрос, но поскольку я имел дело с обоими недавно, вот мои 2c:

Требуется сортировка сортировки в среднем ~ N log N сравнения. Для уже (почти) отсортированных отсортированных массивов это сокращается до 1/2 N log N, так как при слиянии мы (почти) всегда выбираем "левую" часть 1/2 N раз, а затем просто копируем правые 1/2 N элементов. Кроме того, я могу предположить, что уже отсортированный ввод делает синтаксис предсказателя ветки процессора, но правильно угадывает почти все ветки, тем самым предотвращая конвейеры.

Быстрая сортировка в среднем требует ~ 1,38 N log N сравнений. Это не очень выгодно из уже отсортированного массива с точки зрения сравнений (однако это происходит с точки зрения свопов и, вероятно, с точки зрения прогнозов ветвлений внутри ЦП).

Мои тесты на довольно современном процессоре показывают следующее:

Когда функция сравнения является функцией обратного вызова (например, в реализации libs-реализации qsort()), quicksort медленнее, чем mergesort, на 15% при случайном вводе и 30% для уже отсортированного массива для 64-битных целых чисел.

С другой стороны, если сравнение не является обратным вызовом, мой опыт в том, что quicksort превосходит mergesort на 25%.

Однако, если ваш (большой) массив имеет очень мало уникальных значений, сортировка слияния начинает набирать скорость в quicksort в любом случае.

Итак, может быть, нижняя строка: если сравнение стоит дорого (например, функция обратного вызова, сравнивая строки, сравнивая многие части структуры, которые в основном попадают во второй-третий-четвертый "если", чтобы сделать разницу) - есть вероятность, что вы будет лучше с сортировкой слияния. Для более простых задач quicksort будет быстрее.

Тем не менее все сказанное верно: - Quicksort может быть N ^ 2, но Sedgewick утверждает, что хорошая рандомизированная реализация имеет больше шансов на то, что компьютер, выполняющий сортировку, будет поражен молнией, а не N ^ 2 - Mergesort требует дополнительного пространства

Ответ 28

В c/С++ land, когда я не использую stl-контейнеры, я, как правило, использую quicksort, потому что он построен во время выполнения, а mergesort - нет.

Поэтому я считаю, что во многих случаях это просто путь наименьшего сопротивления.

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