почему мы должны использовать N-way merge? каковы его преимущества перед 2-way merge?

Я попытался прочитать несколько статей о n-way merge, но не понял концепцию. Я смущен, почему вы используете N-way merge над 2-way merge? Например, почему вы разделяете массив на 3 части, сортируете их, затем выполняете двустороннее слияние 2 частей, а затем двустороннее слияние 3-й части с этими объединенными 2 частями:)

спасибо

2 ответов


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

это приведет вас к следующей формуле (в анализе времени):

n/2 * 2 + n/4 * 4 + ... 1 * n = n * log2n

теперь, если вы сделаете трехстороннее слияние, вы разделите массив на 3. Разница с предыдущим методом двоякая:

  • глубина разделения теперь log3n.
  • во время слияния вместо сравнения 2 элементов вам нужно найти минимум 3 элемента.

это означает, что в самой базовой реализации, вы получите такую формулу:

n/3 * 2*3 + n/9 * 2*9 + ... 1 * 2*n = 2 * n * log3n

обратите внимание, что 2 умножается, потому что поиск минимум трех элементов состоит из 2 операций.

асимптотически эти два являются Θ(nlogn). Однако, возможно (я не пробовал) на практике трехсторонняя сортировка слияния будет дайте лучшую производительность из-за его log3n. Тем не менее, с log2n для n = 1000000-это всего лишь 20, и log3n для того же числа 12.5, я сомневаюсь, что эта оптимизация будет действительно эффективной, если n довольно большой.


С умной реализацией слияние k-way действительно может оказать хорошее влияние на сортировку слияния. Идея в том, что как только вы найдете минимум k элементы, вы уже знаете, отношения между остальными k-1 элементы это не минимум. Поэтому, как только вы потребляете этот минимальный элемент из соответствующего списка, вам нужно только сравнить новое значение этого списка и найти его порядок относительно оставшегося k-1 элементы. Используя кучу, это было бы довольно тривиально.


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


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

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

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

Если вы делаете это на регулярной основе, у вас, вероятно, есть довольно высококачественное оборудование для этого. Если вы поместили каждый промежуточный файл на отдельный диск (и имеете по крайней мере еще один для вывода), вы можете почти наверняка улучшить скорость, объединив все данные сразу, а не только две. Процесс обычно будет связан с вводом-выводом, поэтому чтение с (скажем) 8 дисков за раз обычно будет примерно в 4 раза быстрее, чем чтение только с 2 дисков за раз (хотя это зависит от вашего выходного диска с такой пропускной способностью, что может быть неверно). Избегая создания более промежуточных файлов (что потребует дальнейшего слияния), ваша общая скорость, вероятно, улучшится еще больше.