Можно ли избежать шага «разделяй» в слиянии?

13

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

Таким образом, сортировка слиянием - это алгоритм «разделяй и властвуй». Пока я смотрел на приведенную выше диаграмму, я думал, можно ли вообще обойти все этапы разделения.

Если вы перебираете исходный массив при переходе на два, вы можете получить элементы по индексам i и i + 1 и поместить их в свои отсортированные массивы. Если у вас есть все эти подмассивы ([7,14], [3,12], [9,11] и [2,6], как показано на схеме), вы можете просто перейти к обычной процедуре слияния, чтобы получить отсортированный массив.

Является ли итерация по массиву и немедленная генерация требуемых подмассивов менее эффективной, чем выполнение шагов деления во всей их полноте?

Jimmy_Rustle
источник
Связанный: cs.stackexchange.com/questions/77075/…
Омар

Ответы:

29

Путаница возникает из-за разницы между концептуальным описанием алгоритма и его реализацией .

Логически сортировка слиянием описывается как разделение массива на более мелкие массивы, а затем их объединение. Однако «разбиение массива» не подразумевает «создание совершенно нового массива в памяти», или что-то в этом роде - это можно реализовать в коде как

/*
 * Note: array is now split into  [0..n) and [n..N)
 */

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

psmears
источник
4
Лично мне очень нравится сортировка по принципу «снизу вверх», потому что ее проще реализовать таким образом, чтобы избежать выделения временного буфера на каждом уровне рекурсии. Вместо этого вы выделяете буфер один раз и пинг-понг между ними.
храповик урод
Это - деление в вычислительном отношении является предложением no-op ... plus OPs - это просто введение эквивалента слияния одноэлементных массивов и начало использования слияния со 2-го шага, что кажется избыточным, потому что оригинальное слияние работает так же хорошо. Нет смысла оптимизировать это. Это только вводит избыточные понятия и логику.
luk32
@ratchetfreak: Мне тоже это нравится, но, к сожалению, это не эквивалентно нисходящему (по крайней мере, версии, которую я знаю). Он будет выполнять слияние по-другому, в основном округляя до следующей длины массива степени 2, что, я думаю, может быть даже немного медленнее. Знаете ли вы о восходящей версии, которая делает то же самое слияние, не платя огромную стоимость где-то еще?
user541686
@Mehrdad единственная реальная проблема - маленький хвост, который нужно объединить. В худшем случае это означает еще один проход для объединения в один элемент для массивов длины 1<<n+1. Хотя я уверен, что вы можете отрегулировать вещи так, чтобы слишком маленький хвост слился с нижним проходом.
фрик с трещоткой
@psmears «вам просто не нужна никакая работа с компьютера» - так что я предполагаю, что затраты на производительность n вызовов некоторой рекурсивной функции деления (7 вызовов в диаграмме примера) в основном незначительны?
Jimmy_Rustle
11

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

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

В противном случае сортировка без разбиения массива невозможна. Фактически сущность сортировки слиянием - это деление и сортировка подмассивов, т. Е. Разделяй и властвуй.

fade2black
источник