brainfuck (178 bytes)
Incluso si el brainfuck es engorroso, ayuda a trabajar con el grano del lenguaje. Pregúntese "¿Tengo que almacenar este valor explícitamente en una celda?" A menudo puedes ganar velocidad y concisión haciendo algo más sutil. Y cuando el valor es un índice de matriz (o un número natural arbitrario), es posible que no quepa en una celda. Por supuesto, podría aceptar eso como un límite de su programa. Pero diseñar su programa para manejar valores grandes a menudo lo mejorará de otras maneras.
Como de costumbre, mi primera versión de trabajo fue el doble de lo necesario: 392 bytes. Numerosas modificaciones y dos o tres reescrituras importantes produjeron esta versión comparativamente elegante de 178 bytes. (Aunque de forma divertida, una ordenación de tiempo lineal es de solo 40 bytes).
>+>>>>>,[>+>>,]>+[--[+<<<-]<[[<+>-]<[<[->[<<<+>>>>+<-]<<[>>+>[->]<<[<]
<-]>]>>>+<[[-]<[>+<-]<]>[[>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]<<[<<<]>[>>[>>
>]<+<<[<<<]>-]]+<<<]]+[->>>]>>]>[brainfuck.org>>>]
Los valores de entrada están espaciados cada tres celdas: por cada celda de alor (V), hay una celda (L) abel (utilizada para la navegación) y una celda más para el espacio de bloqueo (S). El diseño general de la matriz es
0 1 0 0 0 SVLSVL ... SVL 0 0 0 0 0 0 ...
Inicialmente, todas las celdas L se configuran en 1, para marcar partes de la matriz que aún necesitan ser ordenadas. Cuando hayamos terminado de particionar un subconjunto, lo dividimos en subconjuntos más pequeños al establecer la celda L de su pivote en 0, luego ubicamos la celda L más a la derecha que todavía es 1 y luego dividimos esa subarregla. Curiosamente, esta es toda la contabilidad que necesitamos para manejar adecuadamente el procesamiento recursivo de las submatrices. Cuando todas las celdas L se han puesto a cero, se ordena toda la matriz.
Para dividir un subconjunto, extraemos su valor más a la derecha en una celda S para que actúe como pivote, y lo llevamos (y la correspondiente celda V vacía) a la izquierda, comparándolo con el valor del otro en el subconjunto e intercambiando según sea necesario. Al final, el pivote se intercambia nuevamente, utilizando el mismo código de intercambio (que ahorra 50 bytes más o menos). Durante la partición, dos celdas L adicionales se mantienen establecidas en 0, para marcar las dos celdas que pueden necesitar intercambiarse entre sí; al final de la partición, el 0 izquierdo se fusionará con el 0 a la izquierda del subconjunto, y el 0 derecho terminará marcando su pivote. Este proceso también deja un 1 extra en la celda L a la derecha de la submatriz; El bucle principal comienza y termina en esta celda.
>+>>>>>,[>+>>,]>+[ 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