Сложность O(n) означает, что сортировка слиянием в худшем случае занимает пространство памяти, равное количеству элементов, присутствующих в исходном массиве. Но разве он не создал новые массивы при выполнении рекурсивных вызовов? Как это место не считается?
Как сортировка слиянием имеет пространственную сложность O (n) для наихудшего случая?
Ответы (4)
В худшем случае реализация сортировки слиянием сверху вниз может занять больше места, чем исходный массив, если она выделяет обе половины массива в mergesort() перед выполнением рекурсивных вызовов самой себе.
Более эффективная сортировка слиянием сверху вниз использует функцию входа, которая выполняет однократное выделение временного буфера, передавая адрес временного буфера в качестве параметра одной из пар взаимно рекурсивных функций, которые генерируют индексы и объединяют данные между двумя массивами.
В случае сортировки слиянием снизу вверх можно использовать временный массив в 1/2 размера исходного массива, объединяя обе половины массива, в результате чего первая половина данных находится во временном массиве, а вторая половина в исходном массиве, а затем выполнить окончательное слияние обратно в исходный массив.
Однако пространственная сложность равна O(n) в любом случае, поскольку константы типа 2 или 1/2 игнорируются для большого O.
MergeSort достаточно одного буфера того же размера, что и исходный массив.
В обычной версии вы выполняете слияние из массива в дополнительный буфер и копируете обратно в массив.
В расширенной версии вы выполняете слияния из массива в дополнительный буфер и наоборот, попеременно.
Примечание. Этот ответ неверен, как мне было указано в комментариях. Я оставлю его здесь, так как считаю, что он будет полезен большинству людей, которые хотят понять эти вещи, но помните, что этот алгоритм на самом деле называется сортировка слиянием на месте и может иметь другую сложность во время выполнения, чем чистый сортировка слиянием.
Сортировку слиянием легко реализовать, чтобы использовать один и тот же массив для всего без создания новых массивов. Просто отправьте границы в каждом рекурсивном вызове. Что-то вроде этого (в псевдокоде):
mergesort(array) ->
mergesort'(array, 0, length of array - 1)
mergesort'(array, start, end) ->
mergesort'(array, start, end/2)
mergesort'(array, end/2+1, end)
merge(array, start, end/2, end/2+1, end)
merge(array, start1, end1, start2, end2) ->
// This function merges the two partitions
// by just moving elements inside array
В сортировке слиянием пространственная сложность всегда равна omega(n), так как вам нужно где-то хранить элементы. Дополнительная пространственная сложность может составлять O(n) в реализации с использованием массивов и O(1) в реализациях связанных списков. На практике реализации, использующие списки, требуют дополнительного места для указателей на списки, поэтому, если у вас уже нет списка в памяти, это не имеет значения. редактировать, если вы считаете кадры стека, то это O(n)+ O(log n) , так что еще O(n) в случае массивов. В случае списков это O(log n) дополнительной памяти.
Вот почему при анализе сложности сортировки слиянием люди упоминают «требования к дополнительному пространству» или что-то в этом роде. Очевидно, что вам нужно где-то хранить элементы, но всегда лучше упомянуть «дополнительную память», чтобы держать пуристов в страхе.