Chapitre 6 : Les arbres binaires.

Introduction :

L'idée des arbres binaires est simple : chaque nœud a au maximum deux enfants, un à gauche et un à droite, ce qui permet d'organiser les données de manière structurée pour faciliter certaines opérations comme la recherche ou le tri.

1. Définition :

A copier dans le cahier.

Un arbre binaire est un arbre dont l'arité est égale à deux.

Une fois ceci fixé, nous pouvons ainsi parler d'enfant gauche et d'enfant droit.

2. Exemple :

Dans l'exemple ci-dessus :

3. Exercice :

A faire dans le cahier.

Dans cet exercice un arbre composé uniquement d'un seul noeud a une hauteur de 1.

On considère cet arbre binaire :

  1. Quelle est sa racine?
  2. Quelle est sa hauteur?
  3. Quelle est sa taille?
  4. Combien a-t-il de feuille?
  5. Qui est l'enfant gauche de l'enfant gauche de l'enfant gauche du parent du parent de Mia?

4. Définition :

Dans un arbre binaire, à partir d'un noeud, on peut considérer son sous-arbre gauche et son sous-arbre droit.

5. Exemple :

6. Arbre localement complet

A copier dans le cahier.

Un arbre est dit localement complet si chaque noeud possède soit 0 soit deux enfants.

7. Exemple :

Cet arbre est localement complet.

8. Arbre complet

A copier dans le cahier.

Un arbre est dit complet s'il est localement complet et que ses noeuds ne comportant pas d'enfant sont au même niveau.

9. Exemple :

Cet arbre est complet.

10. Arbre dégénéré

A copier dans le cahier.

Un arbre est dit dégénéré s'il ne possède qu'une seule feuille.

On peut alors l'associer à une structure linéaire.

11. Exemple :

Cet arbre est dégénéré.

12. Exercice :

A faire dans le cahier.

Représenter l'arbre correspondant au tableau ci-dessous :

Noeud Valeur Enfant gauche Enfant droit
1 René 2 3
2 Lilou 4 \(\emptyset\)
4 Léa \(\emptyset\) \(\emptyset\)
3 Julie \(\emptyset\) 6
6 Chloé 7 8
7 Titou \(\emptyset\) \(\emptyset\)
8 Irène \(\emptyset\) \(\emptyset\)

13. Exercice

A faire dans le cahier.

En prenant exemple sur le tableau de l'exercice précédent, faire un tableau correspondant à l'arbre ci-dessous :

14. Une première implémentation dans Python

A copier dans le cahier.

On peut stocker un arbre binaire dans Python à l'aide de liste de liste :

[racine,[sous_arbre_gauche],[sous_arbre_droit]]

15. Exercice : Une première implémentation dans Python

Insérer dans Python l'arbre suivant à l'aide de liste de liste.

Une feuille aura ce format : [valeur,None,None]

arbre = [..]

Tests :

# Tests

Affichage :

Console:



    
>>>

16. Exercice : Ajout d’une feuille à gauche (récursif)

Écrire une fonction ajout_feuille_gauche(liste_arbre, valeur) qui prend en paramètre un arbre sous forme de liste et une valeur.

Elle fonctionnera de manière récursive ainsi :

  • Si l’enfant gauche de la racine est vide, on place la valeur à cet endroit.
  • Sinon, on exécute cette fonction dans le sous-arbre gauche.

Dans le contexte, un arbre est ici stocké dans des listes de listes (format [etiquette, gauche, droite]). Par exemple :

["Olivier",
 ["Julien", None, None],
 ["Léa", None, None]]
def ajout_feuille_gauche(liste_arbre, valeur): """ Modifie l'arbre en place : - si l'enfant gauche de la racine est vide, on insère [valeur, None, None] - sinon, on applique récursivement au sous-arbre gauche """ if ... is None: liste_arbre[1] = [valeur, None, None] else: ... arbre = ["Olivier", ["Julien", None, None], ["Léa", None, None]] ajout_feuille_gauche(arbre,"Chloé") print(arbre)

