เรียงลำดับที่เร็วที่สุดใน BrainF ***


15

หลังจากนำQuickSortมาใช้ใน BrainF ***ฉันรู้ว่าอาจไม่รวดเร็วเท่านี้ การดำเนินการที่เป็น O (1) ในภาษาปกติ (เช่นการจัดทำดัชนีแถวลำดับ) นั้นยาวกว่าใน BF อย่างมาก กฎส่วนใหญ่สำหรับสิ่งที่ทำให้การเรียงลำดับที่มีประสิทธิภาพสามารถโยนออกไปนอกหน้าต่างเมื่อคุณกำลังเขียนโค้ดในTuring tarpit

ดังนั้นนี่คือความท้าทายในการใช้ "การเรียงลำดับสมองที่เร็วที่สุด *** ฉันจะจับเวลารายการทั้งหมดโดยใช้ล่ามด้านล่าง ผู้บุกรุกใช้เทป 16K ของอักขระที่ไม่ได้ลงนาม ทั้งเทปและเซลล์ห่อเมื่อขั้นสูง / เพิ่มขึ้นผ่านขีด จำกัด การอ่าน EOF จะใส่ 0 ในเซลล์ปัจจุบัน เวลาที่วัดได้รวมทั้งเวลาในการวิเคราะห์ไฟล์ต้นฉบับและเวลาในการประมวลผลไฟล์อินพุตทั้งหมด รหัสที่เร็วที่สุดชนะ

เวกเตอร์ทดสอบจะเป็นชุดของไฟล์ Ascii ที่ออกแบบมาเพื่อทดสอบการเรียงตัวขอบกรณีรวมถึง

  • รายการที่เรียงลำดับแล้ว: "สั่งแล้ว"

    &#33;"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
    
  • รายการที่เรียงกลับกัน: "ย้อนกลับ"

    ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!
    
  • ไฟล์ประกอบด้วยสำเนาที่ไม่ซ้ำกันหลายค่า: "onlynine"

    ibbkninbkrauickabcufrfckbfikfbbakninfaafafbikuccbariauaibiraacbfkfnbbibknkbfankbbunfruarrnrrrbrniaanfbruiicbuiniakuuiubbknanncbuanbcbcfifuiffbcbckikkfcufkkbbakankffikkkbnfnbncbacbfnaauurfrncuckkrfnufkribnfbcfbkbcrkriukncfrcnuirccbbcuaaifiannarcrnfrbarbiuk
    
  • ไฟล์ ascii แบบสุ่มสมบูรณ์: "random"

    'fQ`0R0gssT)70O>tP[2{9' 0.HMyTjW7-!SyJQ3]gsccR'UDrnOEK~ca 'KnqrgA3i4dRR8g.'JbjR;D67sVOPllHe,&VG"HDY_'Wi"ra?n.5nWrQ6Mac;&}~T_AepeUk{:Fwl%0`FI8#h]J/Cty-;qluRwk|S U$^|mI|D0\^- csLp~`VM;cPgIT\m\(jOdRQu#a,aGI?TeyY^*"][E-/S"KdWEQ,P<)$:e[_.`V0:fpI zL"GMhao$C4?*x
    
  • ไฟล์สุ่มในช่วง 1..255: "wholerange"

    öè—@œ™S±ü¼ÓuǯŠf΀n‚ZÊ,ˆÖÄCítÚDý^öhfF†¬I÷xxÖ÷GààuÈ©ÈÑdàu.y×€ôã…ìcÑ–:*‰˜IP¥©9Ä¢¬]Š\3*\®ªZP!YFõ®ÊÖžáîÓ¹PŸ—wNì/S=Ìœ'g°Ì²¬½ÕQ¹ÀpbWÓ³
    »y  »ïløó„9k–ƒ~ÕfnšÂt|Srvì^%ÛÀâû¯WWDs‰sç2e£+PÆ@½ã”^$f˜¦Kí•òâ¨÷ žøÇÖ¼$NƒRMÉE‹G´QO¨©l¬k¦Ó 
    

