Birleştirme Sıralamasını Görselleştir


30

Birleştirme sıralaması , belirli bir listeyi ikiye bölerek, her iki küçük listeyi tekrar tekrar sıralayarak ve bunları bir sıralanan listeyle birleştirerek çalışan bir sıralama algoritmasıdır. Özyinelemenin temel durumu, daha fazla bölünemeyen, ancak önceden tanımlanmış olan tek bir listeye varmaktır.

Algoritmanın listede yürütülmesi [1,7,6,3,3,2,5]aşağıdaki şekilde görselleştirilebilir:

       [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]

Görev

Tamsayıların listesini girdi olarak kabul eden ve bu listenin farklı bölümlerini görselleştiren bir birleştirme sıralama algoritmasına göre sıralanan bir program veya işlev yazın. Bu , yukarıdaki gibi bir grafik çıkarmanız gerekmediği anlamına gelir , ancak yalnızca listeler iyidir:

[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]

Ayrıca, makul herhangi bir liste gösterimi iyi değildir, bu nedenle aşağıdakiler de geçerli bir çıktı olacaktır:

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

Son olarak, bir listeyi iki küçük listeye ayırmanın yolu, her iki sonuç listesinin uzunluğu en fazla bir farklılık gösterdiği sürece size bağlıdır. Bunun anlamı, [3,2,4,3,7]içine bölünmek yerine [3,2,4]ve [3,7]aynı zamanda tek ve tek indeksleri ( [3,4,7]ve [2,3]) de alarak elementleri ayırmak veya hatta her zaman bölmeyi rastgele yapmak anlamına gelebilir .

Bu , yani bayt cinsinden ölçülen herhangi bir dilde en kısa kod kazanır.

Test durumları

Yukarıda belirtildiği gibi, gerçek format ve listeleri ikiye bölme şekli size bağlıdır.

