Brainfuck (178 Bytes)
Auch wenn Brainfuck umständlich ist, hilft es, mit der Körnung der Sprache zu arbeiten. Fragen Sie sich: "Muss ich diesen Wert explizit in einer Zelle speichern?" Sie können häufig an Geschwindigkeit und Präzision gewinnen, indem Sie etwas Feinsinnigeres tun. Und wenn der Wert ein Arrayindex (oder eine beliebige natürliche Zahl) ist, passt er möglicherweise nicht in eine Zelle. Natürlich können Sie dies als Grenze Ihres Programms akzeptieren. Das Entwerfen Ihres Programms für den Umgang mit großen Werten verbessert es jedoch häufig auf andere Weise.
Wie üblich war meine erste Arbeitsversion doppelt so lang wie nötig - 392 Bytes. Zahlreiche Modifikationen und zwei oder drei größere Änderungen führten zu dieser vergleichsweise eleganten 178-Byte-Version. (Obwohl eine lineare Zeitsortierung amüsanterweise nur 40 Bytes umfasst.)
>+>>>>>,[>+>>,]>+[--[+<<<-]<[[<+>-]<[<[->[<<<+>>>>+<-]<<[>>+>[->]<<[<]
<-]>]>>>+<[[-]<[>+<-]<]>[[>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]<<[<<<]>[>>[>>
>]<+<<[<<<]>-]]+<<<]]+[->>>]>>]>[brainfuck.org>>>]
Die Eingabewerte sind in Abständen von jeweils drei Zellen angeordnet: Für jede (V) Wertezelle gibt es eine (L) Wertezelle (für die Navigation) und eine weitere Zelle für den (S) Cratch-Raum. Das Gesamtlayout des Arrays ist
0 1 0 0 0 SVLSVL ... SVL 0 0 0 0 0 0 ...
Zu Beginn werden alle L-Zellen auf 1 gesetzt, um Teile des Arrays zu markieren, die noch sortiert werden müssen. Wenn wir mit dem Partitionieren eines Subarrays fertig sind, teilen wir es in kleinere Subarrays auf, indem wir die L-Zelle des Pivots auf 0 setzen, dann die am weitesten rechts liegende L-Zelle ausfindig machen, die noch 1 ist, und das Subarray als nächstes partitionieren. Seltsamerweise ist dies die gesamte Buchhaltung, die wir benötigen, um die rekursive Verarbeitung von Subarrays ordnungsgemäß zu handhaben. Wenn alle L-Zellen auf Null gesetzt wurden, wird das gesamte Array sortiert.
Um ein Subarray zu partitionieren, ziehen wir seinen äußersten rechten Wert in eine S-Zelle, um als Drehpunkt zu fungieren, und bringen ihn (und die entsprechende leere V-Zelle) nach links, vergleichen ihn mit dem Wert im Subarray und tauschen ihn nach Bedarf aus. Am Ende wird der Pivot mit demselben Swap-Code (der ungefähr 50 Bytes spart) wieder eingelagert. Während der Partitionierung werden zwei zusätzliche L-Zellen auf 0 gesetzt, um die zwei Zellen zu markieren, die möglicherweise gegeneinander ausgetauscht werden müssen. Am Ende der Partitionierung verschmilzt die linke 0 mit der 0 links vom Subarray und die rechte 0 markiert den Drehpunkt. Bei diesem Vorgang verbleibt außerdem eine zusätzliche 1 in der L-Zelle rechts neben dem Subarray. Die Hauptschleife beginnt und endet an dieser Zelle.
>+>>>>>,[>+>>,]>+[ 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