Tests :

Affichage :

Console:


    
>>>

17. Algorithmes de la taille, de la hauteur et du nombre de feuilles d'un arbre.

A copier dans le cahier.

Ces trois algorithmes sont des algorithmes récursifs :

18. Exercice : Arbres — taille, hauteur, nombre de feuilles

On représente un arbre binaire par une liste de la forme [etiquette, gauche, droite], où gauche et droite sont soit None, soit des sous-arbres au même format.

Écrire en Python les fonctions suivantes :

  • taille(arbre) : renvoie le nombre total de nœuds de l’arbre.
  • hauteur(arbre) : renvoie la hauteur de l’arbre (un arbre réduit à un seul nœud a une hauteur égale à 1 ; l’arbre vide a une hauteur de 0).
  • nombre_feuille(arbre) : renvoie le nombre de feuilles (nœuds sans enfant) de l’arbre.

Exemple de structure :

["Olivier",
 ["Julien", None, None],
 ["Léa", None, None]]
# Jeux d'arbres pour les tests arbre_vide = None arbre_feuille = ['A', None, None] arbre_simple = ['Olivier', ['Julien', None, None], ['Léa', None, None]] arbre_prof = ['R', ['A', ['B', None, None], None], ['C', ['D', None, None], ['E', None, None]]] def taille(arbre): """Renvoie le nombre total de nœuds de l'arbre.""" if arbre is None: return ... gauche, droite = arbre[1], arbre[2] gauche = arbre[1] droite = arbre[2] return ... def hauteur(arbre): """Renvoie la hauteur de l'arbre (1 pour un nœud seul, 0 si vide).""" if ...: return ... return 1 + max(..., ...) def nombre_feuille(arbre): """Renvoie le nombre de feuilles (nœuds sans enfants).""" if arbre is None: return ... gauche, droite = arbre[1], arbre[2] if ... is None and ... is None: return ... return ... + ...

Tests :

Affichage :

Console:


    
>>>

19. Parcours en profondeur

A copier dans le cahier.

Parcourir l'arbre en profondeur signifie que l'on explore chaque sous-arbre complètement avant de passer à un autre sous-arbre.

On distingue alors trois cas :

20. Exercice

A faire dans le cahier.

On considère l'arbre suivant:

Sur une feuille :

  1. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre préfixe.
  2. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre infixe.
  3. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre postfixe.

21. Algorithmes parcours en profondeur.

A copier dans le cahier.

Ces trois algorithmes sont des algorithmes récursifs :

22. Exercice : Parcours d'arbre — préfixe, infixe, postfixe (afficher & renvoyer)

On représente un arbre binaire par une liste [etiquette, gauche, droite], où gauche et droite sont soit None, soit des sous-arbres au même format.

  1. lecture_prefixe(arbre) : renvoie la liste des valeurs rencontrées en ordre préfixe (racine, gauche, droite).
  2. lecture_infixe(arbre) : renvoie la liste des valeurs en ordre infixe (gauche, racine, droite).
  3. lecture_postfixe(arbre) : renvoie la liste des valeurs en ordre postfixe (gauche, droite, racine).
# Arbres d'exemple # 'A' # / \ # 'B' 'C' # / \ \ # 'D' 'E' 'F' arbre_ex1 = ['A', ['B', ['D', None, None], ['E', None, None]], ['C', None, ['F', None, None]]] arbre_ex2 = ['Z', None, None] arbre_vide = None def lecture_prefixe(arbre): """Affiche les valeurs en ordre préfixe et renvoie la liste correspondante.""" if arbre is None: return [] etiquette, gauche, droite = arbre[0], arbre[1], arbre[2] liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee def lecture_infixe(arbre): """Affiche les valeurs en ordre infixe et renvoie la liste correspondante.""" if ...: return ... etiquette, gauche, droite = arbre[0], arbre[1], arbre[2] liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee def lecture_postfixe(arbre): """Affiche les valeurs en ordre postfixe et renvoie la liste correspondante.""" if ...: return ... etiquette, gauche, droite = arbre[0], arbre[1], arbre[2] liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee #print(lecture_prefixe(arbre_ex1)) #print(lecture_infixe(arbre_ex1)) #print(lecture_postfixe(arbre_ex1))

