Реализовать алгоритм сортировки Таноса


93

Алгоритм сортировки выглядит так:

Пока список не отсортирован, закрепите половину всех элементов (удалите их из списка). Продолжайте, пока список не будет отсортирован или пока не останется только один элемент (который сортируется по умолчанию). Этот алгоритм сортировки может давать разные результаты в зависимости от реализации.

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

Входной список может содержать произвольное количество элементов (в пределах разумного, скажем, до 1000 элементов), а не только идеально делимые списки из 2 ^ n элементов. Вам придется либо удалить (n + 1) / 2, либо (n-1) / 2, если список нечетный, либо жестко задан, либо выбран случайным образом во время выполнения. Решите сами: что бы сделал Танос, если бы во вселенной было нечетное количество живых существ?

Список сортируется, если ни один элемент не меньше предыдущего. Дубликаты могут появляться на входе и на выходе.

Ваша программа должна получить массив целых чисел (через stdin или в качестве параметров, либо отдельные элементы, либо параметр массива) и вернуть отсортированный массив (или вывести его в stdout).

Примеры:

// A sorted list remains sorted
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]

// A list with duplicates may keep duplicates in the result
[1, 2, 3, 4, 3] -> [1, 3, 3] // Removing every second item
[1, 2, 3, 4, 3] -> [3, 4, 3] -> [4, 3] -> [3] // Removing the first half
[1, 2, 3, 4, 3] -> [1, 2] // Removing the last half

[1, 2, 4, 3, 5] может дать разные результаты:

// Removing every second item:
[1, 2, 4, 3, 5] -> [1, 4, 5]

или же:

// Removing the first half of the list
[1, 2, 4, 3, 5] -> [3, 5] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [4, 3, 5] -> [3, 5] // With (n-1)/2 items removed

или же:

// Removing the last half of the list
[1, 2, 4, 3, 5] -> [1, 2] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [1, 2, 4] // With (n-1)/2 items removed

или же:

// Taking random items away until half (in this case (n-1)/2) of the items remain
[1, 2, 4, 3, 5] -> [1, 4, 3] -> [4, 3] -> [4]

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

22
Разве нам не нужно сортировать и исключать половину ответов ...
Sumner18

4
Похожий тест: [9, 1, 1, 1, 1]. Мой собственный алгоритм не удалось на этом входе
Конор О'Брайен

Ответы:





12

Brachylog (v2), 6 байт

≤₁|ḍt↰

Попробуйте онлайн!

Это функция представления. Вход слева, вывод справа, как обычно. (Ссылка TIO использует аргумент командной строки, который автоматически превращает функцию в полноценную программу, чтобы вы могли увидеть ее в действии.)

объяснение

≤₁|ḍt↰
≤₁       Assert that {the input} is sorted {and output it}
  |      Handler for exceptions (e.g. assertion failures):
   ḍ     Split the list into two halves (as evenly as possible)
    t    Take the last (i.e. second) half
     ↰   Recurse {and output the result of the recursion}

Бонус раунд

≤₁|⊇ᵇlᵍḍhtṛ↰

Попробуйте онлайн!

Снимок должен быть случайным, не так ли? Вот версия программы, которая выбирает выживающие элементы случайным образом (при этом гарантируя, что половина выживает в каждом раунде).

≤₁|⊇ᵇlᵍḍhtṛ↰
≤₁            Assert that {the input} is sorted {and output it}
  |           Handler for exceptions (e.g. assertion failures):
   ⊇ᵇ         Find all subsets of the input (preserving order)
     lᵍ       Group them by length
       ḍht    Find the group with median length:
         t      last element of
        h       first
       ḍ        half (split so that the first half is larger)
          ṛ   Pick a random subset from that group
           ↰  Recurse

Это было бы намного короче, если бы мы могли изменить порядок элементов, но почему алгоритм сортировки хотел бы сделать это ?


12
Один байт на камень бесконечности.
Джечлин

@djechlin Байт бесконечности - это то, почему вы должны идти за голову и особенно за челюсть.
Великая утка

10

Perl 6 , 30 байт

$!={[<=]($_)??$_!!.[^*/2].&$!}

Попробуйте онлайн!

Рекурсивная функция, которая удаляет вторую половину списка, пока список не отсортирован.

Объяснение:

$!={                         }    # Assign the function to $!
    [<=]($_)??                    # If the input is sorted
              $_                  # Return the input
                !!                # Else
                  .[^*/2]         # Take the first half of the list (rounding up)
                         .&$!     # And apply the function again


8

Java 10, 106 97 байт

L->{for(;;L=L.subList(0,L.size()/2)){int p=1<<31,f=1;for(int i:L)f=p>(p=i)?0:f;if(f>0)return L;}}

-9 байт благодаря @ OlivierGrégoire .

Попробуйте онлайн.

