Tri rapide de crêpes

Contrairement aux problèmes classiques de tri, l'opération coûteuse à économiser n'est pas la comparaison des valeurs, mais le retournement des crêpes. Dans cet exercice, nous allons explorer un autre algorithme permettant de réduire le nombre de retournements nécessaires pour trier la pile. Fait amusant, cet algorithme a été proposé pour la première fois par Bill Gates, avant qu'il n'invente Windows.

L'idée de base est de faire grandir des séquences de crêpes triées, pas forcément en commençant du bas de la pile. On dira qu'un ensemble de crêpes dans l'ordre constitue un block tandis qu'une crêpe qui n'est pas dans un bloc est dite libre. L'algorithme considère la crêpe tout en haut de la pile, dont la taille est notée t, et cherche les deux crêpes de taille t-1 et t+1 (le voisin ainsi considéré est noté t+o). Huit cas sont possibles alors :

Chaque itération augmente la taille des blocs, donc la terminaison de l'algorithme est certaine. Une analyse plus fine montre qu'il prend au plus (5n+5)/3 étapes pour trier la pile. C'est mieux que l'algorithme naïf, qui nécessite 2n-3 étapes pour cela.

À vous de jouer

Vous avez maintenant quasi assez d'informations pour implémenter cet algorithme par vous-même. Il faut juste lever les dernières ambiguïtés pour que vous implémentiez exactement le même algorithme que la correction. Si plusieurs cas s'appliquent à la situation courante, appliquez le premier. Par exemple, si les cas a et b s'appliquent (avec t-1 pour le cas a et t+1 pour le cas b), vous devez appliquer les instructions du cas a. Si un cas donné s'applique à la fois pour t+1 et t-1, appliquez le pour t+1.

Cet exercice est plus difficile que ceux que nous avons fait jusque là, et il ne serait pas choquant que vous ayez besoin d'un peu plus de temps que les autres pour le résoudre. Mais n'abandonnez pas, vous pouvez le faire !

Commencez par écrire des fonctions d'aide, comme estLibre() ou estPremier(). Cela simplifiera l'écriture de votre algorithme, qui peut être écrit sous une forme très similaire à l'énoncé si vous faites les bonnes fonctions d'aide. Factoriser ainsi votre code aide très souvent à améliorer la lisibilité du code.

Pour débugger un monde après l'autre, il est préférable d'éviter que les affichages de tous les mondes se mélangent. Le plus simple pour cela est d'utiliser la méthode isSelected() qui ne renvoi vrai que si le monde courant est celui sélectionné dans l'interface. Cela aidera à réduire la complexité en résolvant les problèmes les uns après les autres.
En particulier, afficher l'état du monde sous forme textuelle à chaque fois que vous rentrez dans la boucle principale peut aider.