Tests :

Affichage :

Console:


    
>>>

23. Implementation à l'aide d'une classe :

On peut implémenter un arbre dans Python avec une classe de différentes façons.

Afin de faciliter les différentes corrections, nous utiliserons la même qui est celle-ci:

class ArbreBinaire:
    def __init__(self,valeur):
        self.valeur=valeur
        self.gauche=None
        self.droit=None

    def ajout_gauche(self,valeur):
        self.gauche=ArbreBinaire(valeur)

    def ajout_droit(self,valeur):
        self.droit=ArbreBinaire(valeur)

    def suppr_gauche(self):
        self.gauche=None

    def suppr_droit(self):
        self.droit=None

24. Exercice : Construire l'arbre donné (classe fournie)

Compléter le code pour créer l’instance arbre et tous ses descendants en utilisant ajout_gauche / ajout_droit.

class ArbreBinaire: def __init__(self,valeur): self.valeur=valeur self.gauche=None self.droit=None def ajout_gauche(self,valeur): self.gauche=ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit=ArbreBinaire(valeur) def suppr_gauche(self): self.gauche=None def suppr_droit(self): self.droit=None # ---------------------------- # À compléter : construction de l'arbre demandé # ---------------------------- arbre = ArbreBinaire("Liam") ...

Tests :

Affichage :

Console:


    
>>>

25. Exercice : Taille, hauteur et nombre de feuilles (classe ArbreBinaire)

On représente un arbre binaire avec la classe ArbreBinaire (valeur, gauche, droit). Écrire les fonctions suivantes :

  • taille(arbre) : renvoie le nombre total de nœuds (0 si l’arbre est vide) ;
  • hauteur(arbre) : renvoie la hauteur (0 si vide, 1 si un seul nœud) ;
  • nombre_feuilles(arbre) : renvoie le nombre de feuilles (nœuds sans enfant).
class ArbreBinaire: def __init__(self,valeur): self.valeur=valeur self.gauche=None self.droit=None def ajout_gauche(self,valeur): self.gauche=ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit=ArbreBinaire(valeur) # Arbres d'exemple pour les tests arbre_vide = None feuille = ArbreBinaire('Z') arbre_simple = ArbreBinaire('A') arbre_simple.ajout_gauche('B') arbre_simple.ajout_droit('C') arbre_prof = ArbreBinaire('R') arbre_prof.ajout_gauche('A') arbre_prof.gauche.ajout_gauche('B') arbre_prof.ajout_droit('C') arbre_prof.droit.ajout_gauche('D') arbre_prof.droit.ajout_droit('E') arbre_chaine = ArbreBinaire('X') arbre_chaine.ajout_gauche('Y') arbre_chaine.gauche.ajout_gauche('Z') def taille(arbre): """Renvoie le nombre total de nœuds de l'arbre (0 si vide).""" if arbre is None: return ... return 1 + ... + ... def hauteur(arbre): """Renvoie la hauteur de l'arbre (0 si vide, 1 si un seul nœud).""" if ...: return ... return 1 + max(..., ...) def nombre_feuilles(arbre): """Renvoie le nombre de feuilles (nœuds sans enfant).""" if arbre is None: return ... if ... is None and ... is None: return ... return ... + ...

Tests :

Affichage :

Console:


    
>>>

26. Exercice : Parcours d'arbre — préfixe, infixe, postfixe (classe ArbreBinaire)

