Thanos 정렬 알고리즘 구현


93

정렬 알고리즘은 다음과 같습니다.

목록이 정렬되지 않은 동안 모든 항목의 절반을 스냅하십시오 (목록에서 제거). 목록이 정렬되거나 하나의 항목 만 남을 때까지 계속하십시오 (기본적으로 정렬 됨). 이 정렬 알고리즘은 구현에 따라 다른 결과를 제공 할 수 있습니다.

품목 제거 절차는 결정할 구현에 달려 있지만, 품목 제거 절차를 한 번 통과 한 후 목록의 길이는 절반이어야합니다. 알고리즘은 목록의 반이 길거나 언급되지 않은 한 번에 하나씩, 전반 또는 목록, 목록의 마지막 절반, 모든 홀수 항목, 모든 짝수 항목을 제거하기로 결정할 수 있습니다.

입력 목록은 2 ^ n 항목의 완벽하게 나눌 수있는 목록뿐만 아니라 임의의 양의 항목을 포함 할 수 있습니다 (이유로, 최대 1000 개의 항목을 말합시다). 런타임 중에 목록이 홀수이거나 하드 코딩되거나 임의로 결정된 경우 (n + 1) / 2 또는 (n-1) / 2 항목을 제거해야합니다. 우주가 이상한 양의 생물을 포함하고 있다면 Thanos는 어떻게 할 것인가?

이전 항목보다 작은 항목이 없으면 목록이 정렬됩니다. 입력에서 중복이 발생할 수 있으며 출력에서 ​​발생할 수 있습니다.

프로그램은 정수 배열 (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

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
무한대 스톤 당 1 바이트.
djechlin

@djechlin 무한 바이트 는 머리와 특히 턱으로 가야하는 이유입니다.
그레이트 덕

10

펄 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

자바 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;}}

@ OlivierGrégoire 덕분에 -9 바이트 .

온라인으로 사용해보십시오.

반복 할 때마다 목록의 첫 절반 만 남겨두고 n + 1을 제거합니다.n+12목록 크기가 홀수 인 경우 2 개 항목

설명:

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을 반환 한 후 오류 를 피하는 방법을 알 수 없었습니다.
무지의 구현

이것은 무의미한 일 reduce입니다. 이것은 스트림을 닫는 터미널 작업 이기 때문에 발생 합니다. reduce같은 스트림에서 두 번 전화를 걸 수 없습니다 . 그래도 새 스트림을 만들 수 있습니다.
Olivier Grégoire


@ OlivierGrégoire 그 순서는 지금보기에는 너무 단순 해 보입니다. 때로는 다른 사람들이 처음에 놓친 것 같은 명백한 것을보기 위해 다른 각도에서 보는 경우가 있습니다. :) 감사!
케빈 크루이 센

1
걱정하지 마십시오. 분명하지 않았습니다. 나는 그곳에 도착했습니다. 내가 발견하기 전에 적어도 10 버전을 테스트 한 해당)
올리비에 그레 구 아르

8

Wolfram Language (Mathematica) , 30 바이트

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

온라인으로 사용해보십시오!

@Doorknob이 12 바이트를 절약했습니다


1
전반부를 취하는 대신 다른 모든 요소 ( x[[;;;;2]])를 가져 와서 바이트를 절약 할 수 있습니다.
손잡이

물론
@Doorknob

를 사용하여 비용을 절약 할 수 있다고 생각 OrderedQ했지만 작동시킬 수 없음
Greg Martin

@GregMartin 나는 OrderedQ첫 번째 접근법에 사용 했다 (편집 참조)
J42161217



6

05AB1E , 8 7 바이트

[Ð{Q#ιн

@Emigna 덕분에 -1 바이트 .

반복 할 때마다 홀수 0 인덱스 항목을 모두 제거하므로 제거합니다.n12

온라인으로 시도 하거나 더 많은 테스트 사례를 확인하십시오 (또는 각 반복마다 단계별로 테스트 사례를 확인하십시오 ).

@Grimy의 7 바이트 대안 :

ΔÐ{Ê>äн

마지막 제거합니다n2n12

온라인으로 시도 하거나 더 많은 테스트 사례를 확인하십시오 (또는 각 반복마다 단계별로 테스트 사례를 확인하십시오 ).

설명:

[        # 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
다른 모든 요소 전략 유지로 전환 하는 ι대신 대신 사용할 수 있습니다 .
Emigna

1
"마지막 절반 제거"전략을 사용한 대안 7 :ΔÐ{Ê>äн
Grimy

@ 그림은 꽤 좋은 접근 방법입니다. 게시물에 글을 추가 하시겠습니까 (물론 당신에게 신용), 또는 별도의 답변으로 게시 하시겠습니까?
케빈 크루이 센

자유롭게 추가하십시오.
그리미

6

TI-BASIC (TI-84), 47 42 45 44 바이트

@SolomonUcko 덕분에 -1 바이트!

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바이트를 저장합니다.
솔로몬 Ucko


3

하스켈 , 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)}())

온라인으로 사용해보십시오! 네. 내 질문 에 대한 @ceilingcat의 훌륭한 답변 덕분에 재귀 익명 기능 . 인수 목록에 자신을 정의하여 재귀 익명 함수를 반환하는 익명 함수입니다. 나는 익명의 기능을 좋아한다. 음


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

@ 팔코 감사합니다! 이제 수정
Luis Mendo

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 바이트

Zgarb 덕분에 1 바이트 절약

ΩΛ<Ċ2

온라인으로 사용해보십시오!

설명

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

이것은 6이 아닌 11 바이트입니다.›echo -n "ΩΛ <(← ½"| wc --bytes 11
Mike Holler


@MikeHoller 다른 많은 골프 언어와 마찬가지로 Husk는 다른 문자에 액세스하기 위해 사용자 지정 코드 페이지를 사용합니다. github.com/barbuz/Husk/wiki/Codepage
Leo

감사합니다, 오늘 무언가를 배웠습니다 :)
Mike Holler

1
바이트를 저장하는 Ċ2대신 사용하십시오 (←½.
Zgarb



2

C ++ (gcc) , 103 바이트

나는 말할 수는 없지만 포함을 줄이고 자동을 사용하여 movatica의 버전을 개선했습니다.

-2 바이트 : ceilingcat
-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둘 다 유효합니다. hmm ....
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와 함께 %. 또한 후행 람다 변수를 삭제하고 ZPyth가 암시 적으로 채우도록하여 총 2 바이트를 절약 할 수 있습니다.
hakr14

1

C ++ (GCC) , 139 (137) 116 바이트

PeterZuger에 -2 바이트 고맙습니다.

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

정렬 될 때까지 벡터를 첫 번째 절반으로 크기를 조정하십시오.

온라인으로 사용해보십시오!


1
수입은 바이트 수에 포함 rquired, 그래서 당신은 추가 할 필요가 있습니다 include
예 무지의

감사합니다. 추가하겠습니다.
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      

편집 :

  • ngn 덕분에 -2 바이트

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

나는 시험해 2 0N보았지만 시험하지 않고 더 길 것이라고 가정했습니다. 감사합니다!
streetster


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
ceilingcat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.