TP2 - Arbres binaires de recherche
- Comprendre la structure d’un arbre binaire de recherche
- Implémenter l’insertion et la recherche dans un ABR
- Exploiter la propriété d’ordre d’un ABR
- Arbres binaires
- Programmation orientée objet
- Récursivité
Pour chaque fonction créée, ne pas oublier de la documenter.
Le but de cette seconde partie est de modéliser un arbre binaire de recherche en Python à l’aide de la programmation orientée objet.
Nous allons construire une classe représentant un nœud binaire de recherche, héritant des propriétés d’un nœud binaire, puis implémenter différentes méthodes permettant d’obtenir des informations sur l’arbre.
Création de la classe NBR
On souhaite définir une classe NBR (Nœud Binaire de Recherche) héritant de NoeudBinaire.
Ici, le constructeur ne prend qu’un seul paramètre : la valeur, et les fils gauche et droit seront initialisés à None.
- Créer la classe
NBRhéritant deNoeudBinairepuis implémenter son constructeur__init__prenant en paramètrevaleur, et initialisant les fils gauche et droit àNone. - Créer l'arbre suivant :
et stocker la racine dans la variable
arbre_binaire_recherche. - Tester les méthodes
tailleethauteursur cet arbre. - Afficher l'arbre en utilisant la fonction
afficher_arbre.
Méthodes de classe
Toutes les méthodes à écrire doivent être récursives.
Insertion d’une valeur
On souhaite insérer une valeur dans l’arbre tout en respectant les règles de l’ABR.
- Si on veut insérer les valeurs 2, 13, 9 et 20 dans
arbre_binaire_recherche, où faudrait-il placer ces nouveaux noeuds ? - En utilisant l'algorithme présenté dans le cours, écrire la méthode
inserer_valeur(self, x)dans la classe NBR qui ajoute un noeud contenant la valeurxdans l’arbre binaire de recherche. - Insérer successivement les valeurs 2, 13, 9 et 20 dans
arbre_binaire_recherche, puis vérifier si l'arbre obtenu correspond bien au résultat de la question 5.
Recherche d’une valeur
On souhaite maintenant écrire une méthode permettant de vérifier si un arbre contient bien une valeur x, sans parcourir tous les nœuds.
- En utilisant l'algorithme présenté dans le cours, écrire la méthode
contient_valeur(self, x)dans la classe NBR qui retourneTruesi un noeud contenant la valeurxest présent dans l’arbre binaire de recherche,Falsesinon. - Tester la méthode sur l'arbre
arbre_binaire_rechercheen vérifiant la présence des noeuds 4, 5 et 6.
Trace de recherche
Dans cet exercice, on s'intéresse à l'affichage d'une trace de la recherche effectuée, en indiquant par quel noeud on passe, et si on se dirige à gauche ou à droite, à l'aide de print.
>>> arbre_binaire_recherche.trace_recherche(7)
15
Gauche
6
Droite
7
>>> arbre_binaire_recherche.trace_recherche(16)
15
Droite
18
Gauche
17
Gauche
Introuvable
- Écrire la fonction
trace_recherche(self,x)affichant les informations de recherche de la valeurx. - Tester la méthode sur l'arbre
arbre_binaire_rechercheen vérifiant la présence des noeuds 4, 5 et 6.
Valeurs extrêmes
On souhaite ici trouver la valeur minimale et maximale de l'ABR.
- Déterminer la valeur minimale et maximale de l'arbre
arbre_binaire_recherche. - Proposer un algorithme permettant de trouver les valeurs des extremums.
- Implémenter les méthodes
valeur_minimale(self)etvaleur_maximale(self)retournant respectivement la plus petite et la plus grande des valeurs d'un ABR, à l'aide de l'algorithme trouvé à la question précédente. - Tester la méthode sur l'arbre
arbre_binaire_recherche.
Structure triée
Par définition, un ABR est une structure qui se veut triée.
- Identifier le parcours permettant d’obtenir les valeurs dans l’ordre croissant.
- Implémenter une méthode
tri_par_arbre(self)retournant une liste triée depuis un ABR. - Implémenter une méthode en dehors de la classe
liste_vers_arbre(liste)prenant en paramètre une liste triée, et retournant un ABR contenant les valeurs de la liste.Aide : la racine de l'arbre doit être la valeur du milieu de la liste. La moitié gauche fera partie du sous-arbre gauche, la moitié droite fera partie du sous-arbre droit.
Différentes constructions d’ABR et impact sur la complexité
La façon dont un arbre binaire de recherche est construit influence fortement l’efficacité des opérations de recherche et d’insertion.
Nous allons comparer deux cas extrêmes :
- un ABR dégénéré
- un ABR bien équilibré (complet)
ABR dégénéré
Un ABR est dit dégénéré lorsqu’il ressemble à une liste chaînée : chaque nœud n’a qu’un seul fils.
- Construire un ABR en insérant successivement les valeurs de la liste
dans un arbre initialement vide.
[1, 2, 3, 4, 5, 6, 7] - Afficher l'arbre avec la fonction
afficher_arbre. Quelle est sa hauteur ? - En utilisant la méthode
trace_recherche, compter le nombre de comparaisons effectuées pour rechercher la valeur 7 dans l'arbre. - Dans le pire des cas, si on dispose de
nnoeuds, quelle serait la complexité de la recherche ?
ABR équilibré (ou presque complet)
On souhaite maintenant construire un ABR dont la hauteur est minimale.
- À partir de la liste triée :
utiliser la fonction
[1, 2, 3, 4, 5, 6, 7]liste_vers_arbrepour construire un ABR équilibré. - Afficher l'arbre avec la fonction
afficher_arbre. Quelle est sa hauteur ? - À l’aide de la méthode
trace_recherche, observer le nombre de comparaisons nécessaires pour rechercher la valeur 7. - Quelle est la complexité de la recherche dans cet arbre en fonction du nombre
de nœuds
n?
Comparaisons
- Expliquer pourquoi la façon d’insérer les valeurs dans un ABR est déterminante pour ses performances.
- Faire des recherches sur 2 structures basées sur les ABR :
- Les AVL ;
- Les Red-Black Trees et expliquer en quelques phrases leur fonctionnement, et comment ces structures sont utilisées.
- Pourquoi, dans les bibliothèques et logiciels réels, utilise-t-on souvent des ABR auto-équilibrés (AVL, Red-Black trees) plutôt que des ABR simples ?