On représente un arbre binaire avec la classe ArbreBinaire (valeur, gauche, droit). Écrire des fonctions qui renvoient la liste des valeurs rencontrées :

  1. lecture_prefixe(racine) : ordre préfixe (racine, gauche, droite) ;
  2. lecture_infixe(racine) : ordre infixe (gauche, racine, droite) ;
  3. lecture_postfixe(racine) : ordre postfixe (gauche, droite, racine).
class ArbreBinaire: def __init__(self,valeur): self.valeur=valeur self.gauche=None self.droit=None def ajout_gauche(self,valeur): self.gauche=ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit=ArbreBinaire(valeur) # Arbres d'exemple # 'A' # / \ # 'B' 'C' # / \ \ # 'D' 'E' 'F' arbre_ex1 = ArbreBinaire('A') arbre_ex1.ajout_gauche('B'); arbre_ex1.ajout_droit('C') arbre_ex1.gauche.ajout_gauche('D'); arbre_ex1.gauche.ajout_droit('E') arbre_ex1.droit.ajout_droit('F') arbre_ex2 = ArbreBinaire('Z') arbre_vide = None def lecture_prefixe(arbre): """Renvoie la liste des valeurs en ordre préfixe (racine, gauche, droite).""" if arbre is None: return [] liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee def lecture_infixe(arbre): """Renvoie la liste des valeurs en ordre infixe (gauche, racine, droite).""" if ...: return ... liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee def lecture_postfixe(arbre): """Renvoie la liste des valeurs en ordre postfixe (gauche, droite, racine).""" if ...: return ... liste_retournee = ... liste_retournee = liste_retournee + ... liste_retournee = liste_retournee + ... return liste_retournee

Tests :

Affichage :

Console:


    
>>>

27. Parcours de l'arbre en largeur (aussi appelé "en largeur d'abord") :

Nous avons vu que nous pouvons parcourir un arbre en profondeur. Nous pouvons aussi le parcourir en largeur d'abord.

Il suffit d'évaluer les valeurs de chaque noeud niveau par niveau.

28. Exercice

On considère l'arbre suivant:

Sur une feuille, écrire les valeurs des noeuds rencontrés par un parcours en largeur.

29. Algorithme du parcours en largeur d'un arbre:

A copier dans le cahier.

 fonction parcours_largeur(arbre):
    si arbre vide:
        On ne fait rien
    sinon :    
        on place l'arbre dans une file.
        tant que la file n'est pas vide:
            on sort un element de la file
            on affiche la valeur de la racine
            on place le sous-arbre gauche dans la file s'il n'est pas vide
            on place le sous-arbre droit dans la file s'il n'est pas vide

30. Exercice : Parcours en largeur (classe ArbreBinaire + File)

On représente un arbre binaire avec la classe ArbreBinaire (valeur, gauche, droit).

Écrire une fonction parcours_largeur(arbre) qui renvoie la liste des valeurs rencontrées lors du parcours en largeur de l’arbre (niveau par niveau de gauche à droite).

Pour cela, on utilisera une classe File permettant de gérer une file FIFO avec les méthodes :

  • enfiler(x) : ajoute un élément en fin de file ;
  • defiler() : retire et renvoie le premier élément de la file ;
  • est_vide() : renvoie True si la file est vide.

Exemple :

#         'A'
#        /   \ 
#      'B'   'C'
#     /  \      \
#   'D'  'E'    'F'
# Le parcours en largeur renvoie : ['A', 'B', 'C', 'D', 'E', 'F']
class ArbreBinaire: def __init__(self,valeur): self.valeur=valeur self.gauche=None self.droit=None def ajout_gauche(self,valeur): self.gauche=ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit=ArbreBinaire(valeur) class File: def __init__(self): self.__donnees=[] def enfiler(self,x): self.__donnees.insert(0, x) def defiler(self): return self.__donnees.pop() def est_vide(self): return self.__donnees == [] # Arbre d'exemple arbre_ex1 = ArbreBinaire('A') arbre_ex1.ajout_gauche('B') arbre_ex1.ajout_droit('C') arbre_ex1.gauche.ajout_gauche('D') arbre_ex1.gauche.ajout_droit('E') arbre_ex1.droit.ajout_droit('F') def parcours_largeur(arbre): """Renvoie la liste des valeurs en parcours en largeur (niveau par niveau).""" if arbre is None: return [] file = File() ... resultat = [] while not file.est_vide(): noeud = ... resultat.append(...) if noeud.gauche is not None: ... if noeud.droit is not None: ... return resultat #print(parcours_largeur(arbre_ex1))

