Précédent Index Suivant

Arbres binaires de recherche

 
 
Les arbres binaires sont des structures de données très utiles en informatique. Dans cette section, comme exemple d'utilisation des arbres binaires, nous étudions les « arbres binaires de recherche ».
 
Introduction et définition  
En informatique, il est fréquent d'avoir besoin de gérer un ensemble d'informations (comme l'ensemble des étudiants de DEUG-MIAS). Dans cette gestion, l'une des opérations fondamentales est de savoir si un individu donné (connu par son nom ou par son numéro de carte d'étudiant) fait, ou ne fait pas, partie de la base. Pour ce faire, il existe une structure de données efficace, la structure d'arbre binaire de recherche.
 
Un arbre binaire de recherche est un arbre binaire vide ou un arbre binaire qui possède les propriétés suivantes:  
Par la suite, pour que les opérations de comparaison soient définies (et soient < et >), nous considèrerons que les étiquettes sont des nombres.
 
Voici un exemple d'arbre binaire de recherche:
 
 

 
Les propriétés caractéristiques de la notion d'arbre binaire de recherche sont intéressantes pour l'efficacité de la recherche car elles permettent de ne chercher un élément que dans un des deux sous-arbres, recherche qui s'effectue en ne recherchant que dans un des deux sous-sous-arbres...
 
Notons que, dans un arbre binaire de recherche, c'est l'ensemble de ses étiquettes qui nous intéresse: deux arbres binaires de recherche peuvent donc être « équivalents ». Par exemple, en tant qu'arbres binaires de recherche, l'arbre précédent est « équivalent » à l'arbre suivant:
 
 

 
Spécification  
Nous nommerons ArbreBinRecherche le type des arbres binaires de recherche, et, par la suite, nous voudrions définir les fonctions suivantes:
 
;;; abr-recherche : Nombre * ArbreBinRecherche -> ArbreBinRecherche + #f 
;;; (abr-recherche x ABR) rend l'arbre de racine «x», lorsque «x» apparait dans «ABR» 
;;; et renvoie #f si «x» n'apparait pas dans «ABR» 
 

 
Par exemple, dans notre implantation, si abr1 est l'arbre binaire de recherche dessiné ci-dessus, (abr-recherche 5 abr1) a comme valeur  
 

 
;;; abr-ajout : Nombre * ArbreBinRecherche -> ArbreBinRecherche  
;;; (abr-ajout x ABR) rend l'arbre «ABR» lorque «x» apparait dans «ABR» et, lorsque 
;;; «x» n'apparait pas dans «ABR», rend un arbre binaire de recherche qui contient «x» 
;;; et toutes les étiquettes qui apparaissent dans «ABR» 
 

 
Par exemple, dans notre implantation -- et une autre implantation peut rendre un arbre binaire de recherche équivalent --, (abr-ajout 17 abr1) a comme valeur
 
 
;;; abr-moins : Nombre * ArbreBinRecherche -> ArbreBinRecherche 
;;; (abr-moins x ABR) rend l'arbre «ABR» lorque «x» n'apparait pas dans «ABR» et,  
;;; lorsque «x» apparait dans «ABR», rend un arbre binaire de recherche qui 
;;; contient toutes les étiquettes qui apparaissent dans «ABR» hormis «x». 
 

 
Par exemple, dans notre implantation -- et une autre implantation peut rendre un arbre binaire de recherche équivalent --, (abr-moins 10 abr1) a comme valeur
 
 
Noter que lorsque l'élément à supprimer est l'étiquette d'un noeud interne, obligatoirement, l'arbre binaire est profondemment modifié.
 
Implantation  
Naturellement, nous implantons les arbres binaires de recherche à l'aide de la barrière d'abstraction ArbreBinaire.
 
Fonction abr-recherche  
Rappelons la spécification:
 
;;; abr-recherche : Nombre * ArbreBinRecherche -> ArbreBinRecherche + #f 
;;; (abr-recherche x ABR) rend l'arbre de racine «x», lorsque «x» apparait dans «ABR» 
;;; et renvoie #f si «x» n'apparait pas dans «ABR» 
 

 
L'idée (récursive) de l'implantation est très simple:  
D'où la définition:
 
(define (abr-recherche x ABR)
  (if (ab-vide? ABR)
      #f
      (let ((e (ab-etiquette  ABR)))
        (cond ((= x e) ABR)
              ((< x e) (abr-recherche x (ab-gauche ABR)))
              (else (abr-recherche x (ab-droit ABR)))))))
 

 
Fonction abr-ajout  
Rappelons la spécification:
 
;;; abr-ajout : Nombre * ArbreBinRecherche -> ArbreBinRecherche  
;;; (abr-ajout x ABR) rend l'arbre «ABR» lorque «x» apparait dans «ABR» et, lorsque 
;;; «x» n'apparait pas dans «ABR», rend un arbre binaire de recherche qui contient «x» 
;;; et toutes les étiquettes qui apparaissent dans «ABR» 
 

 
L'idée (récursive) de l'implantation est également très simple:  
D'où la définition:
 
(define (abr-ajout x ABR)
  (if (ab-vide? ABR)
      (ab-noeud x (ab-vide) (ab-vide))
      (let ((e (ab-etiquette  ABR)))
        (cond ((= x e) ABR)
              ((< x e) (ab-noeud e
                                 (abr-ajout x (ab-gauche ABR))
                                 (ab-droit ABR)))
              (else (ab-noeud e 
                              (ab-gauche ABR)
                              (abr-ajout x (ab-droit ABR))))))))
 

 
Remarque: le recueil d'exercices contient une autre implantation de cette fonction.
 
Fonction abr-moins  
Rappelons la spécification:
 
;;; abr-moins : Nombre * ArbreBinRecherche -> ArbreBinRecherche 
;;; (abr-moins x ABR) rend l'arbre «ABR» lorque «x» n'apparait pas dans «ABR» et,  
;;; lorsque «x» apparait dans «ABR», rend un arbre binaire de recherche qui 
;;; contient toutes les étiquettes qui apparaissent dans «ABR» hormis «x». 
 

 
L'idée initiale est encore très simple (mais ça se complique par la suite...):  
 
(define (abr-moins x ABR) 
  (if (ab-vide? ABR)
      (ab-vide)
      (let ((e (ab-etiquette  ABR)))
        (cond ((= x e) (moins-racine ABR))
              ((< x e) (ab-noeud e
                                 (abr-moins x (ab-gauche ABR))
                                 (ab-droit ABR)))
              (else (ab-noeud e 
                              (ab-gauche ABR)
                              (abr-moins x (ab-droit ABR))))))))
 

 
La spécification de moins-racine étant:
 
;;; moins-racine : ArbreBinRecherche -> ArbreBinRecherche 
;;; (moins-racine ABR) rend l'arbre binaire de recherche qui contient toutes 
;;; les étiquettes qui apparaissent dans «ABR» hormis l'étiquette de sa racine. 
;;; ERREUR lorsque l'arbre «ABR» est vide 
 

 
Comment implanter cette fonction?
 
Première idée:
 
(define (moins-racine0 ABR)
  (reduce abr-ajout 
          (ab-gauche ABR) 
          (ab-liste-infixe (ab-droit ABR))))
 

 
Seconde idée:
 
Deux situations entraînent une solution évidente: lorsque l'un des deux sous-arbres est vide, le résultat est l'autre sous-arbre. Dans le cas contraire, on peut essayer de « conserver » un des deux sous-arbres, le droit par exemple: pour obtenir un arbre qui vérifie la propriété « arbre binaire de recherche », il faut alors que la racine de l'arbre résultat soit le plus grand élément du sous-arbre gauche. Ainsi, le résultat est un arbre  
 
Ainsi, pour implanter la fonction moins-racine, on a besoin de la fonction max-sauf-max de spécification:
 
;;; max-sauf-max : ArbreBinRecherche -> NUPLET[Nombre ArbreBinRecherche] 
;;; (max-sauf-max ABR) rend le couple formé de la plus grande étiquette présente 
;;; dans l'arbre «ABR» et d'un arbre binaire de recherche qui contient toutes les 
;;; étiquettes qui apparaissent dans «ABR» hormis ce maximum 
;;; ERREUR lorsque l'arbre «ABR» est vide 
 

 
La définition de la fonction moins-racine étant alors:
 
(define (moins-racine ABR)
  (cond ((ab-vide? (ab-gauche ABR))
         (ab-droit ABR))
        ((ab-vide? (ab-droit ABR))
         (ab-gauche ABR))
        (else
         (let ((m-sm-ss-ab-g (max-sauf-max (ab-gauche ABR))))
           (ab-noeud (car m-sm-ss-ab-g)
                     (cadr m-sm-ss-ab-g)
                     (ab-droit ABR))))))
 

 
Ne reste plus qu'à implanter la fonction max-sauf-max. Comme nous l'avons noté, le plus grand des éléments présents dans un arbre binaire de recherche se trouve au bout de la branche la plus à droite de cet arbre. Ainsi, la recherche du maximum et la constitution de l'arbre privé de son maximum s'effectuent par l'exploration successive des sous-arbres droits:
 
;;; max-sauf-max : ArbreBinRecherche -> NUPLET[Nombre ArbreBinRecherche] 
;;; (max-sauf-max ABR) rend le couple formé de la plus grande étiquette présente 
;;; dans l'arbre «ABR» et d'un arbre binaire de recherche qui contient toutes les 
;;; étiquettes qui apparaissent dans «ABR» hormis ce maximum 
;;; ERREUR lorsque l'arbre «ABR» est vide 
(define (max-sauf-max ABR)
  (if (ab-vide? (ab-droit ABR))
      (list (ab-etiquette ABR) (ab-gauche ABR))
      (let ((m-sm-ss-ab-d (max-sauf-max (ab-droit ABR))))
        (list (car m-sm-ss-ab-d)
              (ab-noeud (ab-etiquette ABR)
                        (ab-gauche ABR)
                        (cadr m-sm-ss-ab-d))))))
 

 


Auteur(s): titou@ufr-info-p6.jussieu.fr.Mainteneur de la page: titou@ufr-info-p6.jussieu.fr.

Précédent Index Suivant