[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 Sınıflandırmayı yapmak için başka bir sıralama algoritması veya yerleşik bir sıralama işlevi kullanabilirsiniz ...
kusur 14:17 '

5
Bazı golf fikirleri: sonucun alt yarısı, her alt listeyi ilk yarıda sıralayarak ve sırayı tersine çevirerek oluşturulabilir.
JungHwan Min

2
@Arnauld Birleştirme işlemi tekrarlı bir şekilde çalıştığı için [[1,2],[3],[4,5],[6]]sahne aslında doğru çözümdür. Biz başlarsak budur [1,2,3,4,5,6]ve bölmek [1,2,3]ve [4,5,6]onlar son adımda birleştirilir kadar sonra bu listelere bağımsız işlenir.
Laikoni

2
@ l4m2 Tamam, bir cevap için son deneyin: 1. sınırlayıcılara ihtiyacınız var çünkü> 9 tamsayılar da desteklenmeli. 2. Bu, yukarıdaki yorumumda verilen sebeplerle aynı değildir. Biz bölünmüş ise [3]ve [2,1]biz birleştiremezsiniz böylece daha sonra bu, farklı dallarda olan [3]ve [2]sonra [2,1]bölünmüş içine [2]ve [1].
Laikoni

1
Aslında bundan sonraki cümle sorumu tam olarak cevaplıyor. Bunu kaçırdığım için üzgünüm. : P
Zgarb

Yanıtlar:


8

Haskell , 137 128 127 125 121 109 106 bayt

(-2) + (- 4) = (- 6) nimi sayesinde bayt ! Listedeki tüm adımları (nimi nedeniyle) toplayacak şekilde değiştirmek, 12 bayttan daha fazla tasarruf sağlar.

Laikoni'ye bağlı 3 bayt , desen koruyucu ciltleme ve korumayı kodlamak için akıllıca bir liste kullanımı.

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

Çevrimiçi deneyin!

Listeleri tek ve çift konumlu öğelere bölmek iki sıralı yarıya göre daha kısa bir koddur, çünkü o zaman ölçmek zorunda kalıyoruz length.

Tarafından İşleri (bölünmüş listeleri ile recursing sonra, listeleri "baskı" x >>= h) ise aslında hiçbir bölme yapılır ve sıralı listeleri "baskı" vardı; bir giriş listesinden başlayarak; boş olmayan girdi varsayılarak. Ve gerçek baskı yerine, sadece bir listede onları toplamak .

g[[6,5..1]]Satır satır yazdırılan liste şöyledir:

[[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=printve üç kere p. Çevrimiçi deneyin!
nimi

@ nimi harika, tekrar ve çok teşekkürler! şimdi gerçekten golf gibi görünüyor . :)
Ness

İşlev içinde yazdırmak yerine, glistedeki tüm adımları toplayıp geri verebilirsiniz. Çevrimiçi deneyin!
nimi

3
“Görselleştirmenin” doğru bir tanımına sahip olduğumuzu sanmıyorum. Daha genel olarak, zorluklar listelerin "çıktısını" ister ve varsayılanlara göre bu , bir fonksiyonun dönüş değeri ile yapılabilir . Diğer cevaplar, örneğin 1 , 2 de bunu böyle yapar. - Önerimimin bu kadar farklı olduğunu sanmıyorum, sadece ara listelerini yazdırmak yerine topluyor. Düzenlemek için çekinmeyin.
nimi

3
g x|y<-x>>=h=x:[z|x/=y,z<-g y++[sort<$>x]]biraz daha bayt kaydeder.
Laikoni

7

Wolfram Dili (Mathematica) , 146 127 111 102 bayt

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

Çevrimiçi deneyin!

ListAdımları içeren bir döndürür .

açıklama

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

Bir girişte, List2 veya daha fazla tam sayı içeren tüm öğeleri ikiye bölün . İlk alt liste tek indeksli elemanlara (1 indeksli) ve ikincisi çift indeksli elemanlara sahiptir.

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

Hiçbir şey değişinceye kadar bunu tekrarlayın (yani tüm alt listeler uzunluk-1'dir). Tüm ara sonuçları saklayın. Bunu ( Listtüm adımların arasında) içinde saklayın u.

Reverse@Most@u

Son elemanını bırakın uve ters çevirin.

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

Yukarıdaki sonuçtan, bir tamsayı listesinin tüm oluşumlarını sıralayın.


6

Temiz , 228 206 168 157 140 121 104 bayt

Sonundan n-th elemanının baştan itibaren -th elemanının sıralanmış versiyonu olduğu gerçeğini kullanarak, uçlardan içe doğru aşamaların listesini oluşturur n.

Dan Fikir Junghwan Min'in comment

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

Çevrimiçi deneyin!


4

Kömür , 145 133 123 122 bayt

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

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı bir versiyonudur. Hala Kömür böcekleri üzerinde çalışmak zorunda ... Düzenleme: MapZavallı bir adamın dizi kavrayışını bir çift kullanarak 5 bayt kurtardı. PopBir dizi üzerinde yineleme yapmak için 4 bayt kullanılarak kaydedildi . Yerine birleştirme kullanarak 3 bayt kaydedildi Push. whileAyrıca bir Kömür hata önler bir golfier koşulu ile gelip 10 bayt kurtardı . Kömürün gerçekten bir filtre operatörüne sahip olduğunu keşfederek 1 bayt kurtarıldı. Açıklama:

≔⟦⪪S ⟧θ

Girişi boşluklara bölün ve sonucu bir dış diziye sarın ve onu kaydedin q.

W⊖L§θ⁰«

İlk elemanın qbirden fazla eleman varken tekrarlayın . ( qListelerin ikiye ayrılmasından dolayı, ilk öğenin her zaman en çok öğesi vardır.)

⟦⪫Eθ⪫κ ¦|⟧

qBoşluklarla ve dikey çizgilerle birleştirilen öğelerini yazdırın . (Dizi sonucun kendi satırında yazdırılmasına neden olur. Aynı bayt sayısı için bunu başarmanın başka yolları da vardır.)

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

Her bir öğeyi çoğaltarak bir liste oluşturun q, ardından o listenin üzerinde eşleyin ve sonucun tekrar kaydedilmesini sağlayarak her listenin yarısını alın (alternatif öğe yaklaşımını kullanarak) q.

⟦⪫ΦEθ⪫ι ι|⟧

qBoşluklarla ve dikey çizgilerle birleştirilen öğelerini yazdırın . Aslında, bu noktada, unsurları qya boş ya da tek elemanlı listelerdir, bu yüzden onları birleştirmek onları sadece boş dizgilere ya da elemanlarına dönüştürür. Boş dizeler gereksiz iz bırakma çizgileri ekler, böylece filtrelenirler. Bir düzleştirici operatör olsa da golfçü olurdu (gibi bir şey ⟦⪫Σθ|⟧).

W⊖Lθ«

qBirden fazla eleman varken tekrarlayın . (Aşağıdaki kod eşit sayıda eleman gerektirir.)

≔⮌θη≔⟦⟧θ

Kopya qiçin h, ama (aşağıya bakınız) ters ve reset qboş listeye.

Wη«

hBoş olana kadar tekrarlayın .

≔⊟ηε

Bir sonraki öğeyi hiçine çek e. ( PopSonundan alıntılar, bu yüzden geri dönmem gerekiyor q.)

≔⟦⟧ζ

zBoş bir listeye sıfırla .

F⊟η«

Bir sonraki öğenin öğelerinin üzerine döngü h.

≔εδ≔⟦⟧ε

Kopya eiçin dve sıfırlama eboş listeye.

Fδ

Elemanları üzerinde döngü d.

⊞⎇‹IμIλζεμ

Onları itin zveya eonlar bir sonraki elemanın akım elemanı daha küçük olmasına bağlı olarak h.

⊞ζλ»

Sonraki elemanın akım elemanı itin hiçin z.

⊞θ⁺ζε»

zKalan tüm öğelerle bir araya gelin eve bunu itin q. Bu, iki öğenin birleştirilmesini tamamlar h.

⟦⪫Eθ⪫κ ¦|

qBoşluklarla ve dikey çizgilerle birleştirilen öğelerini yazdırın .


Dayan. Başka bir böcek var mı? : /
ASCII-sadece

Sadece ASCII @ Hayır, bu while (...Map(...)...)zaten size bahsettiğim hataydı.
Neil,


2

JavaScript (ES6), 145 bayt

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`|`:``)

Girdiyi dizi içinde dizi olarak alır, yani f([[6,5,4,3,2,1]]). Çıktının ilk ve son satırlarını oluşturarak çalışır, sonra her alt dizinin uzunluğu 1 olana kadar kendisini tekrar bölerek çağırıp çalışır. İşte nasıl çalıştığının temel bir gösterimi:

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
Peki, 145 bayta bağlı üç cevabın olduğu bir nokta var mıydı?
Neil,

2

Kabuğu , 14 bayt

S+ȯ†O↔hUmfL¡ṁ½

Tek bir dizi içeren bir dizi alır. Çevrimiçi deneyin!

açıklama

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.

Yerleşik ½bir dizi alır ve ortada bunu böler. Uzunluğu tuhafsa, ilk kısım bir eleman tarafından daha uzundur. Bir singleton dizisi [a]sonuçlanır [[a],[]]ve boş bir dizi []verir [[],[]], bu nedenle uygulamadan önce boş dizileri kaldırmak gerekir U.


1

Stax , 116 (÷ 3>) 38 29 bayt CP437

@ Recursive tarafından yorum başına -9 bayt. Şimdi girdi, tek elemanı sıralanacak sayıların bir dizisi olan bir tekil olarak verilir.

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

Çevrimiçi deneyin!

35 baytlık paketsiz sürüm:

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

açıklama

Kod iki bölüme ayrılabilir. İlk bölüm ayrılmayı görselleştiriyor, ikincisi birleşmeyi görselleştiriyor.

Bölmenin görselleştirilmesi için kod:

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

Birleşmeyi görselleştirmek için kod:

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

Eski versiyon, aslında yuvalanmış liste yapısını inşa ediyor.

{{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+= Yığının tepesinin bir skaler mi yoksa bir dizi mi olduğunu kontrol etmek için kodda üç kez kullanılır.

{{cc0+=!{x!}Mm',*:}}Xİç içe geçmiş bir sayı dizisini doğru bir şekilde çıkarmaya devam etmek için kendisini tekrarlayan bir blok oluşturur. (Stax'taki varsayılan çıktı, yazdırmadan önce iç içe geçmiş bir diziyi vektörleştirir).

{                  }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

Sırasıyla, bölmeyi ve birleştirmeyi gerçekleştiren iki blok daha var. Onlar çok ayrıntılı ve açıklamak umurumda değil (bu yazının tarihsel versiyonunda biraz daha fazla bilgi var ama çok fazla beklemeyin).


Çok güzel gelişme. Henüz tam olarak anlamadım, ama bunun cH!yerine kullanılabileceğini düşünüyorum cH%!.
özyinelemeli

{Nd}Mayrıca ile değiştirilebilir T.
özyinelemeli

Biraz daha adaptasyon yaptım. staxlang.xyz/… Husk cevabı bir dizideki diziyi girdi olarak alır, sanırım bu yasal.
özyinelemeli

2 ascii karakterden daha kısa olması gereken bir çözüm buldum, ancak dizi transpozisyonunda bir hata buldum. Spesifik olarak, dizi satırlarını değiştirir. 1.0.4 için backlog'a ekleyeceğim
özyinelemeli

TAMAM. Güncellemeyi dört gözle bekliyorum.
Weijun Zhou,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.