Tests :

Affichage :

Console:


    
>>>

31. Calculs à l'aide d'un arbre :

Un arbre permet de stocker un calcul tout en précisant les priorités opératoires à effectuer.

32. Exemple :

On considère l'arbre suivant:

Il permet de stocker le calcul suivant : \( 3 \times 2 + \frac{60}{4+6}\)

33. Exercice :

A faire dans le cahier

On considère l'arbre de l'exemple précédent.

  1. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre préfixe.
  2. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre infixe.
  3. Ecrire les valeurs rencontrées en parcourant l'arbre dans l'ordre postfixe.

34. Ecriture en ligne d'un parcours postfixé ou préfixé d'un arbre contenant une expression mathématique :

Certains langages de programmation ou même de calculatrice utilisent de telles notations pour calculer.

35. Exemples :

36. Exercice : Évaluer une expression dans un arbre binaire

On représente une expression mathématique sous forme d’arbre binaire à l’aide de la classe ArbreBinaire. Chaque nœud contient soit un opérateur (+, -, *, /), soit un entier.

Programmer une fonction Python evaluer qui prend comme paramètre un objet ArbreBinaire contenant une expression mathématique et qui renvoie le résultat numérique.

class ArbreBinaire: def __init__(self,valeur): self.valeur=valeur self.gauche=None self.droit=None def ajout_gauche(self,valeur): self.gauche=ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit=ArbreBinaire(valeur) def suppr_gauche(self): self.gauche=None def suppr_droit(self): self.droit=None # Construction de l'arbre (3*2) + (60 / (4+6)) arbre = ArbreBinaire("+") arbre.ajout_gauche("*") arbre.gauche.ajout_gauche(3) arbre.gauche.ajout_droit(2) arbre.ajout_droit("/") arbre.droit.ajout_gauche(60) arbre.droit.ajout_droit("+") arbre.droit.droit.ajout_gauche(4) arbre.droit.droit.ajout_droit(6) def evaluer(arbre): """Évalue récursivement l'expression représentée par l'arbre binaire.""" if arbre.gauche is None and arbre.droit is None: return ... op = arbre.valeur g = ... d = ... if op == "+": return ... elif op == "-": return ... elif op == "*": return ... elif op == "/": return ... print(evaluer(arbre))

Tests :

Affichage :

Console:


    
>>>

37. Exercice : (sujet 35 - 2025)

Nous avons l’habitude de noter les expressions arithmétiques avec des parenthèses comme par exemple : \((2 + 3) \times 5\).

Il existe une autre notation utilisée par certaines calculatrices, appelée notation postfixe, qui n’utilise pas de parenthèses. L’expression arithmétique précédente est alors obtenue en saisissant successivement 2, puis 3, puis l’opérateur +, puis 5, et enfin l’opérateur *. On modélise cette saisie par le tableau [2, 3, '+', 5, '*'].

Autre exemple, la notation postfixe de \(3 \times 2 + 5\) est modélisée par le tableau :

[3, 2, '*', 5, '+']

