Почему mergesort O (log n)?

27

Mergesort является алгоритмом «разделяй и властвуй» и имеет значение O (log n), потому что вход многократно уменьшается вдвое. Но разве это не должно быть O (n), потому что, несмотря на то, что каждый цикл ввода делится пополам на каждый цикл, каждый элемент ввода должен быть повторен для замены в каждом массиве пополам? Это по сути асимптотически O (n) в моем уме. Если возможно, приведите примеры и объясните, как правильно считать операции! Я еще ничего не кодировал, но я смотрел на алгоритмы онлайн. Я также приложил gif того, что использует Википедия, чтобы наглядно показать, как работает mergesort.

введите описание изображения здесь

настойчивость
источник
34
Это O (n log n)
Эсбен Сков Педерсен
19
Даже алгоритм сортировки Бога (алгоритм гипотетической сортировки, который имеет доступ к оракулу, который сообщает ему, где каждый элемент принадлежит) имеет время выполнения O (n), потому что ему нужно переместить каждый элемент, который находится в неправильной позиции, по крайней мере, один раз.
Филипп

Ответы:

59

Это O (n * log (n)), а не O (log (n)). Как вы точно догадались, весь ввод должен быть повторен, и это должно происходить O (log (n)) раз (вход может быть только вдвое O (log (n)) раз). n элементов повторяется log (n) раз дает O (n log (n)).

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

DeadMG
источник
3
s / быстрее / с меньшей сложностью /
JK.
34

Сложность сортировки слиянием O (nlogn) и НЕ O (logn).

Сортировка слиянием - это алгоритм «разделяй и властвуй». Думайте об этом с точки зрения 3 шагов -

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

Теперь для шагов 1 и 3, то есть между O (1) и O (n), O (n) выше. Давайте рассмотрим шаги 1 и 3, которые занимают всего O (n) времени. Скажем, это cn для некоторой константы c.

Сколько раз выполняются эти шаги?

Для этого посмотрите на дерево ниже - для каждого уровня сверху вниз Уровень 2 вызывает метод слияния по 2 подмассивам длины n / 2 каждый. Сложность здесь 2 * (cn / 2) = cn Уровень 3 вызывает метод слияния на 4 подмассивах длины n / 4 каждый. Сложность здесь 4 * (cn / 4) = cn и так далее ...

Теперь высота этого дерева (logn + 1) для данного n. Таким образом, общая сложность равна (logn + 1) * (cn). Это O (nlogn) для алгоритма сортировки слиянием.

Сортировка слиянием для n элементов

Изображение предоставлено: Академия Хана

Шантану Альши
источник
9

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

T (n) = 2T (n / 2) + ɵ (n)

Вышеуказанное повторение может быть решено с использованием метода дерева повторений или метода Master. Это относится к случаю II Master Method и решение повторения rence (n log n).

Временная сложность сортировки слиянием составляет ɵ (nLogn) во всех 3 случаях (наихудший, средний и лучший), поскольку сортировка слиянием всегда делит массив на две половины и занимает линейное время для объединения двух половин.

Он разделяет входной массив на две половины, вызывает себя для двух половинок и затем объединяет две отсортированные половины. Функция merg () используется для объединения двух половинок. Слияние (arr, l, m, r) является ключевым процессом, который предполагает, что arr [l..m] и arr [m + 1..r] отсортированы и объединяет два отсортированных подмассива в один. Смотрите следующую реализацию C для деталей.

MergeSort(arr[], l,  r)
If r > l
     1. Find the middle point to divide the array into two halves:  
             middle m = (l+r)/2
     2. Call mergeSort for first half:   
             Call mergeSort(arr, l, m)
     3. Call mergeSort for second half:
             Call mergeSort(arr, m+1, r)
     4. Merge the two halves sorted in step 2 and 3:
             Call merge(arr, l, m, r)

введите описание изображения здесь

Если мы более внимательно посмотрим на диаграмму, то увидим, что массив рекурсивно разделен на две половины, пока размер не станет равным 1. Как только размер станет равным 1, процессы слияния вступают в действие и начинают объединять массивы обратно до тех пор, пока весь массив не станет слиты.

Нишант Сетхи
источник
1
Не могли бы вы подробнее рассказать о природе этой части слияния и о том, как она влияет на производительность O (n log n)?
Сложность функции слияния - O (n), так как она принимает 2 массива в качестве входных данных, сравнивает их и выдает выходные данные в новых. Поскольку он сравнивает каждый элемент с каждым другим элементом в массиве, сложность этой функции слияния оказывается равной O (n).
Нишант Сетхи
1
Мне нравится такая визуализация!
spaaarky21
0

Алгоритмы сортировки, основанные на сравнении, имеют нижнюю границу 𝞨(n*log(n)), что означает, что невозможно иметь алгоритм сортировки на основе сравнения с O(log(n))временной сложностью.

Кстати, сортировка слиянием есть O(n*log(n)). Подумай об этом так.

[ a1,a2,         a3,a4,         a5,a6,          a7,a8     .... an-3,an-2,     an-1, an ] 
   \ /            \  /           \ /             \  /            \  /            \  /    
    a1'            a3'            a5'             a7'            an-3'           an-1'    
      \            /                \             /                 \             /
            a1''                          a5''                       an-3''
             \                             /                         /
                          a1'''                                     /
                           \
                                              a1''''

Это выглядит перевернутым двоичным деревом.

Пусть размер ввода будет n.

каждый a_n представляет список элементов. Первая строка a_nимеет только один элемент.

На каждом уровне сумма стоимости слияния в среднем равна n(есть угловые случаи, стоимость которых ниже [1]). И высота дерева есть log_2(n).

Итак, временная сложность сортировки слиянием равна O(n*log_2(n)).

[1] при сортировке по списку, который уже отсортирован, что называется наилучшим случаем. стоимость снижена до n/2 + n/4 + n/8 + .... + 1 = 2^log_2(n) -1 ~ O(n). (предположим, что длина nравна степени двух)

W. ПК
источник
-2

Сортировка - это NP-полная проблема в информатике (Неполиномиальная проблема). Это означает, что, если математически не доказано, вы не можете опуститься ниже O (n log n) при сортировке списка элементов.

Проверьте эту статью в Википедии ( https://en.wikipedia.org/wiki/P_versus_NP_problem )

По сути, до сих пор никому не удалось доказать это (P == NP), и если вы это сделаете, то сначала станете миллионером, а потом начнете третью мировую войну из-за того, что вы сможете сломать все используемые механизмы безопасности паб / закрытый ключ. везде сегодня :)

slux83
источник
2
Это не то, что означает NP. Даже BubbleSort в P. Вы должны изо всех сил пытаться сделать сортировку, которая не в P (например, BogoSort)
Caleth