ติดตั้ง QuickSort ใน BrainF *** [ปิด]


32

ตามที่กล่าวไว้ในห้องเลานจ์ของ Stack Overflow:

หากคุณไม่สามารถใช้อัลกอริทึม Quicksort ที่กำหนด en.wikipedia.org/wiki/Quicksort ในภาษาใด ๆ ที่คุณมีความรู้น้อยที่สุดคุณอาจต้องการพิจารณาอาชีพอื่น @sbi

แต่ SBI ยังตั้งข้อสังเกตว่า BrainF *** อาจเป็นข้อยกเว้น

ดังนั้นนี่คือปริศนา / ความท้าทาย: ใช้ QuickSort ในBrainF *** การดำเนินการจะต้อง

  • ถูกตีความโดยสิ่งนี้และ / หรือโดยล่ามที่นี่ (สำหรับสคริปต์ขนาดใหญ่)
  • ใช้อัลกอริทึมตามที่อธิบายไว้ใน Wikipedia - ถ้าเป็นไปได้เป็นการเรียงลำดับ
  • จัดเรียงรายการจำนวนเต็มต่อไปนี้: [0,4,6,4,2,3,9,2,3,6,5,3] และพิมพ์ผลลัพธ์

กำลังค้นหาสิ่งเล็กน้อยฉันสามารถค้นหาการนำไปใช้งานได้ แต่เป็น 6kB (และรวบรวมจาก Haskell)
Peter Taylor

@Peter ที่จริงแล้วการใช้สมองเป็น 474.2 K ภายในคลังข้อมูล - ซึ่งใหญ่กว่าที่ฉันคาดไว้เล็กน้อย (และใหญ่เกินไปสำหรับล่ามออนไลน์) บางทีฉันควรเปลี่ยนล่ามเป้าหมาย .. ( แต่ฉันจะรักที่จะเห็นบางสิ่งบางอย่างที่เขียนด้วยมือ)
โรนัลด์

22
ฉันเดิมพันที่ฉันจะทำฟองเรียงลำดับแทนและไม่มีใครที่กำลังมองหารหัสที่จะทราบความแตกต่าง ...
ปีเตอร์โอลสัน

1
@ แนวคิดนี้คือการนำ QuickSort ไปใช้จริง ๆ ไม่ใช่แค่การเรียงลำดับใด ๆ ที่จะใช้งานได้ ... :-)
Ronald

1
@ Peter Of The Corn: เราจะค้นพบฟองเรียงตามประสิทธิภาพที่ไม่ดี
ผู้ใช้ที่ไม่รู้จัก

คำตอบ:


55

BrainF * (697 ไบต์)

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

ด้านล่างเป็นรุ่นที่มีคำอธิบายประกอบ เพื่อที่จะติดตามสิ่งที่ควรจะเกิดขึ้นในขณะที่กำลังพัฒนามันฉันใช้สัญกรณ์แสดงความคิดเห็นที่มีลักษณะเช่นนี้:|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)

หน่วยความจำจะถูกจัดวางด้วยสแต็กของพาร์ติชันที่เพิ่มขึ้นด้านซ้ายเพื่อประมวลผลทางด้านซ้ายพื้นที่สแคร็ชที่กึ่งกลางและอาร์เรย์ที่เรียงลำดับไปทางขวา การจัดทำดัชนี Array ได้รับการจัดการโดยการย้าย "data bus" ที่มีดัชนีและพื้นที่ทำงานผ่านอาร์เรย์ ตัวอย่างเช่นรถบัสขนาดกว้าง 3 ของ|i|data|0|A0|A1|A2จะกลายเป็น|A0|i-1|data|0|A1|A2หลังจากเปลี่ยนทีละการแบ่งจะดำเนินการโดยทำให้บัสระหว่างองค์ประกอบสูงและต่ำ
นี่คือเวอร์ชั่นเต็ม:

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

ฉันกำลังทำงานกับโซลูชันที่คล้ายกัน แต่ไม่สามารถทำงานได้ แนวคิดที่ยอดเยี่ยมในการแบ่งพาร์ติชันด้วยวิธีนี้ ฉันดึงองค์ประกอบหนึ่งครั้งและแทนที่มันและมันค่อนข้างยุ่งยากอย่างรวดเร็ว ฉันยังเป็น 1.5k ด้วยดังนั้นคุณทำลายฉันด้วยประสิทธิภาพเช่นกัน
captncraig

1
ทุกอย่างใน BF ยุ่งยากไปอย่างรวดเร็ว :) แม้แต่สิ่งที่ดูเหมือนง่ายๆเช่นวิธีการทำอย่างมีประสิทธิภาพif (i<j) {} else {}ก็พยายามหลายครั้งเพื่อให้ถูกต้อง และกรณีขอบเป็นนักฆ่า ฉันไม่รู้ว่ากี่ครั้งที่ฉันคิดว่า "เหลือเพียงสิ่งเล็ก ๆ น้อย ๆ นี้แล้ว ... " จากนั้นก็ค้นพบกรณีทดสอบที่ทำให้ต้องทำงานอีกหลายชั่วโมง ฉันคิดว่าฉันสามารถลดมันได้ด้วยตัวละครไม่กี่โหล แต่ฉันไม่แน่ใจว่าฉันต้องการที่จะพยายาม
AShelly

