Реалізуйте алгоритм сортування Таноса


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]. Мій власний алгоритм не вдався до цього вводу
Conor O'Brien

Відповіді:





12

Брахілог (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

Це було б досить коротше , якби ми могли змінити порядок елементів, але whyever б алгоритм сортування хоче зробити що ?


12
Один байт на нескінченний камінь.
djechlin

@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 .

Спробуйте в Інтернеті.

н+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помилки після повернення потоку
Втілення Незнання

@EmbodimentofIgnorance це відбувається через те reduce, що це термінальна операція, яка закриває потік. Ви ніколи не зможете reduceдвічі дзвонити в один і той же потік. Однак ви можете створити новий потік.
Олів'є Грегоар


@ OlivierGrégoire Цей наказ виглядає настільки простим зараз, коли я його бачу .. Іноді потрібно поглянути з іншого кута, щоб побачити очевидні інші, які спочатку пропускають, я думаю. :) Дякую!
Кевін Кройсейсен

1
Не хвилюйтесь, це не було очевидно: я працював, щоб потрапити туди. Я перевірив щонайменше 10 версій, перш ніж знайти цю;)
Олів'є Грегоар

8

Мова Вольфрама (Mathematica) , 30 байт

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

Спробуйте в Інтернеті!

@Doorknob зберегло 12 байт


1
Замість того, щоб взяти перший тайм, ви можете зберегти кілька байт, взявши кожен інший елемент ( x[[;;;;2]]).
Дверна ручка

@Doorknob так, звичайно ...
J42161217

подумав, що можна скористатися певною економією OrderedQ, але не зміг би зробити це
Грег Мартін

@GregMartin я використовував OrderedQу своєму першому підході (див. Правки)
J42161217



6

05AB1E , 8 7 байт

[Ð{Q#ιн

-1 байт завдяки @Emigna .

н-12

Спробуйте в Інтернеті або перевірте ще кілька тестових випадків (або перевіряйте ці тестові випадки покроково для кожної ітерації ).

Альтернатива 7 байт від @Grimy :

ΔÐ{Ê>äн

н2н-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 Це теж приємний підхід. Чи повинен я додати його до своєї публікації (зважаючи на вас, звичайно), чи ви хочете опублікувати її як окрему відповідь?
Kevin Cruijssen

Сміливо додайте його.
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

Спробуйте в Інтернеті!


Безголовки:

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)}())

Спробуйте в Інтернеті! Так. Рекурсивна анонімна функція, завдяки блискучій відповіді @ roofcat на запитання моїх . Анонімна функція, яка повертає рекурсивну анонімну функцію, визначаючи себе у своєму списку аргументів. Мені подобаються анонімні функції. Ммммм.


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

@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 --байт 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, зменшивши включення та використовуючи auto.

-2 байти: слюсарна плата
-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 раніше, тому не визначений щодо мовних правил. Тому я подав як визначення функції, яке приймає a seq of intі повертає aseq 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
Втілення невігластва

Дякую, я додам їх.
movatica

1

K (oK) , 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
ngn

Я вважав, що робити, 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
roofcat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.