title: Info
Ce document explique la traversée **post-order** d'un arbre binaire, une méthode où chaque nœud est traité **après** ses sous-arbres. La traversée suit l'ordre **gauche → droite → racine**, ce qui est particulièrement utile pour des opérations nécessitant un traitement des enfants avant leur parent, comme la suppression ou l'évaluation d'arbres d'expression.
🏆 Contexte et Objectif
La traversée post-order est utilisée pour explorer et traiter un arbre binaire dans l’ordre où chaque sous-arbre est traité avant la racine. Elle est utile pour :
- Évaluer des expressions mathématiques dans un arbre d’expression.
- Supprimer ou libérer un arbre récursivement.
- Résoudre des problèmes nécessitant un traitement bottom-up (de bas en haut).
🎨 Représentation Visuelle
Prenons l’arbre suivant :
8
/ \
3 10
/ \
1 6
Étapes de la traversée post-order :
- Traverser récursivement le sous-arbre gauche.
- Traverser récursivement le sous-arbre droit.
- Visiter la racine.
Résultat attendu :
1, 6, 3, 10, 8
💻 Code Complet Ultra-Commenté
Fichier suggéré : 18-binary-tree-postorder.c
#include <stdlib.h> // malloc, free
#include <stdio.h> // printf, perror
// Définition d’un nœud pour l'arbre binaire
typedef struct s_btree
{
int data; // Donnée du nœud
struct s_btree *left; // Pointeur vers l'enfant gauche
struct s_btree *right; // Pointeur vers l'enfant droit
} t_btree;
// Fonction pour créer un nouveau nœud
t_btree *create_node(int data)
{
t_btree *node = malloc(sizeof(t_btree));
if (!node)
{
perror("Erreur d’allocation mémoire pour le nœud");
exit(EXIT_FAILURE);
}
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// Fonction pour insérer une valeur dans un arbre binaire de recherche
t_btree *insert_node(t_btree *root, int data)
{
if (root == NULL)
return create_node(data);
if (data < root->data)
root->left = insert_node(root->left, data);
else if (data > root->data)
root->right = insert_node(root->right, data);
return root;
}
// Fonction de traversée post-order (gauche → droite → racine)
void postorder_traversal(t_btree *root)
{
if (root == NULL)
return;
postorder_traversal(root->left); // Traversée du sous-arbre gauche
postorder_traversal(root->right); // Traversée du sous-arbre droit
printf("%d ", root->data); // Traiter la racine
}
// Fonction pour libérer la mémoire de l’arbre
void free_tree(t_btree *root)
{
if (root == NULL)
return;
free_tree(root->left);
free_tree(root->right);
free(root);
}
// Fonction main pour démonstration
int main(void)
{
t_btree *root = NULL;
// Insertion des valeurs dans l'arbre
root = insert_node(root, 8);
root = insert_node(root, 3);
root = insert_node(root, 10);
root = insert_node(root, 1);
root = insert_node(root, 6);
// Traversée post-order de l'arbre
printf("Arbre binaire (traversée post-order) : ");
postorder_traversal(root);
printf("\n");
// Libération de la mémoire
free_tree(root);
return 0;
}
🔎 Analyse Ligne par Ligne et Concepts Clés
1. Fonction postorder_traversal
void postorder_traversal(t_btree *root)
{
if (root == NULL)
return;
postorder_traversal(root->left); // Traversée du sous-arbre gauche
postorder_traversal(root->right); // Traversée du sous-arbre droit
printf("%d ", root->data); // Traiter la racine
}
- Base Case: Si
root == NULL
, on ne fait rien (fin de la branche). - Recursive Traversal:
- Sous-arbre gauche: Explore tous les enfants du côté gauche.
- Sous-arbre droit: Explore tous les enfants du côté droit.
- Racine: Traite le nœud courant après avoir exploré ses enfants.
2. Fonction main
- Construction de l’arbre: Les valeurs
{8, 3, 10, 1, 6}
sont insérées en respectant les règles du BST. - Traversée et Affichage: La fonction
postorder_traversal
parcourt l’arbre en suivant l’ordre gauche → droite → racine.
🧭 Complexité
Opération | Complexité | Explication |
---|---|---|
Traversée post-order | O(n) | Chaque nœud est visité une seule fois. |
Construction de l’arbre | O(h) pour chaque insertion | h est la hauteur de l’arbre. |
- Cas optimal (arbre équilibré): La hauteur
h
est logarithmique (h = log(n)
), donc l’insertion est efficace. - Cas dégénéré (arbre déséquilibré): Si l’arbre devient une liste chaînée (
h = n
), l’insertion et la traversée deviennent linéaires.
🧠 Bonnes Pratiques et Conseils
-
Cas Limites :
- Si l’arbre est vide (
root == NULL
), la traversée ne produit aucune sortie. - Toujours vérifier si
malloc
réussit lors de la création de nœuds.
- Si l’arbre est vide (
-
Extensibilité :
- Ajouter d’autres traversées (in-order, pre-order, level-order) pour répondre à différents besoins.
-
Applications Pratiques :
- Évaluation d’arbres d’expression pour résoudre des équations.
- Suppression d’un arbre entier, car chaque nœud est visité après ses enfants.
✨ Conclusion
La traversée post-order est essentielle pour des tâches nécessitant un traitement des enfants avant leur parent, comme la libération de mémoire ou l’évaluation d’expressions. Son implémentation récursive est simple et respecte les conventions de la 42 School, tout en offrant une base robuste pour des manipulations avancées des arbres binaires.
Bravo, vous avez maîtrisé la traversée post-order ! 🌳