Arbres binaires et arbres binaire de recherche
Arbre binaire : implémentation¶
Modélisation¶
On rappelle qu'un arbre binaire est constitué d'un ensemble (éventuellement vide) de nœuds. Si l'arbre binaire n'est pas vide, il possède un nœud particulier nommé la racine de l'arbre, munie la plupart du temps d'une étiquette. Les nœuds restants sont alors répartis entre le sous-arbre gauche et le sous-arbre droit.
Nous utiliserons dans ce TP deux classes pour implémenter les objets de type Arbre. La classe Noeud permet de représenter les nœuds de l'arbre. Il est à noter que l'étiquette sera toujours un entier dans ce TP, et que les attributs gauche et droit d'un nœud seront des objets de type ArbreBinaire dans cette partie.
1 2 3 4 5 | |
La seconde classe ArbreBinaire permet de représenter un arbre binaire. Un objet de type ArbreBinaire possède un unique attribut, racine, de type Nœud. On prendra pour convention que lorsque l'attribut racine vaut la valeur spéciale None, cela correspond à l'arbre vide. On remarquera l'utilisation de l'argument optionnel n dans la définition de la fonction __init__. Ainsi, il est possible d'instancier une variable a de type ArbreBinaire de deux manières différentes :
a = ArbreBinaire():a.racinevaut alorsNonea = ArbreBinaire(n), avecnun objet de typeNoeud.a.racineest alorsn.
class Noeud:bksl-nl def py-undpy-undinitpy-undpy-und(self, v, g, d):bksl-nl self.etiquette = vbksl-nl self.gauche = gbksl-nl self.droit = dbksl-nlbksl-nlclass ArbreBinaire:bksl-nl """Représente un arbre binaire"""bksl-nl def py-undpy-undinitpy-undpy-und(self, n = None):bksl-nl """ArbreBinaire, Noeud -> NoneType"""bksl-nl self.racine = nbksl-nlbksl-nl def estpy-undvide(self):bksl-nl """ ArbreBinaire -> bool """bksl-nl return ...bksl-nl bksl-nl def etiquette(self):bksl-nl """ ArbreBinaire -> int """bksl-nl return ...bksl-nl bksl-nl def gauche(self):bksl-nl """ ArbreBinaire -> ArbreBinaire """bksl-nl return ...bksl-nl bksl-nl def droit(self):bksl-nl """ ArbreBinaire -> ArbreBinaire """bksl-nl return ...bksl-nl bksl-nl def estpy-undfeuille(self):bksl-nl """ ArbreBinaire -> bool """bksl-nl return ...bksl-nl bksl-nl def py-undpy-undstrpy-undpy-und(self):bksl-nl """ ArbreBinaire -> str """bksl-nl passbksl-nl bksl-nl def ajouterpy-unddepuispy-undtableau(self, tab):bksl-nl """ ArbreBinaire, [int] -> Nonetypebksl-nl Ajoute à l'arbre binaire self (supposé initiallement vide) les éléments de tab (correspondant à un parcours en largeur de l'arbre) """bksl-nl passbksl-nl bksl-nl def taille(self):bksl-nl """ ArbreBinaire -> intbksl-nl Renvoie le nombre de nœuds dont est composé self """bksl-nl passbksl-nl bksl-nl def appartient(self, e):bksl-nl """ ArbreBinaire, int -> boolbksl-nl Détermine si l'entier e est une étiquette de l'arbre self """bksl-nl passbksl-nl bksl-nl def inserer(self, e):bksl-nl """ ArbreBinaire, intbksl-nl Insère l'entier e dans l'arbre binaire self """bksl-nl passbksl-nlbksl-nl
On donne ci-dessous des exemples d'utilisation des classes Noeud et ArbreBinaire.
1 2 3 4 5 6 7 8 | |
Avec le code donné dans le sujet, il est à noter que :
ArbreBinaire()renvoie un objet de typeArbreBinairedont l'attributracinevautNone: il s'agit d'un arbre binaire vide.- La variable
feuille1est un objet de typeArbreBinaire. Sa racine est un objet de typeNoeud, dont les attributsgaucheetdroitsont des objets de typeArbreBinaire. -
Enfin, la variable
a0correspond à l'arbre binaire ci-dessous :
Méthodes de l'interface¶
Compléter le code python des fonctions de l'interface du type ArbreBinaire, telles que décrites dans le cours.
Remarque. Si \(\mathcal{A}\) est un arbre binaire de racine r, et s1 (resp. s2) la chaîne de caractère représentant le sous-arbre gauche (resp. droit) de \(\mathcal{A}\), alors on représentera \(\mathcal{A}\) à l'aide de la chaîne de caractères :
({s1}) {r.etiquette} ({s2})
L'arbre vide sera représenté par la chaîne de caractère vide.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Méthode ajouter_depuis_tableau¶
On souhaite dans cette question écrire une méthode efficace pour créer un arbre binaire dont on fournit la liste la liste des étiquettes. tab est un tableau dont les éléments sont des entiers ou bien la valeur spéciale None, tel qu'obtenu avec un parcours en largeur de l'arbre binaire souhaité.
À l'aide du tableau tab, l'algorithme (similaire à celui d'un parcours en largeur) pour reconstruire l'arbre binaire self correspondant est le suivant :
- l'arbre binaire initialement présent dans la file est
self. - tant que
tabn'est pas vide :- soit
ale premier arbre de la file ; - soit
elemle premier élément du tableautab.- Si celui-ci n'est pas
None: on affecte à la racine deaunNoeudd'étiquetteelemet dont les deux enfants sont des arbres binaires vides. - Sinon on ne fait rien.
- Si celui-ci n'est pas
elema été ajouté à l'arbre binaire en construction. On supprime doncelemdetab.- on ajoute les enfants gauche et droit de l'arbre
aà la file dans le cas oùan'est pas l'arbre vide.
- soit
1 2 3 4 | |
Méthode taille¶
Écrire une méthode taille de la classe ArbreBinaire qui renvoie le nombre de nœuds dont est constitué l'objet self.
1 2 3 4 | |
Méthode appartient¶
Écrire une méthode appartient de la classe ArbreBinaire qui détermine si l'élément e est une étiquette d'un des nœuds de self.
1 2 3 4 | |
Méthode inserer¶
Écrire une méthode inserer qui insère l'élément e dans l'arbre self de la manière suivante :
- si
selfest vide, alors on affecte à son attributracineun nœud d'étiquettee; - sinon, on insère récursivement
edans le sous-arbre gauche ou droit deselfqui possède le moins d'éléments (on pourra utiliser la méthodetaille).
1 2 3 4 | |
Arbre binaire de recherche¶
Définition¶
On appelle arbre binaire de recherche (ABR) un arbre binaire étiqueté qui vérifie les propriétés suivantes :
- toutes les étiquettes de l'arbre appartiennent au même ensemble, et peuvent être comparées entres elles ;
- le sous-arbre gauche est un arbre binaire de recherche dont toutes les étiquettes sont inférieures ou égales à l'étiquette de la racine ;
- le sous-arbre droit est un arbre binaire de recherche dont toutes les étiquettes sont supérieures ou égales à l'étiquette de la racine.
-
Parmi les arbres suivants, lesquels sont des arbres binaires de recherche ?

-
Citer les arbres binaires de recherche parmi les arbres \(\mathcal{A}_1\), \(\ldots\), \(\mathcal{A}_6\).
Implémentation¶
Un ABR est un arbre, dont les nœuds sont répartis de manière particulière. Ainsi, toutes les propriétés, toutes les méthodes s'appliquant aux arbres binaires s'appliquent également aux ABR. Attention cependant, la réciproque est fausse ! Si tout ABR est un arbre binaire, tout arbre binaire n'est pas un ABR.
Nous verrons que la structure d'ABR permet notamment d'optimiser certaines opérations, notamment la méthode appartient. On souhaite écrire une classe ABR afin de manipuler les arbres binaires de recherche. On pourrait copier/coller la classe ArbreBinaire, mais on aurait alors dupliqué notre code (c'est toujours une mauvaise idée). On utilise plutôt le concept d'héritage.
class ABR(ArbreBinaire):bksl-nl """ Représentation d'ABR (Arbre Binaire de Recherche) """bksl-nlbksl-nl def inserer(self, e):bksl-nl """ ABR, int -> NoneTypebksl-nl Insère l'élément e dans l'ABR self """bksl-nl passbksl-nl bksl-nl def appartient(self, e):bksl-nl """ ABR, int -> Nonetypebksl-nl Détermine si l'élément e est une des étiquettes de l'ABR self """bksl-nl passbksl-nl bksl-nl def minimum(self):bksl-nl """ ABR -> intbksl-nl Renvoie la plus petite étiquette de self """bksl-nl passbksl-nlbksl-nl
On dit avec cette syntaxe que la classe ABR hérite de la classe ArbreBinaire : les objets de type ABR possèdent toutes les méthodes des objets de type ArbreBinaire (en particulier la méthode __init__ : leurs attributs sont donc égalements les mêmes).
Exemple¶
On donne ci-dessous un exemple d'utilisation de la classe ABR.
1 2 3 4 5 6 7 8 9 10 11 12 | |
(() 1 ()) 2 (() 3 ())
3
False
Méthode inserer¶
Écrire la méthode inserer de la classe ABR qui insère l'élément e au bon endroit dans l'ABR self : en particulier, self sera toujours un ABR à l'issue de l'exécution de la méthode inserer.
1 2 3 4 | |
Méthode appartient¶
Écrire une méthode appartient de la classe ABR qui détermine si l'élément e est une étiquettes d'un des nœuds de self. On fera attention à ne réaliser au plus qu'un seul appel récursif.
1 2 3 4 | |
Méthode minimum¶
Écrire une méthode minimum de la classe ABR qui renvoie la plus petite étiquette présent dans self. On fera attention à ne réaliser au plus qu'un seul appel récursif.
1 2 3 4 | |
À propos de l'héritage¶
-
Commenter l'affichage suivant :
1 2 3 4
print(a11.taille) print(a11.ajouter_depuis_tableau) print(a11.appartient) print(a11.minimum)<bound method ArbreBinaire.taille of <__main__.ABR object at 0x7fa7139f9270>> <bound method ArbreBinaire.ajouter_depuis_tableau of <__main__.ABR object at 0x7fa7139f9270>> <bound method ABR.appartient of <__main__.ABR object at 0x7fa7139f9270>> <bound method ABR.minimum of <__main__.ABR object at 0x7fa7139f9270>> -
Commenter l'affichage :
1 2 3 4 5
a12 = ABR() a12.ajouter_depuis_tableau([2, 1, 3]) print(a12) a12.inserer(5) print(a12)(() 1 ()) 2 (() 3 ()) (() 1 ()) 2 ((() 5 ()) 3 ()) -
Proposer une méthode
ajouter_depuis_tableaude la classeABRqui étant donné un ABRselfsupposé vide le rempli avec les éléments detab. À l'issue de l'exécution de cette méthode,selfest toujours un ABR.
Documents¶
- Arbres binaires et arbres binaire de recherche (sujet)
- Fichiers python :