Sắp xếp nhanh nhất trong BrainF ***


15

Sau khi thực hiện QuickSort trong BrainF *** , tôi nhận ra có lẽ nó không nhanh như vậy. Các hoạt động là O (1) trong các ngôn ngữ thông thường (như lập chỉ mục mảng) dài hơn đáng kể trong BF. Hầu hết các quy tắc cho những gì tạo ra một loại hiệu quả có thể bị ném ra ngoài cửa sổ khi bạn đang mã hóa trong một bạt Turing.

Vì vậy, đây là một thách thức để thực hiện "BrainF *** Sắp xếp thường xuyên nhất từ ​​trước đến nay". Tôi sẽ thời gian tất cả các mục bằng cách sử dụng trình thông dịch dưới đây. Intepreter sử dụng băng 16K gồm các ký tự không dấu. Cả băng và các ô đều bọc khi nâng / tăng vượt quá giới hạn. Đọc EOF đặt 0 trong ô hiện tại. Thời gian đo bao gồm cả thời gian phân tích tệp nguồn và thời gian xử lý tất cả các tệp đầu vào. Mã nhanh nhất sẽ thắng.

Vectơ kiểm tra sẽ là một tập hợp các tệp Ascii được thiết kế để kiểm tra các trường hợp sắp xếp cạnh, bao gồm

  • Một danh sách đã được sắp xếp: "đã đặt hàng"

    &#33;"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
    
  • Một danh sách được sắp xếp ngược: "đảo ngược"

    ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!
    
  • Một tệp bao gồm nhiều bản sao của một vài giá trị duy nhất: "onlynine"

    ibbkninbkrauickabcufrfckbfikfbbakninfaafafbikuccbariauaibiraacbfkfnbbibknkbfankbbunfruarrnrrrbrniaanfbruiicbuiniakuuiubbknanncbuanbcbcfifuiffbcbckikkfcufkkbbakankffikkkbnfnbncbacbfnaauurfrncuckkrfnufkribnfbcfbkbcrkriukncfrcnuirccbbcuaaifiannarcrnfrbarbiuk
    
  • Một tệp ascii hoàn toàn ngẫu nhiên: "ngẫu nhiên"

    '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
    
  • Một tệp ngẫu nhiên trong phạm vi 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¦Ó 
    

Mỗi tệp đầu vào có tối đa 255 byte.

Đây là thông dịch viên. Nó được viết cho Windows ở chế độ bảng điều khiển, nhưng phải dễ dàng chuyển sang: chỉ cần thay thế read_time()sysTime_to_ms()bằng các tương đương dành riêng cho nền tảng.
Sử dụng: 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));
}

Kết quả cho đến nay

Đây là thời gian trung bình của 5 lần chạy của bộ vectơ hoàn chỉnh:

 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)

Phạm vi của các yếu tố đầu vào là gì?
Keith Randall

Đây là phạm vi của các ô, ngoại trừ 0: 1-255.
HỎI

bạn nên trả lại tiền cho tôi, tôi đã làm nó nhanh hơn một chút.
Keith Randall

Nó dường như nhanh hơn gấp 2 lần so với lần gần đây nhất của tôi - Tôi sẽ thực hiện thời gian chính thức khi tôi quay lại máy tôi đã sử dụng cho những người khác.
HỎI

Câu trả lời:


9

Đây là một loại nhanh hơn ít nhất 6 lần so với quicksort của tôi. Đó là một thuật toán ít có ý nghĩa trong ngôn ngữ truyền thống, vì nó là O (N * m) trong đó m là giá trị đầu vào tối đa. Sau khi thu thập đầu vào, nó đi qua mảng, đếm các ô> 0 và sau đó giảm dần từng ô. Sau đó, nó thêm 1 vào các countô đầu tiên trong vector kết quả. Nó lặp lại các đường chuyền cho đến khi số đếm bằng 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 
<[<<]>>[.>>]

Thuật toán tương đương 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]);

Đây là một trong đó nhanh gấp 2 lần. Nó dựa một cách lỏng lẻo vào "spaghetti sort" : nó đặt một chuỗi 1 giây miễn là mỗi đầu vào. Giá trị trong mỗi ô biểu thị số lượng sợi ít nhất là dài. (Vì vậy, [3,2,1,2] trở thành |4|0|3|0|1|0|0|). Sau đó, nó bắt đầu 'đo' các sợi và in ra độ dài mỗi khi nó tìm thấy kết thúc của một sợi.

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

Nguyên:

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

Đừng gõ sắp xếp đếm! Đó là loại yêu thích của tôi, do một chiến thắng lớn tôi đã nhận được từ nó một lần: nếu m được biết là nhỏ, bạn có thể nhận được sự tăng tốc lớn qua các thuật toán "nhanh". Tương tự, sắp xếp bong bóng đánh bại quicksort trên dữ liệu được sắp xếp chủ yếu. Không ai thuật toán ___ là tốt nhất cho mọi bối cảnh.
gian hàng

Tôi không nghĩ rằng đây chính xác là một loại đếm. Nhận xét của bạn buộc tôi phải làm một số nghiên cứu thêm. Tôi nghĩ rằng nó giống như một loại hạt . Nhưng tôi thậm chí không chắc điều đó đúng.
HỎI

Không, bạn đúng. Đây là một loại lạ. Có thể hữu ích cho một số ứng dụng liên quan đến danh sách các danh sách được liên kết ... nhưng tôi thậm chí còn nghi ngờ điều đó.
gian hàng

4
Sự tương đồng về mặt vật lý là bạn có N ngăn xếp các đồng tiền có kích cỡ khác nhau. Đặt không gian cho một ngăn xếp N khác. Bạn lấy một đồng xu ra khỏi đầu mỗi ngăn xếp có các đồng xu, sau đó thêm 1 vào mỗi ngăn trong bộ mới từ phải sang trái cho đến khi tay bạn trống. Lặp lại cho đến khi tất cả các ngăn xếp ban đầu là trống rỗng. Bây giờ bộ mới được sắp xếp tăng dần từ trái sang phải.
HỎI

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

Tôi không nhớ ý tưởng thuật toán này là của ai. Có lẽ Bertram Felgenhauer? Nó đến từ các cuộc thảo luận xung quanh cuộc thi Brainfuck Golf # 2, hơn một thập kỷ trước.

Đây là cái nhanh nhất trên đầu vào mẫu.

Nó cũng không giới hạn ở các đầu vào có độ dài <256, nhưng có thể xử lý các đầu vào dài tùy ý.

Cả hai điều này cũng đúng với câu trả lời của Albert, bên dưới. Điều hay ho ở cái này là thời gian chạy là O (N) trong độ dài đầu vào. Vâng, điều này thực sự chạy trong thời gian tuyến tính. Nó đã ăn một yếu tố không đổi 255 như một món ăn nhẹ.


3

Một cách thực hiện sắp xếp đếm đơn giản. Mỗi nhóm có 3 ô rộng, chứa đầu vào hiện tại, một điểm đánh dấu và đếm số lần bộ đếm xuất hiện trong đầu vào.

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

không có ý kiến:

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


2
>>+>,[>+>,]<[[<-<]>+>+[>]>[[-<<[[>>+<<-]<]>>]>-.+[>]>]<<]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.