병합 정렬 시각화


30

병합 정렬 은 주어진 목록을 반으로 나누고 작은 목록을 재귀 적으로 정렬 한 다음 다시 정렬 된 목록으로 병합하여 작동하는 정렬 알고리즘입니다. 재귀의 기본 사례는 싱글 톤 목록에 도달하는데,이 목록은 더 이상 분할 할 수 없지만 정의에 따라 이미 정렬되어 있습니다.

목록에서 알고리즘의 실행은 [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]

5
@dylnan 다른 정렬 알고리즘이나 내장 정렬 함수를 사용하여 정렬을 수행 할 수 있습니다.
flawr

5
일부 골프 아이디어 : 전반부의 각 하위 목록을 정렬하고 순서를 반대로하여 결과의 ​​하단 절반을 생성 할 수 있습니다.
JungHwan Min

2
@Arnauld [[1,2],[3],[4,5],[6]]병합 정렬이 재귀 적으로 작동하므로 스테이지는 실제로 올바른 솔루션입니다. 우리가 시작하는 경우 즉 [1,2,3,4,5,6]하고으로 분할 [1,2,3]하고 [4,5,6]그들이 최종 단계에서 병합 될 때까지 그 목록은 독립적으로 처리된다.
Laikoni

2
@ l4m2 정답은 다음과 같습니다. 1. 정수> 9도 지원해야하므로 구분 기호가 필요합니다. 2. 이것은 위의 의견에서 제공된 것과 같은 이유로 유효하지 않습니다. 우리가로 분할하는 경우 [3][2,1], 우리가 병합 할 수 있도록 다음 사람들은, 다른 지점에있는 [3][2][2,1]분할에있다 [2][1].
Laikoni

1
사실 그 이후의 문장은 내 질문에 정확하게 답합니다. 실종해서 죄송합니다. : P
Zgarb

답변:


8

하스켈 , 137 128 127 125 121 109 106 바이트

nimi 덕분에 (-2) + (-4) = (-6) 바이트 ! 목록에서 모든 단계를 수집하도록 다시 변경하면 (니미로 인해) 12 바이트가 더 절약됩니다.

Laikoni에 의한 또 다른 3 바이트 , 패턴 가드 바인딩 및 가드를 인코딩하기 위해 목록 이해력을 영리하게 사용합니다.

import Data.List
g x|y<-x>>=h=x:[z|x/=y,z<-g y++[sort<$>x]]
h[a]=[[a]]
h x=foldr(\x[b,a]->[x:a,b])[[],[]]x

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

목록을 홀수 및 짝수 요소로 나누는 것은 두 개의 순차적 인 절반보다 짧은 코드입니다. 왜냐하면 우리는를 측정해야하기 때문 length입니다.

목록을 "인쇄"한 다음 실제로 분할이 수행 된 경우 분할 목록 ( x >>= h)으로 되풀이 하고 정렬 된 목록을 "인쇄"하여 작동합니다. 하나의 입력 목록으로 시작; 비어 있지 않은 입력을 가정합니다. 실제 인쇄하는 대신 목록으로 수집 하면됩니다.

g[[6,5..1]]인쇄 된 목록 은 다음과 같습니다.

[[6,5,4,3,2,1]]
[[6,4,2],[5,3,1]]
[[6,2],[4],[5,1],[3]]
[[6],[2],[4],[5],[1],[3]]
[[2,6],[4],[1,5],[3]]
[[2,4,6],[1,3,5]]
[[1,2,3,4,5,6]]

1
... p=print그리고 세 번 p. 온라인으로 사용해보십시오!
nimi

@nimi 다시 한번 감사드립니다. 지금 정말 골프 보인다 . :)
Will Ness

함수 내에서 인쇄하는 대신 g목록의 모든 단계를 수집하여 리턴 할 수 있습니다. 온라인으로 사용해보십시오!
nimi

3
나는 우리가 "시각화"의 적절한 정의를 가지고 있다고 생각하지 않습니다. 보다 일반적인 과제는 목록을 "출력"해야하며 기본값 에 따라 함수반환 값을 통해 수행 할 수 있습니다 . 다른 답변, 예를 들어 1 , 2 도이 방법으로 수행합니다. -나는 내 제안이 그렇게 많이 다르다고 생각하지 않으며, 중간리스트를 인쇄하는 대신 수집합니다. 편하게 편집하십시오.
nimi

