brainfuck (178 octets)
Même si le brainfuck est lourd, cela aide à travailler avec le grain de la langue. Demandez-vous "Dois-je stocker cette valeur explicitement dans une cellule?" Vous pouvez souvent gagner en vitesse et en concision en faisant quelque chose de plus subtil. Et lorsque la valeur est un index de tableau (ou un nombre naturel arbitraire), elle peut ne pas tenir dans une cellule. Bien sûr, vous pouvez simplement accepter cela comme une limite de votre programme. Mais la conception de votre programme pour gérer de grandes valeurs l'améliorera souvent par d'autres moyens.
Comme d'habitude, ma première version de travail était deux fois plus longue que nécessaire - 392 octets. De nombreuses modifications et deux ou trois réécritures majeures ont produit cette version relativement gracieuse de 178 octets. (Bien qu'amusamment, une sorte de temps linéaire n'est que de 40 octets.)
>+>>>>>,[>+>>,]>+[--[+<<<-]<[[<+>-]<[<[->[<<<+>>>>+<-]<<[>>+>[->]<<[<]
<-]>]>>>+<[[-]<[>+<-]<]>[[>>>]+<<<-<[<<[<<<]>>+>[>>>]<-]<<[<<<]>[>>[>>
>]<+<<[<<<]>-]]+<<<]]+[->>>]>>]>[brainfuck.org>>>]
Les valeurs d'entrée sont espacées toutes les trois cellules: pour chaque cellule de valeur (V), il y a une cellule (L) abel (utilisée pour la navigation) et une cellule de plus pour (S) l'espace de capture. La disposition générale du tableau est
0 1 0 0 0 SVLSVL ... SVL 0 0 0 0 0 0 ...
Initialement, toutes les cellules L sont définies sur 1, pour marquer les parties du tableau qui doivent encore être triées. Lorsque nous avons terminé de partitionner un sous-tableau, nous le divisons en sous-réseaux plus petits en définissant la cellule L de son pivot sur 0, puis localisons la cellule L la plus à droite qui est toujours 1 et partitionnons ce sous-tableau suivant. Curieusement, c'est toute la comptabilité dont nous avons besoin pour gérer correctement le traitement récursif des sous-réseaux. Lorsque toutes les cellules L ont été mises à zéro, l'ensemble du tableau est trié.
Pour partitionner un sous-tableau, nous tirons sa valeur la plus à droite dans une cellule S pour agir comme pivot, et l'amener (et la cellule V vide correspondante) à gauche, en le comparant aux autres valeurs du sous-tableau et en échangeant si nécessaire. À la fin, le pivot est de nouveau échangé, en utilisant le même code de swap (ce qui économise environ 50 octets). Pendant le partitionnement, deux cellules L supplémentaires sont maintenues à 0, pour marquer les deux cellules qui peuvent avoir besoin d'être échangées l'une avec l'autre; à la fin du partitionnement, le 0 gauche fusionnera avec le 0 à gauche du sous-tableau, et le 0 droit finira par marquer son pivot. Ce processus laisse également un 1 supplémentaire dans la cellule L à droite du sous-tableau; la boucle principale commence et se termine à cette cellule.
>+>>>>>,[>+>>,]>+[ 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