brainfuck (178 byte)
Anche se brainfuck è ingombrante, aiuta a lavorare con il grano della lingua. Chiediti "Devo memorizzare questo valore esplicitamente in una cella?" Spesso puoi ottenere velocità e concisione facendo qualcosa di più sottile. E quando il valore è un indice di array (o un numero naturale arbitrario), potrebbe non rientrare in una cella. Naturalmente, potresti semplicemente accettarlo come limite del tuo programma. Ma progettare il tuo programma per gestire valori elevati spesso lo renderà migliore in altri modi.
Come al solito, la mia prima versione funzionante era il doppio del tempo necessario: 392 byte. Numerose modifiche e due o tre importanti riscritture hanno prodotto questa versione relativamente graziosa da 178 byte. (Anche se in modo divertente un ordinamento a tempo lineare è di soli 40 byte.)
>+>>>>>,[>+>>,]>+[--[+<<<-]<[[<+>-]<[<[->[<<<+>>>>+<-]<<[>>+>[->]<<[<]
<-]>]>>>+<[[-]<[>+<-]<]>[[>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]<<[<<<]>[>>[>>
>]<+<<[<<<]>-]]+<<<]]+[->>>]>>]>[brainfuck.org>>>]
I valori di input sono distanziati ogni tre celle: per ogni cella (V) alue, c'è una cella (L) abel (utilizzata per la navigazione) e un'altra cella per (S) spazio di compressione. Il layout generale dell'array è
0 1 0 0 0 SVLSVL ... SVL 0 0 0 0 0 0 ...
Inizialmente tutte le celle L sono impostate su 1, per contrassegnare le parti dell'array che devono ancora essere ordinate. Quando abbiamo finito di partizionare un subarray, lo dividiamo in subarray più piccoli impostando la cella L del suo perno su 0, quindi individuiamo la cella L più a destra che è ancora 1 e partizioniamo quel subarray successivo. Stranamente, questa è tutta la contabilità di cui abbiamo bisogno per gestire correttamente l'elaborazione ricorsiva dei subarrays. Quando tutte le celle L sono state azzerate, l'intero array viene ordinato.
Per partizionare un subarray, estraiamo il suo valore più a destra in una cella S per agire come perno e portiamo a sinistra (e la corrispondente cella V vuota), confrontandolo con l'altro valore nel subarray e scambiandolo secondo necessità. Alla fine il pivot viene ricambiato, usando lo stesso codice di swap (che consente di risparmiare circa 50 byte). Durante il partizionamento, due celle L aggiuntive vengono mantenute impostate su 0, per contrassegnare le due celle che potrebbero dover essere scambiate tra loro; alla fine del partizionamento, lo 0 sinistro si fonderà con lo 0 a sinistra del subarray e lo 0 destro finirà per contrassegnare il suo perno. Questo processo lascia anche un ulteriore 1 nella cella L a destra del subarray; il ciclo principale inizia e termina in questa cella.
>+>>>>>,[>+>>,]>+[ 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