BrainF'de QuickSort Uygula *** [kapalı]


32

Stack Overflow'taki Lounge odasında tartışıldığı gibi:

en.wikipedia.org/wiki/Quicksort verilen Quicksort algoritmasını en az bildiğiniz herhangi bir dilde uygulayamıyorsanız, farklı bir mesleği düşünmek isteyebilirsiniz. @sbi

Ancak SBI, BrainF'in belki de bir istisna olduğunu belirtti.

Yani, işte bulmaca / meydan okuma: BrainF'de QuickSort'u uygulayın *** . Uygulama gerekir

  • tarafından yorumlanabilir bu ve / veya tercüman (lar) tarafından burada (büyük komut dosyaları için)
  • algoritmayı Wikipedia'da açıklandığı şekilde uygulayın - mümkünse yerinde sıralama olarak
  • aşağıdaki tam sayı listesini sıralayın: [0,4,6,4,2,3,9,2,3,6,5,3] ve sonucu yazdırın

Biraz aranıyor Bir uygulama bulabiliyorum , ama 6kB (ve Haskell'den derlendi).
Peter Taylor

@Peter aslında brainfuck uygulaması arşivi içinde 474,2 K - ki bu beklediğimden biraz daha büyük (ve çevrimiçi tercüman için çok büyük). Belki de hedef tercümanı değiştirmeliyim .. (ama elle yazılmış bir şeyler görmeyi çok isterdim )
Ronald

22
Bahse girerim kabarcık sıralaması yapabilirim ve koda bakacak olan kimse
aradaki

1
@Keith fikri gerçekten işe yarayacak herhangi bir tür değil, gerçekten QuickSort'u uygulamaktır ... :-)
Ronald

1
@ Mısırın Peter: Kötü performans tarafından bir kabarcık sıralama keşfedecekti.
kullanıcı bilinmeyen

Yanıtlar:


55

BrainF * (697 bayt)

>>>>>>>>,[>,]<[[>>>+<<<-]>[<+>-]<+<]>[<<<<<<<<+>>>>>>>>-]<<<<<<<<[[>>+
>+>>+<<<<<-]>>[<<+>>-]<[>+>>+>>+<<<<<-]>[<+>-]>>>>[-<->]+<[>->+<<-[>>-
<<[-]]]>[<+>-]>[<<+>>-]<+<[->-<<[-]<[-]<<[-]<[[>+<-]<]>>[>]<+>>>>]>[-<
<+[-[>+<-]<-[>+<-]>>>>>>>>[<<<<<<<<+>>>>>>>>-]<<<<<<]<<[>>+<<-]>[>[>+>
>+<<<-]>[<+>-]>>>>>>[<+<+>>-]<[>+<-]<<<[>+>[<-]<[<]>>[<<+>[-]+>-]>-<<-
]>>[-]+<<<[->>+<<]>>[->-<<<<<[>+<-]<[>+<-]>>>>>>>>[<<<<<<<<+>>>>>>>>-]
<<]>[[-]<<<<<<[>>+>>>>>+<<<<<<<-]>>[<<+>>-]>>>>>[-[>>[<<<+>>>-]<[>+<-]
<-[>+<-]>]<<[[>>+<<-]<]]>]<<<<<<-]>[>>>>>>+<<<<<<-]<<[[>>>>>>>+<<<<<<<
-]>[<+>-]<+<]<[[>>>>>>>>+<<<<<<<<-]>>[<+>-]<+<<]>+>[<-<<[>+<-]<[<]>[[<
+>-]>]>>>[<<<<+>>>>-]<<[<+>-]>>]<[-<<+>>]>>>]<<<<<<]>>>>>>>>>>>[.>]

Aşağıda açıklamalı bir sürüm bulunmaktadır. Geliştirirken ne olması gerektiğini takip etmek için, şuna benzeyen bir yorum yazımı kullandım:|a|b=0|c=A0|@d|A0|A1|```|

|a| represents a named cell
|b=X| means we know the cell has value X, where X can be a constant or a variable name
|@d|  means the data pointer is in this cell
|A0|A1|```| is variable length array. (using ``` for ... because . is a command)

Bellek, solda işlenecek solda büyüyen bir bölüm yığını, merkezde bir çizik alanı ve dizinin sağa doğru sıralanmasıyla düzenlenmiştir. Dizi dizini, dizini ve çalışma alanını içeren bir "veri yolunu" dizi içinde hareket ettirerek gerçekleştirilir. Mesela 3 genişliğinde bir otobüs, birer birer kaydırıldıktan sonra |i|data|0|A0|A1|A2olacak |A0|i-1|data|0|A1|A2. Bölme, veri yolu yüksek ve düşük elemanlar arasında tutularak gerçekleştirilir.
İşte tam sürüm:

Get input
>>>>>>>> ,[>,]                      |A0|A1|```|An|@0|
Count items
<[ [>>>+<<<-]>[<+>-]<+ <]  |@0|n|0|0|A0|A1|```
Make 8wide data bus w/ stack on left
>[<<<<<<<<+>>>>>>>>-]  ```|K1=n|K0=0|Z=0|a|b|c|d|e|@f|g|X=0|A0|A1|```
K1 and K0 represent the first index to process (I) and one past the last (J)
Check if still partitions to process
<<<<<<<<[
  Copy K1 to a&c via Z
  [>>+>+>>+<<<<<-]>>[<<+>>-] ```|K1=J|K0=I|@Z=0|a=J|b|c=J|d|e|f|g|X=0|A0|A1|```
  Copy K0 to b&d via Z
  <[>+>>+>>+<<<<<-]>[<+>-] ```|K1|K0|@Z=0|a=J|b=I|c=J|d=I|e|f|g|X=0|A0|A1|```
  Check if J minus I LE 1 : Subtract d from c
  >>>>[-<->]                    |a=J|b=I|c=JminusI|@d=0|e|f|g|
  d= c==0; e = c==1
  +<[>- >+<<-[>>-<<[-]]]        |a=J|b=I|@c=0|d=c==0|e=c==1|f|g|
  if d or e is 1 then J minus I LE 1: partition empty
  >[<+>-]>[<<+>>-]<+<      |a=J|b=I|@c=isEmpty|d=1|e=0|f|g|
  If Partition Empty;
  [->-                      |a=J|b=I|@c=0|d=0|c=0|f|g|
    pop K0: Zero it and copy the remaining stack right one; inc new K0
    <<[-]<[-]<<[-]<[[>+<-]<]>>[>]<+    ``|K1|@Z=0|a=J|b=I|c=0|d=0|e|f|g|
  Else:
  >>>>]>[-                   Z|a=J|b=I|c=isEmpty=0|@d=0|e|f|g|X|A0|A1
    Move Bus right I plus 1 frames; leaving first element to left
    <<+[ -[>+<-]<-[>+<-]>>>>>>>>      (dec J as we move)
      [<<<<<<<<+>>>>>>>>-]<<<<<< ]      Z|Ai|a=J|@b=0|c=0|d|e|f|g|X|Aq
    first element becomes pivot Ap; store in b
    <<[>>+<<-]            Z|@0|a=J|b=Ap|c=0|d|e|f|g|X|Aq
    While there are more elements (J GT 0);
    >[                    Z|0|@a=J|b=Ap|c=0|d|e|f|g|X|Aq
      copy Ap to e via c
      >[>+>>+<<<-]>[<+>-]  Z|0|a=J|b=Ap|@c=0|d=0|e=Ap|f|g|X=0|Aq
       copy Aq to g via X
      >>>>>>[<+<+>>-]<[>+<-] |c|d=0|e=Ap|f|g=Aq|@X=0|Aq
      Test Aq LT Ap:  while e; mark f; clear it if g 
      <<<[ >+>[<-]<[<]           |@d=0|e|f=gLTe|g|
        if f: set d and e to 1; dec e and g 
        >>[<<+>[-]+>-]>-<<-]
      set g to 1; if d: set f 
      >>[-]+<<< [->>+<<]
      If Aq LT Ap move Aq across Bus
      >>[->- <<<<<[>+<-] <[>+<-] >>>>>>>>
        [<<<<<<<<+>>>>>>>>-] <<]  Z|0|Aq|a=J|b=Ap|c|d|e|@f=0|g=0|X=0|Ar
      Else Swap AQ w/ Aj: Build a 3wide shuttle holding J and Aq                
      >[[-] <<<<<<[>>+>>>>>+<<<<<<<-]>>[<<+>>-] |@c=0|d|e|f=0|g=0|X=J|Aq|Ar|```
      If J then dec J
      >>>>>[-
        & While J shuttle right
        [>>[<<<+>>>-]<[>+<-]<-[>+<-]>] |a=J|b=Ap|c|d|e|f|Ar|```|Aj|g=0|@X=0|Aq|
        Leave Aq out there and bring Aj back
        <<[ [>>+<<-] < ]              |a=J|b=Ap|c|d|e|@f=0|g|X=0|Ar|```|Aj|Aq|
      ]>]
    Either bus moved or last element swapped; reduce J in either case
    <<<<<<-]                 |Aq|@a=0|b=Ap|c|d|e|f|g|X|Ar|```|
    Insert Ap To right of bus
    >[>>>>>>+<<<<<<-]        |Aq|a=0|@b=0|c|d|e|f|g|Ap|Ar|```|
    Move the bus back to original location tracking pivot location
    <<[ [>>>>>>>+<<<<<<<-]>[<+>-]<+ <]     
    <[ [>>>>>>>>+<<<<<<<<-]>>[<+>-]<+ <<] |K1|K0|@Z=0|a=0|b=p|c|d|e|f|g|X|Ar|```
    if p is not 0:  put new partition on stack between K0 and K1:
    >+>[<-                                 |K1|K0|Z=0|@a=pEQ0|b=p|
      move K0 to Z; search for last K
      <<[>+<-] <[<]                           |@0|Kn|```|K1|0|Z=K0|a=0|b=p| 
      shift left until return to 0 at K0;
      >[ [<+>-] >]                            |Kn|```|K1|0|@0|Z=K0|a=0|b=p|
      put p one left of there making it K1; restore K0 from Z;
      >>>[<<<<+>>>>-]<<[<+>-]                 |Kn|```|K2|K1=p|K0|@Z=0|a=0|b=0|
    else increment K0 (special case when first partition empty) 
    >>]<[- <<+>>]              
  >>>]  End if !empty