ไฟล์อินพุตแต่ละไฟล์มีขนาดไม่เกิน 255 ไบต์

นี่คือล่าม มันถูกเขียนขึ้นสำหรับ Windows ในโหมดคอนโซล แต่ควรพอร์ตได้ง่าย: เพียงแค่แทนที่read_time()และsysTime_to_ms()เทียบเท่ากับแพลตฟอร์มเฉพาะ
การใช้งาน: bftime program.bf infile1 [infile2 ...]

#include <windows.h>
#include <stdio.h>

#define MS_PER_SEC  1000.0f
#define MAXSIZE  (0x4000)
#define MAXMASK  (MAXSIZE-1)

typedef  __int64 sysTime_t;
typedef unsigned char Uint8;
typedef unsigned short Uint16;

typedef struct instruction_t {
   Uint8 inst;
   Uint16 pair;
} Instruction;

Instruction prog[MAXSIZE] = {0};
Uint8 data[MAXSIZE] = {0};
const Uint8 FEND = EOF;

sysTime_t read_time() {
    __int64 counts;
    QueryPerformanceCounter((LARGE_INTEGER*)&counts);
    return counts;
}

float sysTime_to_ms(sysTime_t timeIn) {
    __int64 countsPerSec;
    QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
    return (float)timeIn * MS_PER_SEC / (float)countsPerSec;
}

int main(int argc, char* argv[])
{
   FILE* fp;
   Uint8 c;
   Uint16 i = 0;
   Uint16 stack = 0;
   sysTime_t start_time;
   sysTime_t elapsed=0,delta;

   if (argc<3) exit(printf("Error: Not Enough Arguments\n"));
   fp = fopen(argv[1],"r");
   if (!fp) exit(printf("Error: Can't Open program File %s\n",argv[1]));

   start_time=read_time();
   while (FEND != (c = fgetc(fp)) && i <MAXSIZE) {
      switch (c)  {
      case '+': case '-': case ',': case '.': case '>': case '<':
         prog[++i].inst = c;
         break;
      case '[': 
         prog[++i].inst = c;
         prog[i].pair=stack;
         stack = i;
         break;
      case ']': 
         if (!stack) exit(printf("Unbalanced ']' at %d\n",i));
         prog[++i].inst = c;
         prog[i].pair=stack;
         stack = prog[stack].pair;
         prog[prog[i].pair].pair=i;
         break;
      }
   }
   if (stack) exit(printf("Unbalanced '[' at %d\n",stack));
   elapsed = delta = read_time()-start_time;
   printf("Parse Time: %f ms\n", sysTime_to_ms(delta));

   for (stack=2;stack<argc;stack++) {
      Instruction *ip = prog;
      fp = fopen(argv[stack],"r");
      if (!fp) exit(printf("Can't Open input File %s\n",argv[stack]));
      printf("Processing %s:\n", argv[stack]);
      memset(data,i=0,sizeof(data));

      start_time=read_time();
      //Run the program
      while (delta) {
         switch ((++ip)->inst) {
         case '+': data[i]++; break;
         case '-': data[i]--; break;
         case ',': c=getc(fp);data[i]=(FEND==c)?0:c; break;
         case '.': putchar(data[i]);  break;
         case '>': i=(i+1)&MAXMASK;   break;
         case '<': i=(i-1)&MAXMASK;   break;
         case '[': if (!data[i]) ip = prog+ip->pair; break;
         case ']': if (data[i])  ip = prog+ip->pair;  break;
         case 0: delta=0; break;
         }
      }
      delta = read_time()-start_time;
      elapsed+=delta;
      printf("\nProcessing Time: %f ms\n", sysTime_to_ms(delta));
   }
   printf("\nTotal Time for %d files: %f ms\n", argc-2, sysTime_to_ms(elapsed));
}