Оставляйте первую половину списка только на каждой итерации и удаляйте элементы , если размер списка нечетный.N+12

Объяснение:

L->{               // Method with Integer-list as both parameter and return-type
  for(;;           //  Loop indefinitely:
      L=L.subList(0,L.size()/2)){
                   //    After every iteration: only leave halve the numbers in the list
    int p=1<<31,   //   Previous integer, starting at -2147483648
        f=1;       //   Flag-integer, starting at 1
    for(int i:L)   //   Inner loop over the integer in the list:
      f=p>(p=i)?   //    If `a>b` in a pair of integers `a,b`:
         0         //     Set the flag to 0
        :          //    Else (`a<=b`):
         f;        //     Leave the flag the same
    if(f>0)        //   If the flag is still 1 after the loop:
      return L;}}  //    Return the list as result

n->{for(;n.reduce((1<<31)+0d,(a,b)->a==.5|b<a?.5:b)==.5;n=n.skip(n.count()/2));return n;} короче с использованием потоков, но я не смог выяснить, как избежать java.lang.IllegalStateException: stream has already been operated upon or closedошибки после возврата потока
Embodiment of Ignorance,

@EmbodimentofIgnorance это происходит потому, что reduceэто терминальная операция, которая закрывает поток. Вы никогда не сможете звонить reduceдважды в одном потоке. Вы можете создать новый поток, хотя.
Оливье Грегуар


@ OlivierGrégoire Этот порядок теперь выглядит так просто, что я его вижу .. Иногда мне нужно взглянуть с другой стороны, чтобы увидеть очевидные, которые другие изначально упускают, я полагаю. :) Спасибо!
Кевин Круйссен

1
Не беспокойтесь, это не было очевидно: я работал, чтобы добраться туда. Я проверил по крайней мере 10 версий, прежде чем нашел эту;)
Оливье Грегуар

8

Wolfram Language (Mathematica) , 30 байтов

#//.x_/;Sort@x!=x:>x[[;;;;2]]&

Попробуйте онлайн!

@ Doorknob сэкономил 12 байт


1
Вместо того, чтобы брать первую половину, вы можете сохранить несколько байтов, взяв любой другой элемент ( x[[;;;;2]]).
дверная ручка

@ Doorknob да, конечно ...
J42161217

думал, что можно было бы сэкономить с помощью OrderedQ, но не смог заставить его работать
Грег Мартин