D’une manière plus générale, la valeur associée à une expression arithmétique en notation postfixe est déterminée à l’aide d’une pile en parcourant l’expression de gauche à droite :

  • si l’élément parcouru est un nombre, on le place au sommet de la pile,
  • si l’élément parcouru est un opérateur, on récupère les deux éléments situés au sommet de la pile et on leur applique l’opérateur, puis on place le résultat au sommet de la pile,
  • à la fin du parcours, il reste alors un seul élément dans la pile qui est le résultat de l’expression arithmétique.

Dans cet exercice, on se limitera aux opérations * et +.

Complète la fonction eval_expression qui reçoit en paramètre une liste python représentant la notation postfixe d’une expression arithmétique et qui renvoie sa valeur.

⭐ Exemple :

>>> eval_expression([2, 3, '+', 5, '*'])
25
class Pile: def __init__(self): self.__contenu = [] def est_vide(self): return self.__contenu == [] def empiler(self, v): self.__contenu.append(v) def depiler(self): assert not self.est_vide() return self.__contenu.pop() def eval_expression(tab): p = Pile() for ... in tab: if element != '+' ... element != '*': p.empiler(...) else: a = p.depiler() b = p.depiler() if element == ...: resultat = ... + ... else: resultat = ... p.empiler(resultat) return ...

Tests :

Affichage :

Console:



    
>>>

38. Exercice (sujet 30 - 2025)

Une expression arithmétique ne comportant que les quatre opérations \(+\), \(-\), \( \times \) , \( \div \) peut être représentée sous forme d’arbre binaire. Les nœuds internes sont des opérateurs et les feuilles sont des nombres. Dans un tel arbre, la disposition des nœuds joue le rôle des parenthèses que nous connaissons bien.

En parcourant en profondeur infixe l’arbre binaire ci-dessus, on retrouve l’expression notée habituellement :

\((3 \times (8 + 7)) – (2 + 1)\)

La classe Expr ci-après permet d’implémenter une structure d’arbre binaire pour représenter de telles expressions.

Compléter la méthode récursive infixe qui renvoie une chaîne de caractères contenant des parenthèses représentant l’expression arithmétique sur laquelle on l’applique.

class Expr: """Classe implémentant un arbre d'expression.""" def __init__(self, g, v, d): """un objet Expr possède 3 attributs : - gauche : la sous-expression gauche ; - valeur : la valeur de l’étiquette, opérateur ou nombre ; - droite : la sous-expression droite.""" self.gauche = g self.valeur = v self.droite = d def est_une_feuille(self): """renvoie True si et seulement si le noeud est une feuille""" return self.gauche is None and self.droite is None def infixe(self): """renvoie la représentation infixe de l'expression en chaîne de caractères""" s = ... if self.gauche is not None: s = s + '(' + self.gauche.infixe() s = s + ... if self.droite is not None: s = s + ... + ... return s # Exemples de test a = Expr(Expr(None, 1, None), '+', Expr(None, 2, None)) b = Expr(Expr(Expr(None, 1, None), '+', Expr(None, 2, None)), '*', Expr(Expr(None, 3, None), '+', Expr(None, 4, None))) e = Expr( Expr( Expr(None, 3, None), '*', Expr( Expr(None, 8, None), '+', Expr(None, 7, None)) ), '-', Expr( Expr(None, 2, None), '+', Expr(None, 1, None) ) )

Tests :

Affichage :

Console:


    
>>>

39. Exercice : (sujet 47 - 2025)

Un arbre binaire de caractères est stocké sous la forme d’un dictionnaire où les clés sont les caractères des nœuds de l’arbre et les valeurs, pour chaque clé, la liste des caractères des fils gauche et droit du nœud.

Par exemple, l’arbre

est stocké dans

a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'],'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}

Écrire une fonction récursive taille prenant en paramètres un arbre binaire arbre sous la forme d’un dictionnaire et un caractère lettre qui est la valeur du sommet de l’arbre, et qui renvoie la taille de l’arbre, à savoir le nombre total de nœud.

On observe que, par exemple, arbre[lettre][0], respectivement arbre[lettre][1], permet d’atteindre la clé du sous-arbre gauche, respectivement droit, de l’arbre arbre de sommet lettre.