ผลลัพธ์จนถึงตอนนี้

นี่คือเวลาเฉลี่ย 5 การวิ่งของเซตเวกเตอร์ที่สมบูรณ์:

 Author    Program      Average Time    Best Set          Worst Set
 AShelly   Quicksort    3224.4 ms       reverse (158.6)   onlynine (1622.4) 
 K.Randall Counting     3162.9 ms       reverse (320.6)   onlynine  (920.1)
 AShelly   Coinsort      517.6 ms       reverse  (54.0)   onlynine  (178.5) 
 K.Randall CountingV2    267.8 ms       reverse  (41.6)   random     (70.5)
 AShelly   Strandsort    242.3 ms       reverse  (35.2)   random     (81.0)

ช่วงขององค์ประกอบอินพุตคืออะไร?
Keith Randall

มันเป็นช่วงของเซลล์ยกเว้น 0: 1-255
AShelly

คุณควรปรับเวลาของฉันฉันทำให้มันค่อนข้างเร็ว
Keith Randall

มันดูเหมือนว่าจะเร็วกว่า 2x กว่าล่าสุดของฉัน - ฉันจะทำเวลาอย่างเป็นทางการเมื่อฉันกลับไปที่เครื่องที่ฉันใช้เพื่อคนอื่น
AShelly

คำตอบ:


9

นี่คือประเภทที่เร็วกว่า 6xSort ของฉันอย่างน้อย 6 เท่า มันเป็นอัลกอริทึมที่เข้าใจได้ง่ายในภาษาดั้งเดิมเนื่องจากเป็น O (N * m) โดยที่ m คือค่าอินพุตสูงสุด หลังจากรวบรวมอินพุตมันจะผ่านอาร์เรย์นับเซลล์> 0 จากนั้นลดค่าแต่ละอัน จากนั้นจะเพิ่ม 1 เป็นcountเซลล์แรกในผลลัพธ์เวกเตอร์ มันจะทำซ้ำผ่านจนนับเป็น 0
BF:

Get Input
>,[>>+>,]   
Count values GT 0 and decrement each
<[<[<<<+>>>-]<[-<<+>>>]>[<]<<]
While count: add 1 to results
<[[[<<+>>-]<+<-]
Seek back to end of input
>[>>]>>>[>>>]
Repeat counting step
<<<[<[<<<+>>>-]<[-<<+>>>]>[<]<<]<]
Seek to far end of results and print in reverse order 
<[<<]>>[.>>]

อัลกอริทึมเทียบเท่า C:

 uchar A[MAX]={0}; uchar R[MAX]={0}; int count,i,n=0;
 while (A[n++]=getchar()) ;
 do { 
   count = 0;
   for (i=0; i<n; i++) count += (A[i]) ? (A[i]-->0) : 0;
   for (i=0; i<count; i++) R[i]++; 
 } while (count>0);
 for (i=0; R[i]; i++) ;
 for (i--; i>=0; i--) putchar(R[i]);

นี่คือ 2x เร็ว มันขึ้นอยู่กับ"การจัดเรียงสปาเก็ตตี้"อย่างอิสระ: มันวางสตริง 1s ตราบใดที่แต่ละอินพุต ค่าในแต่ละเซลล์แสดงถึงจำนวนเส้นอย่างน้อยที่สุดความยาว (ดังนั้น [3,2,1,2] จึงกลายเป็น|4|0|3|0|1|0|0| ) จากนั้นจะเริ่ม 'วัด' เส้นและพิมพ์ความยาวทุกครั้งที่พบจุดสิ้นสุด

>,[ [-[>>+<<-]>+>] <[<<]>,]   build strand of 1s for each input
+>[>+<-]>[                    while there are strands
  >[>+<<->-]                  do any strands end here?
  <[<<.>>-]                   print length of all that do  
  <<[>>+<<-]>>+>>]            shift right 1; inc length 

