Ce projet consiste à trier une pile A par ordre croissant avec deux piles avec un nombre limité d'opérations disponibles. Les seules opérations possibles sont les suivantes :
- sa (swap a) : échanger les 2 premiers éléments en haut de la pile a. Ne rien faire s'il n'y a qu'un seul élément ou aucun élément.
- sb (swap b) : échanger les 2 premiers éléments en haut de la pile b. Ne rien faire s'il n'y a qu'un seul élément ou aucun élément.
- ss : sa et sb en même temps.
- pa (push a) : prendre le premier élément en haut de b et le mettre en haut de a. Ne rien faire si b est vide.
- pb (push b) : prendre le premier élément en haut de a et le mettre en haut de b. Ne rien faire si a est vide.
- ra (rotate a) : décaler tous les éléments de la pile a de 1 vers le haut. Le premier élément devient le dernier.
- rb (rotation b) : Décaler vers le haut tous les éléments de la pile b de 1. Le premier élément devient le dernier.
- rr : ra et rb en même temps.
- rra (rotation inverse a) : Décaler vers le bas tous les éléments de la pile a de 1. Le dernier élément devient le premier.
- rrb (rotation inverse b) : Décaler vers le bas tous les éléments de la pile b de 1. Le dernier élément devient le premier.
- rrr : rra et rrb en même temps.
Voici le sujet
Clone le projet.
git clone https://github.com/ugozchi/42_Push_Swap.git
cd 42_Push_Swap
Ici, vous pouvez utiliser les options classiques d'un Makefile (options ci-dessous) mais aussi l'option bonus qui vous permettra d'ajouter vos fonctions bonus dans votre fichier archive libft.a si vous les avez fait.
Toute cette partie correspond à ce que l'on doit rendre pour ce faire corriger.
| Option | Description |
|---|---|
make |
Créer un fichier archive libftpritnf.a avec tous les fichiers |
make clean |
Supprime le dossier contenant les fichiers objets .o |
make fclean |
Execute clean puis supprime le fichier archive .a |
make re |
Execute fclean puis make |
La première étape se déroule dans la fonction main :
- Vérification des arguments
- Si le programme est exécuté sans arguments
(ac == 1), ou si un seul argument vide est passé(ac == 2 && !av[1][0]), le programme appelle immédiatementexit(EXIT_FAILURE)et se termine. -Si un seul argument est passé, il est supposé être une chaîne contenant plusieurs nombres séparés par des espaces (exemple :"1 2 3 4"). Dans ce cas, le programme utiliseft_splitpour diviser cette chaîne en plusieurs sous-chaînes représentant chaque nombre individuel.
- Si le programme est exécuté sans arguments
- Conversion des arguments en liste chaînée
- Après avoir divisé les arguments ou après avoir reçu plusieurs arguments directement, le programme les convertit en une pile chaînée (
t_list). Chaque nombre est vérifié pour s'assurer qu'il est bien un entier valide et qu'il ne dépasse pas les limites d'unint(aveccheck_intetft_atoi). - Ensuite, le programme vérifie s'il y a des doublons dans les arguments à l'aide de la fonction
check_double.
- Après avoir divisé les arguments ou après avoir reçu plusieurs arguments directement, le programme les convertit en une pile chaînée (
- Vérification si la pile est déjà triée
- Une fois la pile construite, avant de lancer les algorithmes de tri, le programme appelle
is_sortpour voir si la pile est déjà dans l'ordre croissant. - Si la pile est déjà triée, le programme libère la mémoire et termine l'exécution immédiatement, car aucune autre action n'est nécessaire.
- Une fois la pile construite, avant de lancer les algorithmes de tri, le programme appelle
- Allocation de la structure
t_data- Une fois que le programme est prêt à trier, il alloue une structure
t_data. Cette structure stockera des informations critiques pour le tri, notamment :med: La médiane de la pile (utilisée comme pivot pour le tri rapide).best: Le coût minimal de déplacement des éléments lors du tri par insertion.- D'autres champs pour les coûts et mouvements nécessaires lors de l'insertion des éléments.
- Une fois que le programme est prêt à trier, il alloue une structure
Le tri rapide (quick sort) est un algorithme divisé en deux grandes étapes : I) Séparation des éléments par rapport à un pivot. II) Réarrangement récursif de chaque sous-ensemble.
- Calcul de la médiane comme pivot
- Avant de trier, le programme détermine un pivot en calculant la médiane des valeurs présentes dans la pile
a. Processus :- La pile
aest convertie en un tableau viaget_tab. - Le tableau est trié avec l'algorithme du tri à bulles dans
bubble_sort. Bien que simple, cet algorithme n'est efficace que pour de petits ensembles de données, ce qui est suffisant ici, car il est utilisé uniquement pour déterminer le pivot. - La médiane (élément central du tableau trié) est choisie comme pivot.
- La pile
- Avant de trier, le programme détermine un pivot en calculant la médiane des valeurs présentes dans la pile
- Poussée des éléments dans la pile
b- Une fois la médiane calculée, le programme parcourt la pile
aet déplace les éléments inférieurs à la médiane dans la pileben utilisant la fonctionft_pb. Cas possibles :- Si l'élément en tête de la pile
aest inférieur au pivot (médiane), il est poussé dans la pileb. - Si l'élément est supérieur ou égal au pivot, il est déplacé en bas de la pile
aavec une rotation vers le haut (ft_ra). - Si
is_sortretourne vrai, c'est-à-dire que la pileaest déjà triée après un certain nombre de rotations, ou si tous les éléments inférieurs au pivot ont été poussés dansb, la boucle est interrompue.
- Si l'élément en tête de la pile
- Une fois la médiane calculée, le programme parcourt la pile
- Tri récursif
- Après avoir poussé les éléments de
aversb, le programme appelle récursivement quick_sort sur les sous-piles restantes pour continuer le processus de tri. - Cas de base : Si la taille de
atombe à 3 éléments ou moins, la fonctionsmall_sortest appelée pour trier directement cette petite pile. Ce cas est géré séparément car il ne nécessite que quelques mouvements simples (rotations et échanges).
- Après avoir poussé les éléments de
Une fois que les éléments inférieurs au pivot ont été poussés dans b, le programme commence à réinsérer ces éléments dans a en les triant :
- Insertion des éléments de
bdansa- Le programme parcourt la pile
bet tente de réinsérer les éléments dansatout en conservant l'ordre croissant dea. Cas possibles :- La fonction
can_pushvérifie si l'élément en tête debpeut être poussé en tête deaen respectant l'ordre croissant. Si c'est le cas, l'élément est poussé dansaviaft_pa. - Si l'insertion directe n'est pas possible, le programme doit calculer le meilleur mouvement à effectuer pour repositionner les éléments. Les fonctions suivantes sont utilisées :
count_move: Calcule le nombre de mouvements nécessaires pour chaque élément deben tenant compte de sa position dansa.cost_move: Ajuste les coûts en fonction de la taille des piles et des rotations nécessaires.best_move: Sélectionne le mouvement le plus optimal en minimisant le coût total de déplacement.
- Une fois le meilleur mouvement déterminé,
do_movest appelé pour exécuter ce mouvement (rotations, échanges, ou insertion).
- La fonction
- Le programme parcourt la pile
- Rotation finale pour trier
a- Après avoir réinséré tous les éléments de
bdansa, la fonctionend_rotvérifie siaest correctement triée.- Si nécessaire, des rotations supplémentaires sont effectuées pour terminer le tri.
- Si
best_rotindique qu'une rotation vers le haut est préférable, des rotationsft_rasont effectuées. Sinon, des rotations inverses (ft_rra) sont utilisées.
- Après avoir réinséré tous les éléments de
Le programme utilise plusieurs types de mouvements pour réorganiser les piles :
- Rotations simultanées :
ft_rr: Effectue une rotation simultanée vers le haut des pilesaetb.ft_rrr: Effectue une rotation simultanée inverse des pilesaetb.
- Rotations individuelles :
ft_raetft_rra: Rotation vers le haut et rotation inverse pour la pilea.ft_rbetft_rrb: Rotation vers le haut et rotation inverse pour la pileb.
- Si la pile contient 3 éléments ou moins
- Quand
quick_sortdétecte que la taille deaest de 3 éléments ou moins,small_sortest utilisée pour trier cette pile. Cette fonction utilise des rotations et des échanges simples pour trier efficacement une petite pile.
- Quand
- Si la pile est déjà triée
- À chaque étape du tri, le programme vérifie si la pile est déjà triée en utilisant
is_sort. Cela permet d'arrêter le tri plus tôt si la pile est déjà dans l'ordre correct, optimisant ainsi les performances.
- À chaque étape du tri, le programme vérifie si la pile est déjà triée en utilisant
À la fin du processus de tri, le programme libère toutes les ressources allouées :
- Les piles a et b sont libérées via free_list, qui parcourt chaque élément de la pile et libère la mémoire associée.
- La structure t_data est également libérée.
On peut visualiser comment marche l'algorithle grâce à o-reo et son Push_swap visualizer
On peut aussi le tester grâce à complexity. Ce programme va tester l'algorithme autant de fois que 'lon le souhaite avec des données différentes.
Ici on demande 500 itérations de 100 nombres différents avec un objectif de tri en moins de 700 coups (pour avoir tous les points)
Ici on demande 100 itérations de 500 nombres différents avec un objectif de tri en moins de 5500 coups (pour avoir tous les points)
Dans les deux cas notre algorithme passe 100% des tests. Victoire !!!
![]() |
| Correcteur 1 | ![]() |
| Correcteur 2 | ![]() |
| Correcteur 3 | ![]() |







