Ответ 1
Быстрая сортировка хорошо подходит для сортировки на месте. В частности, большинство операций можно определить в терминах замены пар элементов в массиве. Для этого, однако, вы обычно "ходите" через массив с двумя указателями (или указателями и т.д.). Один начинается с начала массива, а другой в конце. Оба они прокладывают себе путь к середине (и вы закончите с определенным шагом раздела, когда они встречаются). Это дорого с файлами, потому что файлы ориентированы прежде всего на чтение в одном направлении, от начала до конца. Начиная с конца и поиска назад, обычно относительно дорого.
По крайней мере, в своем простейшем воплощении сортировка слияния в значительной степени противоположна. Легкий способ его реализации требует только просмотра данных в одном направлении, но включает в себя разбивку данных на две отдельные части, сортировку фрагментов, а затем их объединение обратно.
Со связанным списком легко взять (например) чередующиеся элементы в одном связанном списке и манипулировать ссылками для создания двух связанных списков из этих же элементов. С массивом переупорядочивание элементов, так что чередующиеся элементы попадают в отдельные массивы, легко, если вы готовы создать копию размером с исходные данные, но в противном случае более нетривиальную.
Аналогично, слияние с массивами легко, если вы объедините элементы из исходных массивов в новый массив с данными по порядку - но сделать это на месте без создания целой новой копии данных - совсем другая история. Со связанным списком объединение элементов из двух исходных списков в один целевой список тривиально - опять же, вы просто манипулируете ссылками, не копируя элементы.
Что касается использования Quicksort для создания отсортированных прогонов для внешнего сортирования слияния, он действительно работает, но он (явно) субоптимальный, как правило. Чтобы оптимизировать сортировку слияния, вы обычно хотите максимизировать длину каждого отсортированного "запуска" по мере его создания. Если вы просто читаете данные, которые будут вписываться в память, Quicksort и записывайте их, каждый пробег будет ограничен (немного меньше) размером доступной памяти.
Вы можете сделать немного лучше, чем это, как правило, хотя. Вы начинаете с чтения в блоке данных, но вместо того, чтобы использовать QuickSort, вы создаете кучу. Затем, когда вы пишете каждый элемент из кучи в отсортированный файл "run", вы читаете другой элемент из вашего входного файла. Если он больше, чем элемент, который вы только что записали на диск, вы вставляете его в свою существующую кучу и повторяете.
Элементы, которые меньше (т.е. относятся к элементам, которые уже были написаны), вы держите отдельно и вставляете во вторую кучу. Когда (и только когда) ваша первая куча пуста, а вторая куча заняла всю память, вы перестали записывать элементы в существующий файл "запустить" и начинать с нового.
Насколько эффективно это будет зависеть от начального порядка данных. В худшем случае (вход отсортирован в обратном порядке) он не делает ничего хорошего. В лучшем случае (вход уже отсортирован) он позволяет вам "сортировать" данные за один проход через вход. В среднем случае (ввод в случайном порядке) он позволяет приблизительно удвоить длину каждого сортированного прогона, который обычно улучшает скорость примерно на 20-25% (хотя процент варьируется в зависимости от того, насколько больше ваших данных, чем доступная память).