<<<<<<] End If Partitions remaining   @K1=0|K0=0|Z=0|a|b|c|d|e|f|g|X=0|A0|A1|```
Print the Results
>>>>>>>>>>>[.>]

Benzer bir çözüm üzerinde çalışıyordum ancak çalışmasını sağlayamıyorum. Bu şekilde bölümleme yapmak için harika bir fikir. Her seferinde bir elementi çıkartıyor ve değiştiriyordum ve oldukça çabukça hantallaştı. Ayrıca 1.5k bindim, sen de beni verimlilik konusunda mahvettin.
captncraig

1
BF'deki her şey oldukça çabuk hantallaşıyor :) Verimli bir şekilde basit şeyler bile görünmek if (i<j) {} else {}için doğru bile olsa birkaç denemeye başladı. Ve kenar davaları katil. Kaç kere "sadece bu küçük şeyin bırakıldığını ..." düşündüğümü bilmiyorum ve birkaç saat daha çalışmamıza neden olan bir test davası keşfettim. Sanırım birkaç düzine karakter azaltabilirim, ancak bu çabayı göstermek istediğimden emin değilim.
AShelly

Bir kelime: vay! Gerçekten insanca mümkün olduğunu düşünmedim. Nasıl çalıştığını görmek için birkaç girdi
Ronald

Epik! Sadece epik!
vsz

Söylenecek tek şey "kutsal f * ck!"
Matematik chiller

11

beyin fırtınası (178 bayt)

Brainfuck hantal olsa bile, dilin tahıl ile çalışmak için yardımcı olur. Kendinize "Bu değeri açıkça bir hücrede depolamak zorunda mıyım?" Daha ince bir şey yaparak sık sık hız ve karar kazanabilirsiniz. Değer bir dizi dizini (veya rastgele bir doğal sayı) olduğunda, bir hücreye sığmayabilir . Tabii ki, bunu programınızın sınırı olarak kabul edebilirsiniz. Ancak, programınızı büyük değerlerle başa çıkacak şekilde tasarlamak, genellikle başka şekillerde daha iyi hale getirecektir.

Her zamanki gibi, ilk çalışan sürümüm olması gerekenden iki katıydı - 392 bayt. Çok sayıda değişiklik ve iki veya üç büyük yeniden yazma, bu nispeten zarif 178 bayt sürümü üretti. (Eğlenceli bir şekilde doğrusal zaman sıralama olsa da , sadece 40 bayttır.)

>+>>>>>,[>+>>,]>+[--[+<<<-]<[[<+>-]<[<[->[<<<+>>>>+<-]<<[>>+>[->]<<[<]
<-]>]>>>+<[[-]<[>+<-]<]>[[>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]<<[<<<]>[>>[>>
>]<+<<[<<<]>-]]+<<<]]+[->>>]>>]>[brainfuck.org>>>]

Giriş değerleri her üç hücreye yerleştirilir: her (V) alue hücresi için, bir (L) abel hücresi (navigasyon için kullanılır) ve (S) kazı alanı için bir hücre daha vardır. Dizinin genel düzeni

0 1 0 0 0 SVLSVL ... SVL 0 0 0 0 0 0 ...

Başlangıçta, tüm L hücreleri, hala sıralanması gereken dizinin kısımlarını işaretlemek için 1'e ayarlanır. Bir alt diziyi bölmeyi bitirdiğimizde, pivotunun L hücresini 0'a ayarlayarak daha küçük alt dizilere böler, sonra hala 1 olan en sağdaki L hücresini ve sonradan alt diziyi bölen bölümü buluruz. İşin garibi, alt kayıtların özyinelemeli işlemlerini düzgün bir şekilde yapmamız için gereken tüm kayıt tutma işlemleri budur. Tüm L hücreleri sıfırlandığında, tüm dizi sıralanır.

Bir alt diziyi bölmek için, en sağdaki değeri, Pivot gibi davranmak için bir S hücresine çekeriz ve onu (ve buna karşılık gelen boş V hücresini), alt dizideki diğer değerlerle karşılaştırarak ve gerektiğinde değiştiririz. Sonunda, pivot aynı takas kodunu kullanarak (50 byte tasarruf sağlayan) tekrar takılır. Bölünme sırasında, birbiriyle değiştirilmesi gerekebilecek iki hücreyi işaretlemek için iki ekstra L hücresi 0 olarak tutulur; bölümlemenin sonunda, sol 0, alt dizinin solundaki 0 ​​ile birleşir ve sağ 0, dönme noktasını işaretleyerek sona erer. Bu işlem ayrıca, L hücresinde, alt dizinin sağına ekstra 1 bırakır; ana döngü bu hücrede başlar ve biter.

>+>>>>>,[>+>>,]>+[                      set up; for each subarray:
    --[+<<<-]<[                         find the subarray; if it exists:
        [<+>-]<[                        S=pivot; while pivot is in S:
            <[                          if not at end of subarray
                ->[<<<+>>>>+<-]         move pivot left (and copy it) 
                <<[>>+>[->]<<[<]<-]>    move value to S and compare with pivot
            ]>>>+<[[-]<[>+<-]<]>[       if pivot greater then set V=S; else:
                [>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]     swap smaller value into V
                <<[<<<]>[>>[>>>]<+<<[<<<]>-]        swap S into its place
            ]+<<<                       end else and set S=1 for return path
        ]                               subarray done (pivot was swapped in)
    ]+[->>>]>>                          end "if subarray exists"; go to right
]>[brainfuck.org>>>]                    done sorting whole array; output it

1
Muhteşem. BF'nin deyimleriyle çalışırken, benim yaptığım gibi bir prosedürel dil gibi davranmaya zorlamak yerine, çok daha temiz.
AShelly

Bu; ancak 392 bayttaki 4. versiyon da deyimsel beyin fırtınasıydı. Bu sürüm 39 ya da öylesine. :)
Daniel Cristofani
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.