Сортировка слиянием - это алгоритм сортировки, который работает, разделяя заданный список пополам, рекурсивно сортируя оба меньших списка и объединяя их обратно в один отсортированный список. Базовый случай рекурсии приходит к одноэлементному списку, который не может быть разделен далее, но по определению уже отсортирован.
Выполнение алгоритма в списке [1,7,6,3,3,2,5]
можно визуализировать следующим образом:
[1,7,6,3,3,2,5]
/ \ split
[1,7,6,3] [3,2,5]
/ \ / \ split
[1,7] [6,3] [3,2] [5]
/ \ / \ / \ | split
[1] [7] [6] [3] [3] [2] [5]
\ / \ / \ / | merge
[1,7] [3,6] [2,3] [5]
\ / \ / merge
[1,3,6,7] [2,3,5]
\ / merge
[1,2,3,3,5,6,7]
Задание
Напишите программу или функцию, которая принимает список целых чисел любым разумным способом в качестве входных данных и визуализирует различные разделы этого списка, сортируя их с помощью алгоритма сортировки слиянием. Это означает, что вам не нужно выводить график, как указано выше, но только списки в порядке:
[1,7,6,3,3,2,5]
[1,7,6,3][3,2,5]
[1,7][6,3][3,2][5]
[1][7][6][3][3][2][5]
[1,7][3,6][2,3][5]
[1,3,6,7][2,3,5]
[1,2,3,3,5,6,7]
Кроме того, любая разумная нотация списка подходит, поэтому следующие данные также могут быть действительными:
1 7 6 3 3 2 5
1 7 6 3|3 2 5
1 7|6 3|3 2|5
1|7|6|3|3|2|5
1 7|3 6|2 3|5
1 3 6 7|2 3 5
1 2 3 3 5 6 7
Наконец, способ разбить список на два меньших списка зависит от вас, если длина обоих результирующих списков отличается не более чем на один. Это означает, что вместо разделения [3,2,4,3,7]
на [3,2,4]
и [3,7]
вы также можете разделять, беря элементы по четным и нечетным индексам ( [3,4,7]
и [2,3]
) или даже случайным образом разбивая разделение каждый раз.
Это код-гольф , поэтому выигрывает самый короткий код на любом языке, измеряемый в байтах.
Контрольные примеры
Как отмечалось выше, фактический формат и способ разделения списков пополам зависит от вас.
[10,2]
[10][2]
[2,10]
[4,17,1,32]
[4,17][1,32]
[4][17][1][32]
[4,17][1,32]
[1,4,17,32]
[6,5,4,3,2,1]
[6,5,4][3,2,1]
[6,5][4][3,2][1]
[6][5][4][3][2][1]
[5,6][4][2,3][1] <- Important: This step cannot be [5,6][3,4][1,2], because 3 and 4 are on different branches in the the tree
[4,5,6][1,2,3]
[1,2,3,4,5,6]
источник
[[1,2],[3],[4,5],[6]]
Этап на самом деле является правильным решением, так как сортировка слиянием работает рекурсивно. То есть, если мы начнем с[1,2,3,4,5,6]
и разделим его на[1,2,3]
и[4,5,6]
, то эти списки будут обрабатываться независимо, пока они не будут объединены на последнем этапе.[3]
и[2,1]
, то они находятся в разных ветвях, поэтому мы не можем объединиться,[3]
а[2]
после[2,1]
делим на[2]
и[1]
.Ответы:
Haskell ,
137128127125121109106 байт(-2) + (- 4) = (- 6) байт благодаря nimi ! Изменение его для сбора всех шагов в списке (опять же из-за nimi) экономит еще 12 байтов.
Еще 3 байта из-за Лайкони с привязкой к шаблону и умным использованием списка для кодирования защиты.
Попробуйте онлайн!
Разделение списков на нечетные и четно расположенные элементы является более коротким кодом, чем на две последовательные половины, потому что тогда мы избавлены от необходимости измерять их
length
.Работает, «печатая» списки, затем возвращаясь к разделенным спискам (
x >>= h
), если на самом деле было какое-либо разделение, и «печатая» отсортированные списки; начиная с одного списка ввода; при условии непустого ввода. И вместо фактической печати, просто собирая их в список.Список
g[[6,5..1]]
, выводимый построчно:источник
p=print
и три разаp
. Попробуйте онлайн!g
вы можете собрать все шаги в списке и вернуть его. Попробуйте онлайн!g x|y<-x>>=h=x:[z|x/=y,z<-g y++[sort<$>x]]
сохраняет еще несколько байтов.Wolfram Language (Mathematica) ,
146127111102 байтаПопробуйте онлайн!
Возвращает,
List
который содержит шаги.объяснение
Во входных данных разбить все
List
s, содержащие 2 или более целых чисел пополам. Первый подсписок имеет элементы с нечетным индексом (1-индексированный), а второй имеет элементы с четным индексом.Повторяйте это, пока ничего не изменится (т.е. все подсписки имеют длину 1). Сохраните все промежуточные результаты. Сохраните это (
List
всех шагов) вu
.Оставьте последний элемент
u
и переверните его.Из приведенного выше результата отсортируйте все вхождения списка целых чисел.
источник
Чистый ,
228206168157140121104 байтаСоздает список этапов от концов внутрь, используя тот факт, что
n
-ый элемент с конца является отсортированной версиейn
-ого элемента с самого начала.Идея из комментария Юнг Хван Мин
Попробуйте онлайн!
источник
Древесный уголь ,
145133123122 байтаПопробуйте онлайн! Ссылка на подробную версию кода.
По-прежнему приходится обходить ошибки с древесным углем ...Редактировать: Сохранено 5 байт с использованием двойногоMap
в качестве понимания массива для бедняков. Сохранено 4 байта с помощьюPop
двойной итерации по массиву. Сохранено 3 байта с использованием конкатенации вместоPush
. Сэкономьте 10 байт, придумавwhile
условие для игры в гольф, которое также позволяет избежать ошибки древесного угля. Сэкономил 1 байт, обнаружив, что Charcoal действительно имеет оператор фильтра. Объяснение:Разбейте ввод на пробелы, а затем оберните результат во внешний массив, сохранив его в
q
.Повторите, пока первый элемент
q
имеет более одного элемента. (Первый элементq
всегда содержит наибольшее количество элементов из-за способа разделения списков на два.)Распечатать элементы
q
объединенных с пробелами и вертикальными линиями. (Массив приводит к тому, что результат печатается в отдельной строке. Существуют и другие способы достижения этого при том же количестве байтов.)Создайте список, продублировав каждый элемент
q
, затем сопоставьте его с этим списком и возьмите половину каждого списка (используя подход альтернативного элемента), сохранив результат обратноq
.Распечатать элементы
q
объединенных с пробелами и вертикальными линиями. На самом деле, на данный момент элементыq
являются либо пустыми, либо одноэлементными списками, поэтому объединение их просто превращает их в пустые строки или их элементы. Пустые строки добавят ненужные конечные строки, чтобы они отфильтровывались. Сглаженный оператор был бы гольфистом (что-то вроде⟦⪫Σθ|⟧
).Повторите, пока
q
имеет более одного элемента. (Следующий код требует четного количества элементов.)Копировать
q
вh
, но обратное (см ниже), и сбросq
в пустой список.Повторите, пока
h
не пусто.Извлеките следующий элемент
h
вe
. (Pop
выдержки из конца, поэтому я должен повернуть вспятьq
.)Инициализируйте
z
пустой список.Зацикливание на элементах следующего элемента
h
.Копировать
e
вd
и сброситьe
в пустой список.Зацикливаться на элементах
d
.Нажмите их
z
или вe
зависимости от того, меньше ли они текущего элемента следующего элементаh
.Нажмите текущий элемент следующего элемента
h
вz
.Объедините
z
все оставшиеся элементыe
и нажмите на нихq
. Это завершает слияние двух элементовh
.Распечатать элементы
q
объединенных с пробелами и вертикальными линиями.источник
while (...Map(...)...)
ошибке я уже говорил вам.Python 2 ,
145144 байтаИдея из комментария JungHwan Min
-1 байт благодаря Джонатану Фреху
Попробуйте онлайн!
источник
<2
вместо==1
.JavaScript (ES6), 145 байт
Принимает входные данные как массив в массиве, то есть
f([[6,5,4,3,2,1]])
. Работает, генерируя первую и последнюю строки выходных данных, затем разделяясь и вызывая себя снова, пока каждый вложенный массив не будет иметь длину 1. Вот базовая демонстрация того, как он работает:источник
Шелуха , 14 байт
Принимает массив, содержащий один массив. Попробуйте онлайн!
объяснение
Встроенный
½
берет массив и разбивает его посередине. Если его длина нечетная, первая часть длиннее на один элемент. В[a]
результате получается одноэлементный массив,[[a],[]]
а пустой массив[]
дает[[],[]]
, поэтому перед применением необходимо удалить пустые массивыU
.источник
Stax ,
116 (÷ 3>)3829 байт CP437-9 байтов за комментарий @recursive. Теперь входные данные задаются как синглтон, единственным элементом которого является массив чисел, подлежащих сортировке.
Попробуйте онлайн!
Распакованная версия с 35 байтами:
объяснение
Код можно разбить на две части. Первая часть визуализирует разделение, а вторая визуализирует слияние.
Код для визуализации разбиения:
Код для визуализации слияния:
Старая версия, фактически строящая структуру вложенного списка.
cc0+=
используется трижды в коде, чтобы проверить, является ли вершина стека скаляром или массивом.{{cc0+=!{x!}Mm',*:}}X
строит блок, который рекурсивно вызывает себя для правильного вывода вложенного массива чисел. (Вывод по умолчанию в Stax векторизует вложенный массив перед печатью).Есть два других блока, которые выполняют разбиение и объединение соответственно. Они слишком многословны, и я не хочу объяснять (в исторической версии этого поста есть немного больше информации, но не ожидайте слишком многого).
источник
cH!
может быть использован вместоcH%!
.{Nd}M
может быть замененоT
также.