ดิบ:

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

อย่าเคาะนับเรียง! มันเป็นเกมโปรดของฉันเนื่องจากการชนะครั้งใหญ่ที่ฉันได้รับจากมันในครั้งเดียว: ถ้า m เป็นที่รู้จักกันในชื่อเล็กคุณสามารถเพิ่มความเร็วได้มากกว่าวิธีอื่น ๆ "เร็ว" ในทำนองเดียวกัน Bubble Sort Beats จะจัดเรียงข้อมูลอย่างรวดเร็วเป็นส่วนใหญ่ ไม่มีอัลกอริทึม ___ ใดที่ดีที่สุดสำหรับทุกบริบท
บูธตาม

ฉันไม่คิดว่ามันจะเป็นการจัดเรียงที่แน่นอน ความคิดเห็นของคุณบังคับให้ฉันทำวิจัยเพิ่มเติม ผมคิดว่านี่เป็นเหมือนการจัดเรียงลูกปัด แต่ฉันไม่แน่ใจด้วยซ้ำ
AShelly

ไม่ถูกต้อง นี่เป็นเรื่องแปลก ๆ อาจมีประโยชน์สำหรับแอปพลิเคชันบางรายการที่เชื่อมโยงกับรายการที่เชื่อมโยง ... แต่ฉันก็ยังสงสัยอยู่ดี
บูธตาม

4
การเปรียบเทียบทางกายภาพคือคุณมีเหรียญ N ขนาดแตกต่างกัน จัดสรรพื้นที่สำหรับกอง N ตัวอื่น คุณนำหนึ่งเหรียญออกจากด้านบนของแต่ละสแต็คที่มีเหรียญแล้วเพิ่ม 1 ถึงแต่ละสแต็กในชุดใหม่จากขวาไปซ้ายจนกว่ามือของคุณจะว่างเปล่า ทำซ้ำจนกว่าสแต็กดั้งเดิมทั้งหมดจะว่างเปล่า ตอนนี้ชุดใหม่จะถูกจัดเรียงจากซ้ายไปขวา
AShelly

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

ฉันจำไม่ได้ว่าใครมีความคิดว่าอัลกอริทึมนี้คืออะไร บางที Bertram Felgenhauer หรือไม่ มันมาจากการอภิปรายเกี่ยวกับการแข่งขัน Brainfuck Golf # 2 เมื่อกว่าทศวรรษที่แล้ว

นี่คือสิ่งที่เร็วที่สุดในอินพุตตัวอย่าง

มันไม่ได้ จำกัด เฉพาะอินพุตที่มีความยาว <256 แต่สามารถจัดการอินพุตที่มีความยาวได้ตามใจชอบ

ทั้งสองสิ่งนี้เป็นจริงสำหรับคำตอบของอัลเบิร์ตด้วยเช่นกัน สิ่งที่ดีเกี่ยวกับอันนี้คือเวลาทำงานคือ O (N) ในความยาวอินพุต ใช่สิ่งนี้ทำงานจริงในเวลาเชิงเส้น มันกินปัจจัยคงที่จาก 255 เป็นอาหารว่าง


3

การดำเนินการเรียงลำดับการนับง่าย ๆ ที่เก็บข้อมูลแต่ละอันมีความกว้าง 3 เซลล์ประกอบด้วยการป้อนข้อมูลปัจจุบันเครื่องหมายและการนับจำนวนครั้งที่ตัวนับปรากฏในอินพุต

process input
,[

while input is not zero
[

decrement input
-

copy input over to next bucket
[->>>+<<<]

mark next bucket as not the first
>>>>+<

repeat until input is zero
]

increment count for this bucket
>>+

rewind using markers
<[-<<<]<

process next input
,]

generate output
>+[>[<-.+>-]<[->>>+<<<]>>>+]

โดยไม่ต้องแสดงความคิดเห็น:

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


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