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.racine
vaut alorsNone
a = ArbreBinaire(n)
, avecn
un objet de typeNoeud
.a.racine
est 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 typeArbreBinaire
dont l'attributracine
vautNone
: il s'agit d'un arbre binaire vide.- La variable
feuille1
est un objet de typeArbreBinaire
. Sa racine est un objet de typeNoeud
, dont les attributsgauche
etdroit
sont des objets de typeArbreBinaire
. -
Enfin, la variable
a0
correspond à 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
tab
n'est pas vide :- soit
a
le premier arbre de la file ; - soit
elem
le premier élément du tableautab
.- Si celui-ci n'est pas
None
: on affecte à la racine dea
unNoeud
d'étiquetteelem
et dont les deux enfants sont des arbres binaires vides. - Sinon on ne fait rien.
- Si celui-ci n'est pas
elem
a été ajouté à l'arbre binaire en construction. On supprime doncelem
detab
.- on ajoute les enfants gauche et droit de l'arbre
a
à la file dans le cas oùa
n'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
self
est vide, alors on affecte à son attributracine
un nœud d'étiquettee
; - sinon, on insère récursivement
e
dans le sous-arbre gauche ou droit deself
qui 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_tableau
de la classeABR
qui étant donné un ABRself
supposé vide le rempli avec les éléments detab
. À l'issue de l'exécution de cette méthode,self
est toujours un ABR.
Documents¶
- Arbres binaires et arbres binaire de recherche (sujet)
- Fichiers python :