Сортировка слиянием
В этой задаче вы реализуете функцию слияния сортировки слиянием. В частности, вы должны создать функцию или программу или глагол или аналог, который берет два списка, каждый из которых отсортирован в порядке возрастания, и объединяет их в один список, отсортированный в порядке возрастания. Требования:
- Ваш алгоритм должен занимать асимптотически линейное количество времени в размере ввода. Пожалуйста, прекратите давать O (n ^ 2) решения.
- Вы не можете использовать какие-либо встроенные функции, способные сортировать список, объединять список или что-то в этом роде. Авторское усмотрение.
- Код должен быть в состоянии обрабатывать повторяющиеся элементы.
- Не беспокойтесь о пустых списках.
Примеры:
merge([1],[0,2,3,4])
[0,1,2,3,4]
merge([1,5,10,17,19],[2,5,9,11,13,20])
[1, 2, 5, 5, 9, 10, 11, 13, 17, 19, 20]
Это код-гольф , поэтому победит самый короткий код!
b=a;b=b.length
может дублировать весь массивa
(и привести к O (n ^ 2) времени, если выполняется для каждого элемента) или дублировать только ссылку на массив (O (n) времени). Какой из них считается?Ответы:
Ребму (
3532 символов)Тестовое задание
Около
Rebmu - это диалект Rebol, который допускает «скопление» обычного кода в ситуациях, требующих краткости. Без кода код работает примерно так:
Я полагаю, что это удовлетворяет требованию O (n), так как блок до не более чем зациклен столько раз, сколько длина ввода (и
reverse
только переключает порядок контейнера входных блоков, а не самих блоков). Использованиеtake
- это, пожалуй, свобода, но все еще незначительный удар по эффективности.Ребол (
8375 символов)Просто немного по-другому: в Rebol пути являются более коротким выражением, чем
first
илиsecond
.a
входной блок, содержащий два блока:источник
Решения ОП:
Haskell
494440Python
1311051019993Благодаря @Evpok:
источник
a%b=a++b
после сопоставления с основным шаблоном, чтобы обрабатывать пустые списки, что сбрит пару символов.Python (79)
Python (95, если нам не разрешено возвращать генератор)
Itertools - решение всех мирских проблем.
Бонус: оба из них работают с произвольным числом списков и ДЕЙСТВИТЕЛЬНО беспокоятся о пустых списках (например, они с радостью возьмут 2 пустых списка и вернут пустой список, или возьмут 1 пустой и 1 непустой список, и они возвратят непустой. Еще одна добавленная особенность 2 неубежденных: они также будут работать без аргументов и просто вернут пустой список.)
Ungolfed:
источник
r+=[...]
вместоr.append(...)
(каждый раз сохраняет 4С - 75
Это работает с
NULL
завершенными массивамиint *
, хотя будет одинаково хорошо работать для указателей на другие типы, заменяя соответствующую функцию сравнения**b < **a
(например,strcmp(*b, *a) < 0
).Ungolfed:
источник
Golfscript,
2927302926 байтовили
Как это устроено
Команда
будет обработан следующим образом:
Выход:
источник
[1 1 1 ... 2]
и[1 1 1 ... 3]
), поскольку сравнение массивов (а не их первых элементов) было бы очень медленным в этом случае.J -
4233Модифицированная версия отсюда + комментарий @algorithmshark
k
добавляет заголовок правого массива к объединенным хвостам обоих массивов.k~
то же самое, но с перевернутыми массивами.(>&{.)
сравнивает головы. Код выдаст ошибку, если один из массивов пуст, в этом случае мы возвращаем только их конкатенацию,
.источник
/:~ a,b
запрещенный ответ (вместе с[:/:~,
), что вы стреляете за самый короткий ответ, который не включает/:
, верно?m=:k~`k@.(>&{.)`,@.(0=*&#)
экономит 2 символаk=:(m}.),~0{]
иm=:k~`k@.(>&{.) ::,
. Мы используем,0{
чтобы выдать ошибку, когда список пуст, а затем перехватить эту ошибку и выйти с помощью,
.JavaScript (ES6),
6979 байтКак это устроено
источник
<
оператором недопустимо, так как выполняется сравнение строк:f([123, 456, 789], [1, 2, 3, 4, 5]) => [1, 123, 2, 3, 4, 456, 5, 789]
[]
последующим преобразованием его в строку требует времени O (n). Один раз для всех n элементов массива требуется O (n ^ 2) времени.Питон
(63) (69)(71)Я написал это до того, как увидел комментарии OP о времени выполнения других ответов, так что это еще одно решение, которое в алгоритме использует O (n), но не его реализацию.
источник
return[a.pop(0)]+(a and m(a,b)or b)
Haskell, 35 байт
Haskell, 30 байт (не конкурирует)
Эта неконкурентная версия гарантирует только линейное время выполнения, если
a
иb
имеют непересекающиеся элементы; в противном случае он по-прежнему работает правильно, но может использовать квадратичное время.источник
PHP
91 9891 байтedit # 1: Пусто
$b
требует дополнительного условия в фигурных скобках (+7).редактирование # 2: незначительные игры в гольф
редактирование # 3: добавлена вторая версия
довольно прямо. Самая приятная часть - это троица внутри
array_shift
(которая терпит неудачу, если вы попробуете это без фигурных)
или
ungolfed
тестовое задание
источник
$a&(!$b|$a[0]<$b[0])?$a:$b
вместо${$a&(!$b|$a[0]<$b[0])?a:b}
array_shift
Параметр используется для справки. Это должна быть переменная; выражение не сработает.Go, 124 символа
источник
JavaScript - 133
Такой же подход, как и у ОП.
источник
perl, 87 символов / perl 5.14, 78 + 1 = 79 символов
Эта реализация забивает ссылки на входные массивы. Кроме этого, это довольно просто: хотя в обоих массивах есть что-то, сдвиньте нижнюю из двух. Затем верните объединенный бит, объединенный с любыми оставшимися битами (останется только один из @ $ x или @ $ y). Прямолинейный perl5, 87 символов:
Использование perl 5.14.0 и его новомодного сдвига массива: 78 символов + 1 штраф = 79 символов:
источник
*
вместо того,&&
чтобы сохранить байт. И даже больше, еслиsub M{map{shift(!@$x+@$y*($$y[0]<$$x[0])?$y:$x)}map@$_,($x,$y)=@_}
Ява: 144
Это довольно просто. Функция, которая берет два массива и возвращает один, объединенную версию, в гольф и без оболочки компиляции:
Ungolfed (с компилируемой и запускаемой оболочкой):
Пример исполнения:
Любые советы по сокращению будут оценены.
источник
Скала, 97 байт
Рекурсивное решение с O (n). Чтобы сократить код, иногда операция выполняется путем переключения 2 взаимозаменяемых параметров, то есть f (a, b) вызывает f (b, a).
Ungolfed:
источник
APL (32)
Объяснение:
источник
LISP, 117 байт
Алгоритм заканчивается
n + 1
итерациями, гдеn
длина самого короткого списка на входе.источник
ПИГ (50)
PYG (снова 64, если генераторы не разрешены.):
Адаптация моего ответа на Python .
источник
Python - 69 байт
Если бы порядок ввода и вывода был убывающим, это можно было бы сократить до 61 байта :
И далее до 45 байтов, если разрешены генераторы:
источник
pop(0)
могут быть реализованы в O (1) и,+=
по крайней мере, могут быть реализованы лучше, чем O (n) (см. Ссылку). Кстати, ваше решение использует+=
(т.е.append
иextend
) так же часто, как и мое. В любом случае, все это вопрос реализации (насколько я знаю), поэтому в (вымышленной) реализации Python, где списки реализованы в виде списков, моя функция - O (n). Наконец, ваш вопрос требует, чтобы алгоритм был O (n), а мой -.Perl 6: 53 персонажа
Переход от какой из
a
илиb
имеет меньшее значение, до тех пор ,a
исключающее ИЛИb
(a^b
) не верно. Затем верните все, что осталось, сглаживая ([]
) массивы в списке (a[],b[]
).Предполагая, что сдвиг от начала массива равен O (n), наихудший случай - два сравнения и один сдвиг на элемент, поэтому алгоритм - O (n).
источник
JavaScript (ES5)
908690 байтedit: (90 -> 86) Переместил троичный в условие цикла. Идея украдена у Дениса.
edit: (86 -> 90) Удалено приведение Array к String, поскольку оно нарушает требование O (n) .
источник
Mathematica,
137135Входные данные:
Выход:
Ungolfed:
Возможно, может быть лучше.
источник
m[a:{x___,y_},b:{___,z_}]:=If[y<z,b~m~a,{x}~m~b~Join~{y}];{}~m~b_=b;
R, 80
То же решение, что и в Scala и других языках. Я не уверен, что x [-1] - это O (1).
источник
Mathematica, 104 байта
Анонимная функция хранит длину двух входных списков в переменных,
m
аn
затем каждую итерациюDo
циклаSow
s элемент одного из списков, увеличивающий счетчик для этого списка (i
для первого,k
для второго) на единицу. Если один из счетчиков превышает длину списка,If
оператор всегда будетSow
элементом из другого списка. Послеn+m
операций все элементы позаботились.Reap
или скорее часть[[2,1]]
его вывода представляет собой список элементов в том порядке, в котором они былиSow
n.Я не уверен во внутренних функциях (доступ к части списка -
O(1)
операция или нет), но время выглядело достаточно линейно на моей машине по отношению к длине списка ввода.источник