คำเดียว: ว้าว! ฉันไม่คิดว่ามันเป็นไปได้อย่างมนุษย์ปุถุชน ฉันจะเรียกใช้ปัจจัยการผลิตไม่กี่ผ่านมันเพียงเพื่อดูวิธีการทำงาน :-)
โรนัลด์

มหากาพย์! เพียงมหากาพย์!
vsz

สิ่งเดียวที่จะพูดคือ "ศักดิ์สิทธิ์ f * ck!"
เครื่องทำความเย็นคณิตศาสตร์

11

brainfuck (178 ไบต์)

แม้ว่า brainfuck จะยุ่งยาก แต่ก็ช่วยให้ทำงานกับภาษาได้ ถามตัวเองว่า "ฉันต้องเก็บค่านี้ไว้ในเซลล์อย่างชัดเจนหรือไม่?" คุณมักจะได้รับความเร็วและความกระชับด้วยการทำสิ่งที่ลึกซึ้งยิ่งขึ้น และเมื่อค่าเป็นดัชนีอาเรย์ (หรือจำนวนธรรมชาติโดยพลการ) ก็อาจไม่เหมาะสมในเซลล์ แน่นอนคุณสามารถยอมรับได้ว่าเป็นข้อ จำกัด ของโปรแกรมของคุณ แต่การออกแบบโปรแกรมของคุณเพื่อจัดการกับค่าขนาดใหญ่มักจะทำให้ดีขึ้นในวิธีอื่น

ตามปกติเวอร์ชันการทำงานแรกของฉันนั้นยาวเป็นสองเท่าตราบเท่าที่จำเป็นต้องมีขนาด 392 ไบต์ การดัดแปลงจำนวนมากและการเขียนซ้ำครั้งใหญ่สองหรือสามครั้งทำให้รุ่น 178- ไบต์อันงดงามนี้ค่อนข้างสง่างาม (ถึงแม้ว่าการเรียงลำดับเชิงเส้นเชิงเส้นจะมีขนาดเพียง 40 ไบต์)

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

ค่าอินพุตจะเว้นระยะทุกสามเซลล์: สำหรับทุกเซลล์ (V) alue มีเซลล์ abel (L) (ใช้สำหรับการนำทาง) และอีกหนึ่งเซลล์สำหรับพื้นที่ cratch (S) เค้าโครงโดยรวมของอาร์เรย์คือ

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

เริ่มแรกเซลล์ L ทั้งหมดถูกตั้งค่าเป็น 1 เพื่อทำเครื่องหมายส่วนต่าง ๆ ของอาร์เรย์ที่ยังคงต้องเรียงลำดับ เมื่อเราแบ่งพาร์ติชั่นย่อยเสร็จแล้วเราแบ่งมันออกเป็นรูย่อยเล็ก ๆ โดยตั้งค่าเซลล์ L ของ pivot เป็น 0 จากนั้นหาเซลล์ L ขวาสุดที่ยังคงเป็น 1 และแบ่งพาร์ติชันย่อยถัดไป นี่คือการทำบัญชีทั้งหมดที่เราต้องการเพื่อจัดการกับการประมวลผลย่อยซ้ำ เมื่อเซลล์ L ทั้งหมดถูกทำให้เป็นศูนย์อาร์เรย์ทั้งหมดจะถูกจัดเรียง

ในการแบ่งพาร์ติชั่นย่อยเราจะดึงค่าที่ถูกต้องที่สุดไปยังเซลล์ S เพื่อทำหน้าที่เป็นเดือยและนำไปทางซ้าย (และเซลล์ V ว่างเปล่าที่สอดคล้องกัน) เปรียบเทียบกับค่าอื่น ๆ ในตอนท้ายเดือยจะได้รับการสลับกลับโดยใช้รหัส swap เดียวกัน (ซึ่งจะช่วยประหยัด 50 ไบต์หรือมากกว่านั้น) ในระหว่างการแบ่งพาร์ติชัน L เซลล์พิเศษสองเซลล์จะถูกตั้งค่าเป็น 0 เพื่อทำเครื่องหมายเซลล์สองเซลล์ที่อาจจำเป็นต้องสลับกัน ในตอนท้ายของการแบ่งพาร์ติชั่น 0 ที่เหลือจะรวมกับ 0 ที่ด้านซ้ายของระบบย่อยและ 0 ที่เหมาะสมจะสิ้นสุดการทำเครื่องหมายเดือย กระบวนการนี้ทำให้เหลือ 1 พิเศษในเซลล์ L ทางด้านขวาของ subarray ลูปหลักเริ่มต้นและสิ้นสุดที่เซลล์นี้

>+>>>>>,[>+>>,]>+[                      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
น่ากลัว มันดีกว่าเมื่อคุณทำงานกับสำนวนของ BF แทนที่จะพยายามบังคับให้มันทำตัวเหมือนภาษาเชิงกระบวนอย่างที่ฉันทำ
AShelly

มันคือ; แต่รุ่นที่ 4 ที่ 392 ไบต์ก็มีความคิดเหมือนกัน นี่คือรุ่น 39 หรือมากกว่านั้น :)
Daniel Cristofani
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.