Exemple :

>>> taille(a, 'F')
9
# Dictionnaire de l'exemple officiel a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'],'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']} def taille(arbre, lettre): ...

Tests :

Affichage :

Console:


    
>>>

40. Exercice :

Il est moins usuel mais nous pouvons programmer un parcours préfixé en itératif à l'aide de l'algorithme suivant :

fonction parcours_prefixe_iteratif(arbre):
    créer une pile p
    insérer l'arbre dans la pile 
    tant que la pile p n'est pas vide 
        depiler un element de la pile que l'on nommera element 
        traiter la racine de cet element en l'affichant par exemple
        si le sous-arbre droit n'est pas vide :
            on empile dans p le sous-arbre droit
        si le sous arbre gauche n'est pas vide :
            on empile dans p le sous-arbre gauche

Coder ceci en python à l'aide des classes ArbreBinaire et Pile. On pourra utiliser un arbre des exercices précédents.

class ArbreBinaire: def __init__(self,valeur): self.valeur = valeur self.gauche = None self.droit = None def ajout_gauche(self,valeur): self.gauche = ArbreBinaire(valeur) def ajout_droit(self,valeur): self.droit = ArbreBinaire(valeur) class Pile: def __init__(self): self._d = [] def empiler(self, x): self._d.append(x) def depiler(self): return self._d.pop() def est_vide(self): return self._d == [] def parcours_prefixe_iteratif(arbre): """ Renvoie la liste des valeurs de l'arbre en parcours préfixe (racine, gauche, droite) en utilisant une pile (itératif). """ if arbre is None: return [] p = Pile() p.empiler(arbre) resultat = [] while not p.est_vide(): element = ... resultat.append(...) if element.droit is not None: ... if element.gauche is not None: ... return resultat # Arbre d'exemple (même structure que précédemment) # 'A' # / \ # 'B' 'C' # / \ \ # 'D' 'E' 'F' arbre_ex1 = ArbreBinaire('A') arbre_ex1.ajout_gauche('B'); arbre_ex1.ajout_droit('C') arbre_ex1.gauche.ajout_gauche('D'); arbre_ex1.gauche.ajout_droit('E') arbre_ex1.droit.ajout_droit('F') arbre_vide = None arbre_ex2 = ArbreBinaire('Z') arbre_ex3 = ArbreBinaire('R') arbre_ex3.ajout_gauche('L'); arbre_ex3.ajout_droit('S') arbre_ex3.droit.ajout_gauche('T')

Tests :

Affichage :

Console:


    
>>>

41. Exercice : (sujet 11 - 2025)

Un arbre binaire est soit vide, représenté en Python par la valeur None, soit un nœud représenté par un triplet (g, x, d)x est l’étiquette du nœud et g et d sont les sous-arbres gauche et droit.

On souhaite écrire une fonction parcours_largeur qui prend en paramètre un arbre binaire et qui renvoie la liste des étiquettes des nœuds de l’arbre parcourus en largeur.

Exemples :

>>> arbre = ( ( (None, 1, None), 2, (None, 3, None) ),
...           4,
...           ( (None, 5, None), 6, (None, 7, None) ) )
>>> parcours_largeur(arbre)
[4, 2, 6, 1, 3, 5, 7]
# Exemple officiel arbre = ( ( (None, 1, None), 2, (None, 3, None) ), 4, ( (None, 5, None), 6, (None, 7, None) ) ) def parcours_largeur(a): """Renvoie la liste des étiquettes par parcours en largeur d'un arbre binaire représenté par des triplets (g, x, d) ou None pour l'arbre vide.""" # Autres arbres de test possibles arbre_vide = None arbre_seul = (None, 42, None) arbre_gauche = ((None, 2, None), 1, None) arbre_droit = (None, 1, (None, 3, None))

Tests :

Affichage :

Console:


    
>>>