@GregMartin Я использовал OrderedQв своем первом подходе (см.
Правки



6

05AB1E , 8 7 байт

[Ð{Q#ιн

-1 байт благодаря @Emigna .

Удаляет все нечетные 0-индексированные элементы на каждой итерации, поэтому удаляет элементов, если размер списка нечетный.N-12

Попробуйте онлайн или проверьте еще несколько тестовых случаев (или проверьте эти тестовые примеры с пошаговыми инструкциями для каждой итерации ).

7 байтов альтернатива @Grimy :

ΔÐ{Ê>äн

Удаляет последние элементов (или элементов, если размер списка нечетный) при каждой итерации.N2N-12

Попробуйте онлайн или проверьте еще несколько тестовых случаев (или проверьте эти тестовые примеры с пошаговыми инструкциями для каждой итерации ).

Объяснение:

[        # Start an infinite loop:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
  {Q     #  Sort a copy, and check if they are equal
    #    #   If it is: Stop the infinite loop (and output the result implicitly)
  ι      #  Uninterweave: halve the list into two parts; first containing all even-indexed
         #  items, second containing all odd-indexed items (0-indexed)
         #   i.e. [4,5,2,8,1] → [[4,2,1],[5,8]]
   н     #  And only leave the first part

Δ        # Loop until the result no longer changes:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
       #  Sort a copy, and check if they are NOT equal (1 if truthy; 0 if falsey)
    >    #  Increase this by 1 (so 1 if the list is sorted; 2 if it isn't sorted)
     ä   #  Split the list in that many parts
      н  #  And only leave the first part
         # (and output the result implicitly after it no longer changes)

3
Вы можете использовать ιвместо, если вы переключитесь на сохранение любой другой элемент стратегии.
Эминья

1
Вариант 7 с использованием стратегии «удалить последнюю половину»:ΔÐ{Ê>äн
Grimy

@Grimy Это очень хороший подход. Должен ли я добавить его в свой пост (зачисление вам, конечно) или вы хотите опубликовать его как отдельный ответ?
Кевин Круйссен

Не стесняйтесь добавлять это.
Grimy

6

TI-BASIC (TI-84), 47 42 45 44 байта

-1 байт благодаря @SolomonUcko!

Ans→L1:Ans→L2:SortA(L1:While max(L1≠Ans:iPart(.5dim(Ans→dim(L2:L2→L1:SortA(L1:End:Ans

Входной список находится в Ans.
Выход находится Ansи неявно распечатывается.

Объяснение:

Ans→L1                  ;store the input into two lists
Ans→L2
SortA(L1                ;sort the first list
                        ; two lists are needed because "SortA(" edits the list it sorts
While max(L1≠Ans        ;loop until both lists are strictly equal
iPart(.5dim(Ans→dim(L2  ;remove the latter half of the second list
                        ; removes (n+1)/2 elements if list has an odd length
L2→L1                   ;store the new list into the first list (updates "Ans")
SortA(L1                ;sort the first list
End
Ans                     ;implicitly output the list when the loop ends

Примечание: TI-BASIC - это токенизированный язык. Количество символов не равно количеству байтов.


Я думаю , вы можете заменить not(min(L1=Ansс , max(L1≠Ansчтобы сохранить байты.
Соломон Уко


3

Haskell , 57 55 байт (только благодаря ASCII)

f x|or$zipWith(>)x$tail x=f$take(div(length x)2)x|1>0=x

Попробуйте онлайн!


Оригинальный код:

f x|or$zipWith(>)x(tail x)=f(take(div(length x)2)x)|1>0=x

Попробуйте онлайн!


Ungolfed:

f xs | sorted xs = f (halve xs)
     | otherwise = xs

sorted xs = or (zipWith (>) xs (tail xs))

halve xs = take (length xs `div` 2) xs

1
Добро пожаловать в PPCG!
Rɪᴋᴇʀ




3

Октава , 49 байт

l=input('');while(~issorted(l))l=l(1:2:end);end;l

Попробуйте онлайн! Это было путешествие, где скучнее лучше. Обратите внимание на две гораздо более интересные записи ниже:

50 байтов

function l=q(l)if(~issorted(l))l=q(l(1:2:end));end

Попробуйте онлайн! Вместо неинтересного императивного решения мы можем сделать рекурсивное решение только для одного дополнительного байта.

53 байта

f(f=@(g)@(l){l,@()g(g)(l(1:2:end))}{2-issorted(l)}())

Попробуйте онлайн! Ага. Рекурсивная анонимная функция, благодаря блестящему ответу @ floorcat на мои . Анонимная функция, которая возвращает рекурсивную анонимную функцию, определяя себя в своем списке аргументов. Мне нравятся анонимные функции. Ммммм.


2

MATL , 11 байт

tv`1L)ttS-a

Попробуйте онлайн!

Это работает, удаляя каждый второй элемент.

объяснение

t      % Take a row vector as input (implicit). Duplicate
v      % Vertically concatenate the two copies of the row vector. When read with
       % linear indexing (down, then across), this effectively repeats each entry
`      % Do...while
  1L)  %   Keep only odd-indexed entries (1-based, linear indexing)
  t    %   Duplicate. This will leave a copy for the next iteration
  tS   %   Duplicate, sort
  -a   %   True if the two arrays differ in any entry
       % End (implicit). A new iteration starts if the top of the stack is true
       % Display (implicit). Prints the array that is left on the stack

2
Разбито для изначально отсортированного списка: [1, 2, 3, 4, 5] должно остаться [1, 2, 3, 4, 5]
Falco

@ Фалько Спасибо! Исправлено сейчас
Луис Мендо

2

Japt , 10 байт

eUñ)?U:ßUë

Попробуй

eUñ)?U:ßUë     :Implicit input of array U
e              :Compare equality with
 Uñ            :  U sorted
   )           :End compare
    ?U:        :If true then return U else
       ß       :Run the programme again with input
        Uë     :  Every second element of U



2

Шелуха , 6 5 байт

1 байт сохранен благодаря Zgarb

ΩΛ<Ċ2

Попробуйте онлайн!

объяснение

ΩΛ<Ċ2
Ω         Repeat until
 Λ<         all adjacent pairs are sorted (which means the list is sorted)
   Ċ2         drop every second element from the list

Это 11 байтов, а не 6. ›echo -n" ΩΛ <(← ½ "| wc --bytes 11
Майк Холлер


@MikeHoller Как и многие другие языки игры в гольф, Husk использует пользовательскую кодовую страницу, чтобы иметь доступ к большему количеству других символов: github.com/barbuz/Husk/wiki/Codepage
Лев

Спасибо, я кое-что узнал сегодня :)
Майк Холлер

1
Используйте Ċ2вместо того, (←½чтобы сохранить байт.
Згарб


2

Юлия 1,0 , 30 байт

-x=x>sort(x) ? -x[1:2:end] : x

Попробуйте онлайн!

Принимает каждый второй элемент массива, если не отсортирован.


используйте оператор ASCII, например, -для 20 байтов. также мы почти всегда не считаем символы: | так что было бы хорошо, если бы это было удалено из шапки
только ASCII

Поменял это. Спасибо за 2 байта!
niczky12

2

C ++ (gcc) , 103 байта

Я не могу комментировать, но я улучшил версию от movatica, уменьшив количество включений и используя авто.

-2 байта: floorcat
-2 байта: только ASCII

#include<regex>
auto f(auto l){while(!std::is_sorted(l.begin(),l.end()))l.resize(l.size()/2);return l;}

Попробуйте онлайн!


1
По какой причине вы не можете просто использовать l.size()/2?
Только для ASCII

Да, так не получается :)
peterzuger

1
что вы имеете в виду? возвращая список размера (n+1)/2или (n-1)/2оба действительны. хм ....
ASCII-только

Ой ой не видел, что спасибо
peterzuger

1

VDM-SL , 99 байт

f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

Никогда не отправлял в vdm раньше, поэтому не уверен в определенных правилах языка. Итак, я представил как определение функции, которая принимает seq of intи возвращаетseq of int

Полная программа для запуска может выглядеть так:

functions
f:seq of int +>seq of int
f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

1

Pyth, 10 байт

.W!SIHhc2Z

Попробуйте это онлайн здесь . Это удаляет вторую половину на каждой итерации, округляя вниз. Для того, чтобы изменить его , чтобы удалить первую половину, округление, изменить hк e.

.W!SIHhc2ZQ   Q=eval(input())
              Trailing Q inferred
  !SIH        Condition function - input variable is H
   SIH          Is H invariant under sorting?
  !             Logical not
      hc2Z    Iteration function - input variable is Z
       c2Z      Split Z into 2 halves, breaking ties to the left
      h         Take the first half
.W        Q   With initial value Q, execute iteration function while condition function is true

Взять любой другой элемент списка короче. Заменить hcна %. Это также позволяет вам удалить конечную лямбда-переменную Zи позволить Pyth неявно заполнить ее, чтобы сохранить всего 2 байта.
hakr14

1

C ++ (gcc) , 139 137 116 байт

-2 байта спасибо потолочной кошке, -21 байт спасибо PeterZuger

#include<regex>
auto f(std::vector<int>l){while(!std::is_sorted(l.begin(),l.end()))l.resize(-~l.size()/2);return l;}

Измените размер вектора до его первой половины, пока он не будет отсортирован.

Попробуйте онлайн!


1
Требуется, чтобы импорт был включен в число байтов, поэтому вы должны добавить includes
Embodiment of Ignorance

Спасибо, я добавлю их.
моватика

1

K (ок) , 22 20 байт

Решение:

{(*2 0N#x;x)x~x@<x}/

Попробуйте онлайн!

Перебирайте ввод до тех пор, пока он не отсортирован ... если он не отсортирован, возьмите первые n / 2 элементов.

{(*2 0N#x;x)x~x@<x}/ / the solution
{                 }/ / lambda that iterates
                <x   / indices that sort x ascending (<)
              x@     / apply (@) these indices back to x
            x~       / matches (~) x? returns 0 or 1
 (       ; )         / 2-item list which we index into
          x          / original input (ie if list was sorted)
       #x            / reshape (#) x
   2 0N              / as 2 rows
  *                  / take the first one      

Редактирование:

  • -2 байта благодаря ngn

1
(.5*#x)#x->*2 0N#x
нгн

Я подумал, 2 0Nно предположил, что это будет дольше (без тестирования), спасибо!
Стритстер


0

Сетчатка , 38 байт

\d+
*
/(_+),(?!\1)/+`,_+(,?)
$1
_+
$.&

Попробуйте онлайн! Принимает числа через запятую. Объяснение:

\d+
*

Преобразовать в одинарный.

/(_+),(?!\1)/+`

Повторите, пока список не отсортирован ...

,_+(,?)
$1

... удалить каждый четный элемент.

_+
$.&

Преобразовать в десятичную.


0

C (gcc) , 66 байт

Отбирает вторую половину списка каждую итерацию ( n/2+1элементы, если длина нечетна).

Попробуйте онлайн!

Принимает ввод как указатель на начало массива, за intкоторым следует его длина. Выводит путем возврата новой длины массива (сортирует по месту).

t(a,n,i)int*a;{l:for(i=0;i<n-1;)if(a[i]>a[++i]){n/=2;goto l;}a=n;}

Безголовая версия:

t(a, n, i) int *a; { // take input as a pointer to an array of int, followed by its length; declare a loop variable i
  l: // jump label, will be goto'ed after each snap
  for(i = 0; i < n - 1; ) { // go through the whole array …
    if(a[i] > a[++i]) { // … if two elements are in the wrong order …
      n /= 2; // … snap off the second half …
      goto l; // … and start over
    }
  }
  a = n; // implicitly return the new length
}

Предлагаю ~i+nвместоi<n-1
floorcat
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.