3
g x|y<-x>>=h=x:[z|x/=y,z<-g y++[sort<$>x]]더 많은 바이트를 절약합니다.
Laikoni

7

볼프람 언어 (티카) , 146 (127) 111 102 바이트

Join[u=Most[#/.a:{_,b=__Integer}:>TakeDrop[a,;;;;2]&~FixedPointList~#],Reverse@Most@u/.a:{b}:>Sort@a]&

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

List단계가 포함 된를 반환 합니다.

설명

#/.a:{_,b=__Integer}:>TakeDrop[a,;;;;2]&

입력에서 List2 개 이상의 정수를 포함하는 모든 s를 반으로 나눕니다 . 첫 번째 하위 목록에는 홀수 색인 요소 (1 색인)가 있고 두 번째 하위 목록에는 짝수 색인 요소가 있습니다.

u=Most[... &~FixedPointList~#]

아무것도 변경되지 않을 때까지 반복하십시오 (즉, 모든 하위 목록의 길이는 1입니다). 모든 중간 결과를 유지하십시오. 이것을 ( List모든 단계 중)에 저장 하십시오 u.

Reverse@Most@u

마지막 요소를 u버리고 뒤집습니다.

... /.a:{b}:>Sort@a

위의 결과에서 정수 목록의 모든 항목을 정렬하십시오.


6

면도 , 228 206 168 157 140 121 104 바이트

n끝에서 n-th 요소가 처음부터 -th 요소 의 정렬 된 버전 이라는 사실을 사용하여 끝에서 안쪽으로 단계 목록을 작성합니다 .

에서 아이디어 JungHwan 최소의 코멘트

import StdEnv
@u#(a,b)=splitAt(length u/2)u
=if(a>[])[[u]:[x++y\\y<- @b&x<- @a++ @a++ @a]][]++[[sort u]]

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


4

, 145 133 123 122 바이트

≔⟦⪪S ⟧θW⊖L§θ⁰«⟦⪫Eθ⪫κ ¦|⟧≔EE⊗Lθ§θ÷λ²✂κ﹪λ²Lκ²θ»⟦⪫ΦEθ⪫ι ι|⟧W⊖Lθ«≔⮌θη≔⟦⟧θWη«≔⊟ηε≔⟦⟧ζF⊟η«≔εδ≔⟦⟧εFδ⊞⎇‹IμIλζεμ⊞ζλ»⊞θ⁺ζε»⟦⪫Eθ⪫κ ¦|

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 여전히 숯불 문제를 해결해야합니다 ... 편집 : Map가난한 사람의 배열 이해력 으로 double 을 사용하여 5 바이트를 절약했습니다 . Pop배열을 두 번 반복 하여 4 바이트를 절약했습니다 . 대신 연결을 사용하여 3 바이트를 절약했습니다 Push. while숯불 버그를 피하는 골퍼 조건으로 10 바이트를 절약했습니다 . Charcoal에 실제로 필터 연산자가 있음을 발견하여 1 바이트를 절약했습니다. 설명:

≔⟦⪪S ⟧θ

공백으로 입력을 분할 한 다음 결과를 외부 배열로 래핑하여에 저장합니다 q.

W⊖L§θ⁰«

의 첫 번째 요소에 q둘 이상의 요소가있는 동안 반복하십시오 . (첫 번째 요소 q는 목록이 두 가지로 나뉘어져 있기 때문에 항상 가장 많은 요소를 갖습니다.)

⟦⪫Eθ⪫κ ¦|⟧

q공백과 수직선 으로 결합 된 요소를 인쇄합니다 . (배열은 결과를 자체 행에 인쇄합니다. 동일한 바이트 수로이를 달성하는 다른 방법이 있습니다.)

≔EE⊗Lθ§θ÷λ²✂κ﹪λ²Lκ²θ»

의 각 요소를 복제하여 목록을 생성 한 q다음 해당 목록 위에 매핑하고 각 목록의 절반을 대체 요소 접근 방식을 사용하여 결과를에 저장합니다 q.

⟦⪫ΦEθ⪫ι ι|⟧

q공백과 수직선 으로 결합 된 요소를 인쇄합니다 . 실제로이 시점에서의 요소는 q비어 있거나 단일 요소 목록이므로 결합하면 빈 문자열 또는 요소로 변환됩니다. 빈 문자열은 불필요한 후행 줄을 추가하여 필터링됩니다. 납작한 연산자는 그래도 골퍼 였을 것 ⟦⪫Σθ|⟧입니다.

W⊖Lθ«

q요소가 둘 이상있는 동안 반복하십시오 . (다음 코드에는 짝수 개의 요소가 필요합니다.)

≔⮌θη≔⟦⟧θ

로 복사 하되 반전 q시키십시오 h(아래 참조) q. 빈 목록으로 재설정 하십시오.

Wη«

h비어 있을 때까지 반복하십시오 .

≔⊟ηε

의 다음 요소 추출 h에를 e. ( Pop끝에서 추출하기 때문에 반전해야합니다 q.)

≔⟦⟧ζ

z빈 목록으로 초기화 하십시오.

F⊟η«

의 다음 요소의 요소를 반복합니다 h.

≔εδ≔⟦⟧ε

복사 ed리셋e 빈 목록.

Fδ

의 요소를 반복 d .

⊞⎇‹IμIλζεμ

그것들을 다음 요소의 현재 요소보다 작은 지에 따라 z또는eh .

⊞ζλ»

다음 요소의 현재 요소 hz .

⊞θ⁺ζε»

z남아있는 요소와 연결하여을 ( 를) e누릅니다 q. 이것으로 두 요소의 병합을 완료합니다h .

⟦⪫Eθ⪫κ ¦|

q공백과 수직선 으로 결합 된 요소를 인쇄합니다 .


잠깐만 또 다른 버그가 있습니까? : /
ASCII 전용

@ASCII 전용 아니요, 이것은 while (...Map(...)...)이미 말한 버그 였습니다 .
Neil


2

자바 스크립트 (ES6), 145 바이트

f=a=>a.join`|`+(a[0][1]?`
${f([].concat(...a.map(b=>b[1]?[b.slice(0,c=-b.length/2),b.slice(c)]:[b])))}
`+a.map(b=>b.sort((x,y)=>x-y)).join`|`:``)

배열 내에서 배열로 입력을 f([[6,5,4,3,2,1]])받습니다 ( 예 :) . 출력의 첫 번째와 마지막 줄을 생성 한 다음 모든 하위 배열의 길이가 1이 될 때까지 다시 분할하고 호출하여 작동합니다. 다음은 작동 방식에 대한 기본 데모입니다.

f([[6,5,4,3,2,1]]):
  6,5,4,3,2,1
  f([[6,5,4],[3,2,1]]):
    6,5,4|3,2,1
    f([[6,5],[4],[3,2],[1]]):
      6,5|4|3,2|1
      f([[6],[5],[4],[3],[2],[1]]):
        6|5|4|3|2|1
      end f
      5,6|4|2,3|1
    end f
    4,5,6|1,2,3
  end f
  1,2,3,4,5,6
end f

2
그렇다면 145 바이트에 3 개의 답이 묶여있는 지점이 있습니까?
Neil

2

껍질 , 14 바이트

S+ȯ†O↔hUmfL¡ṁ½

단일 배열을 포함하는 배열을 가져옵니다. 온라인으로 사용해보십시오!

설명

S+ȯ†O↔hUmfL¡ṁ½  Implicit input, say A = [[4,17,32,1]].
           ¡    Iterate this function on A:
            ṁ½   Split each array in two, concatenate results: [[4,17],[32,1]]
                Result is [[[4,17,32,1]],
                           [[4,17],[32,1]],
                           [[4],[17],[32],[1]],
                           [[4],[],[17],[],[32],[],[1],[]],
                           ...
        mfL     Map filter by length, removing empty arrays.
                Result is [[[4,17,32,1]],
                           [[4,17],[32,1]],
                           [[4],[17],[32],[1]],
                           [[4],[17],[32],[1]],
                           ...
       U        Longest prefix of unique elements:
                       P = [[[4,17,32,1]],[[4,17],[32,1]],[[4],[17],[32],[1]]]
      h         Remove last element: [[[4,17,32,1]],[[4,17],[32,1]]]
     ↔          Reverse: [[[4,17],[32,1]],[[4,17,32,1]]]
   †O           Sort each inner array: [[[4,17],[1,32]],[[1,4,17,32]]]
S+ȯ             Concatenate to P:
                           [[[4,17,32,1]],
                            [[4,17],[32,1]],
                            [[4],[17],[32],[1]],
                            [[4,17],[1,32]],
                            [[1,4,17,32]]]
                Implicitly print.

내장 ½은 배열 을 가져 와서 중간에 나눕니다. 길이가 홀수이면 첫 번째 부분이 하나의 요소만큼 길어집니다. 단일 배열이 [a]발생 [[a],[]]하고 빈 배열이 []제공 [[],[]]되므로 적용하기 전에 빈 배열을 제거해야합니다 U.


1

Stax , 116 (÷ 3>) 38 29 바이트 CP437

@recursive의 주석 당 -9 바이트 이제 입력은 요소 만 정렬 할 숫자의 배열 인 싱글 톤으로 제공됩니다.

ƒ3s}óºE/ßB╢↕êb∩áαπüµrL╞¶è,te+

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

35 바이트의 압축 해제 버전 :

{c{Jm'|*Pc{2Mm:f{fc{Dm$wW{{eoJm'|*P

설명

코드는 두 부분으로 나눌 수 있습니다. 첫 번째 부분은 분할을 시각화하고 두 번째 부분은 병합을 시각화합니다.

분할 시각화 코드 :

{                      w    Do the following while the block generates a true value
 c                          Copy current nested array for printing
  {Jm                       Use spaces to join elements in each part
     '|*                    And join different parts with vertical bar 
        P                   Pop and print

         c                  Copy current nested array for splitting
          {2Mm              Separate each element of the array to two smaller parts with almost the same size
                                That is, if the number of elements is even, partition it evenly.
                                Otherwise, the first part will have one more element than the second.
              :f            Flatten the array once
                {f          Remove elements that are empty arrays

                  c         Copy the result for checking 
                   {Dm$     Is the array solely composed of singletons?
                            If yes, ends the loop.

병합 시각화 코드 :

W              Execute the rest of the program until the stack is empty
 {{eoJm        For each part, sort by numeric value, then join with space
       '|*     Join the parts with vertical bar
          P    Pop and print the result

실제로는 중첩 목록 구조를 빌드하는 이전 버전입니다.

{{cc0+=!{x!}Mm',*:}}Xd;%v:2^^{;s~{c^;<~sc%v,*{2M{s^y!svsm}M}YZ!x!Q,dmU@e;%v:2^{;%v:2^-N~0{c;={scc0+=Cc%v!C:f{o}{scc0+=C{s^y!svsm}?}Y!cx!P,dcm

cc0+= 이 코드에서 스택의 최상위가 스칼라인지 또는 배열인지 확인하기 위해 세 번 사용됩니다.

{{cc0+=!{x!}Mm',*:}}X중첩 된 숫자 배열을 올바르게 출력하기 위해 재귀 적으로 호출하는 블록을 작성합니다. Stax의 기본 출력은 인쇄 전에 중첩 배열을 벡터화합니다.

{                  }X    Store the code block in X
 {           m           Map each element in the list with block
  cc                     Make two copies of the element
    0+                   + 0. If the element is a scalar, nothing will change
                              If the element is an array, the element 0 will be appended
      =!{  }M            If the element has changed after the `0+` operation
                             Which means it is an array
         x!              Recursively execute the whole code block on the element

              ',*        Join the mapped elements with comma
                 :}      Bracerizes the final result

분할 및 병합을 각각 수행하는 두 개의 다른 블록이 있습니다. 그들은 너무 장황하고 설명 할 필요가 없습니다 (이 게시물의 이전 버전에는 약간 더 많은 정보가 있지만 너무 많이 기대하지는 않습니다).


아주 좋은 개선. 아직 완전히 이해하지 못했지만 cH!대신 사용할 수 있다고 생각 cH%!합니다.
재귀

{Nd}M대체 할 T수도 있습니다.
재귀

좀 더 적응했습니다. staxlang.xyz/… Husk 답변은 배열의 배열로 입력을 취하므로 합법적이라고 생각합니다.
재귀

2 ASCII 문자보다 짧은 솔루션을 찾았지만 배열 전치의 버그를 발견했습니다. 특히 배열 행을 변경합니다. 1.0.4 백 로그에 추가하겠습니다
재귀 적

승인. 업데이트를 기대합니다.
웨이 준 저우
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.