Leçon 7 sur 19

Chapitre 7 — Arbres binaires de recherche

Rechercher, insérer, supprimer et maintenir un ensemble ordonné

Positionnement dans le parcours — Ce chapitre prolonge l’introduction aux arbres binaires. Il exploite une propriété d’ordre pour obtenir une recherche, une insertion et une suppression efficaces, et prépare l’étude des arbres équilibrés, des dictionnaires ordonnés et des files de priorité.

 

Fiche pédagogique du chapitre

Objectifs d’apprentissage

À la fin de ce chapitre, l’étudiant devra être capable de :

  • énoncer et vérifier la propriété d’ordre d’un arbre binaire de recherche ;
  • définir une politique cohérente pour la gestion des clés dupliquées ;
  • rechercher une clé de manière itérative ou récursive ;
  • insérer une nouvelle clé sans rompre l’invariant d’ordre ;
  • déterminer le minimum, le maximum et le successeur d’un nœud ;
  • supprimer un nœud dans chacun des trois cas fondamentaux ;
  • justifier la correction des opérations à partir de l’invariant de l’arbre ;
  • analyser le coût des opérations selon la hauteur et la forme de l’arbre ;
  • modéliser un répertoire, un classement, un dictionnaire ordonné ou un index d’étudiants.

Prérequis

  • Vocabulaire et représentations des arbres binaires.
  • Parcours préfixe, infixe, postfixe et en largeur.
  • Récursivité et appels de fonctions.
  • Références vers des nœuds et structures chaînées.
  • Notions de complexité O(1), O(h), O(log n) et O(n).

Organisation proposée

Partie

Contenu principal

Durée indicative

7.1Invariant d’ordre et gestion des doublons2 h
7.2Recherche, insertion, extrema, successeur et suppression5 h
7.3Étude détaillée des trois cas de suppression3 h
7.4Performances selon la hauteur et la forme de l’arbre2 h
ApplicationsRépertoire, classement, dictionnaire et étudiants2 h
TD / TPConstruction, traces, tests et implémentation4 à 6 h

 

Introduction

Un arbre binaire de recherche, souvent abrégé ABR, est un arbre binaire qui organise ses clés selon une relation d’ordre. Cette organisation permet d’éliminer une partie du sous-arbre à chaque comparaison : une clé plus petite conduit vers la gauche, tandis qu’une clé plus grande conduit vers la droite.

L’efficacité d’un ABR dépend toutefois de sa forme. Lorsque l’arbre est équilibré, sa hauteur est logarithmique et les principales opérations sont rapides. Lorsqu’il dégénère en chaîne, il perd cet avantage et se comporte comme une liste linéaire.

Idée directrice — La propriété d’ordre réduit l’espace de recherche, mais la hauteur réelle de l’arbre détermine le coût des opérations.

 

7.1 Propriété d’ordre

7.1.1 Définition d’un arbre binaire de recherche

Un arbre binaire de recherche est un arbre binaire dans lequel chaque nœud contient une clé comparable. Pour tout nœud x, toutes les clés du sous-arbre gauche sont inférieures à la clé de x et toutes les clés du sous-arbre droit sont supérieures à la clé de x, selon la politique choisie pour les doublons.

Exemple d’arbre binaire de recherche

                     50

                  /      \

                30        70

               /  \       /  \

             20   40     60   80

                   \   /

                   45  55

 

Nœud

Clés du sous-arbre gauche

Clés du sous-arbre droit

5020, 30, 40, 4555, 60, 70, 80
302040, 45
7055, 6080
40Aucune45

 

Invariant — La propriété d’ordre doit être vraie pour chaque nœud et pour l’ensemble de ses descendants, pas seulement pour ses enfants immédiats.

 

7.1.2 Valeurs du sous-arbre gauche

Toutes les clés placées dans le sous-arbre gauche d’un nœud doivent respecter la relation « plus petite que ». Cette règle s’applique récursivement : une clé située plusieurs niveaux plus bas doit rester inférieure à tous les ancêtres pour lesquels elle appartient à la branche gauche.

Par exemple, 45 est l’enfant droit de 40, mais il appartient au sous-arbre gauche de 50. Il doit donc vérifier 40 < 45 < 50.

7.1.3 Valeurs du sous-arbre droit

Toutes les clés du sous-arbre droit sont supérieures à la clé du nœud courant. Dans l’exemple, 55 est inférieur à 60 mais reste supérieur à 50, car il appartient au sous-arbre droit de 50 et au sous-arbre gauche de 60.

Erreur fréquente — Vérifier uniquement enfantGauche < parent < enfantDroit ne suffit pas. Une valeur éloignée peut violer la contrainte imposée par un ancêtre.

 

7.1.4 Vérification de l’invariant par intervalles

Une méthode robuste consiste à associer à chaque appel récursif un intervalle de clés autorisées. La racine accepte initialement toutes les valeurs. Le sous-arbre gauche reçoit une borne maximale égale à la clé du parent ; le sous-arbre droit reçoit une borne minimale.

Pseudo-code — Vérifier qu’un arbre est un ABR

Fonction EstABR(noeud, borneMin, borneMax) : Booleen

    Si noeud = NULL Alors

         Retourner VRAI

    FinSi

    Si noeud.cle <= borneMin OU noeud.cle >= borneMax Alors

         Retourner FAUX

    FinSi

    Retourner EstABR(noeud.gauche, borneMin, noeud.cle)

            ET EstABR(noeud.droite, noeud.cle, borneMax)

FinFonction

Cette version correspond à une politique où les doublons sont interdits.

 

7.1.5 Parcours infixe et ordre des clés

Le parcours infixe visite successivement le sous-arbre gauche, le nœud puis le sous-arbre droit. Dans un ABR valide sans doublons, il produit les clés dans un ordre strictement croissant.

Pseudo-code — Produire les clés triées

Procedure AfficherTrie(noeud)

    Si noeud != NULL Alors

         AfficherTrie(noeud.gauche)

         Afficher(noeud.cle)

         AfficherTrie(noeud.droite)

    FinSi

FinProcedure

 

Pour l’arbre d’exemple, le résultat est : 20, 30, 40, 45, 50, 55, 60, 70, 80.

7.1.6 Gestion des doublons

La définition de l’ABR doit préciser le traitement des clés égales. Plusieurs politiques sont possibles, mais une seule doit être appliquée uniformément dans la recherche, l’insertion, la suppression et la validation.

Politique

Principe

Avantages

Limites

InterdictionUne clé ne peut apparaître qu’une fois.Invariant simple ; opérations claires.Ne conserve pas les occurrences multiples.
CompteurChaque nœud stocke une clé et un nombre d’occurrences.Structure compacte ; suppression progressive.Le nœud contient un champ supplémentaire.
Égaux à gauchecleGauche <= cleParent < cleDroiteImplémentation simple.Peut créer des chaînes de clés égales.
Égaux à droitecleGauche < cleParent <= cleDroiteConvention fréquente.Même risque de déséquilibre.
Liste de valeursUn nœud regroupe les objets ayant la même clé.Adapté aux index non uniques.Traitement interne plus complexe.

 

Convention du chapitre — Les algorithmes principaux supposent des clés uniques. Une variante avec compteur est ensuite présentée pour les applications comportant des doublons.

 

Pseudo-code — Structure d’un nœud avec compteur

Type NoeudABR

    cle : CleComparable

    occurrence : Entier

    gauche : Reference

    droite : Reference

FinType

 

7.2 Opérations

Toutes les opérations fondamentales suivent un chemin unique depuis la racine. À chaque nœud, une comparaison détermine si le traitement doit s’arrêter, continuer à gauche ou continuer à droite.

7.2.1 Recherche

La recherche compare la clé cible à la clé du nœud courant. En cas d’égalité, le nœud est trouvé. Une cible plus petite conduit au sous-arbre gauche ; une cible plus grande conduit au sous-arbre droit.

Recherche de la clé 45

50   : 45 < 50  -> gauche

30   : 45 > 30  -> droite

40   : 45 > 40  -> droite

45   : égalité  -> trouvé

 

Pseudo-code — Recherche récursive

Fonction Rechercher(noeud, cle) : Reference

    Si noeud = NULL OU noeud.cle = cle Alors

         Retourner noeud

    FinSi

    Si cle < noeud.cle Alors

         Retourner Rechercher(noeud.gauche, cle)

    Sinon

         Retourner Rechercher(noeud.droite, cle)

    FinSi

FinFonction

 

Pseudo-code — Recherche itérative

Fonction RechercherIteratif(racine, cle) : Reference

    courant <- racine

    TantQue courant != NULL ET courant.cle != cle Faire

        Si cle < courant.cle Alors

             courant <- courant.gauche

        Sinon

             courant <- courant.droite

        FinSi

    FinTantQue

    Retourner courant

FinFonction

 

Étape

Nœud courant

Comparaison

Décision

1

50

45 < 50

Aller à gauche

2

30

45 > 30

Aller à droite

3

40

45 > 40

Aller à droite

4

45

45 = 45

Retourner le nœud

 

7.2.2 Insertion

L’insertion recherche d’abord la position où la clé devrait se trouver. Lorsque le parcours atteint une référence NULL, un nouveau nœud est créé à cet emplacement. La nouvelle feuille respecte alors l’invariant d’ordre.

Pseudo-code — Insertion récursive

Fonction Inserer(noeud, cle) : Reference

    Si noeud = NULL Alors

         Retourner NouveauNoeud(cle)

    FinSi

    Si cle < noeud.cle Alors

         noeud.gauche <- Inserer(noeud.gauche, cle)

    SinonSi cle > noeud.cle Alors

         noeud.droite <- Inserer(noeud.droite, cle)

    FinSi

    Retourner noeud

FinFonction

La racine éventuellement modifiée doit être récupérée par l’appelant : racine <- Inserer(racine, cle).

 

Pseudo-code — Insertion itérative

Fonction InsererIteratif(racine, cle) : Reference

    nouveau <- NouveauNoeud(cle)

    Si racine = NULL Alors Retourner nouveau

    parent <- NULL

    courant <- racine

    TantQue courant != NULL Faire

        parent <- courant

        Si cle < courant.cle Alors courant <- courant.gauche

        SinonSi cle > courant.cle Alors courant <- courant.droite

        Sinon Retourner racine

    FinTantQue

    Si cle < parent.cle Alors parent.gauche <- nouveau

    Sinon parent.droite <- nouveau

    Retourner racine

FinFonction

 

7.2.3 Recherche du minimum

Le minimum d’un ABR est le nœud le plus à gauche. En effet, chaque déplacement vers la gauche conduit à une clé plus petite. Si le sous-arbre gauche est absent, le nœud courant est minimal dans son sous-arbre.

Pseudo-code — Minimum

Fonction Minimum(noeud) : Reference

    Si noeud = NULL Alors Retourner NULL

    courant <- noeud

    TantQue courant.gauche != NULL Faire

        courant <- courant.gauche

    FinTantQue

    Retourner courant

FinFonction

 

Dans l’arbre d’exemple, le chemin 50 -> 30 -> 20 conduit au minimum 20.

7.2.4 Recherche du maximum

Le maximum est obtenu symétriquement en suivant les références droites jusqu’à ce qu’aucun enfant droit n’existe.

Pseudo-code — Maximum

Fonction Maximum(noeud) : Reference

    Si noeud = NULL Alors Retourner NULL

    courant <- noeud

    TantQue courant.droite != NULL Faire

        courant <- courant.droite

    FinTantQue

    Retourner courant

FinFonction

 

Dans l’arbre d’exemple, le maximum est 80.

7.2.5 Recherche du successeur

Le successeur d’une clé est la plus petite clé strictement supérieure. Deux situations doivent être distinguées.

1. Si le nœud possède un sous-arbre droit, son successeur est le minimum de ce sous-arbre droit.

2. Sinon, il faut remonter vers le premier ancêtre pour lequel le nœud appartient au sous-arbre gauche.

Nœud

Sous-arbre droit ?

Successeur

Justification

40Oui : racine 4545Minimum du sous-arbre droit.
45Non50Premier ancêtre plus grand.
60Non70Remontée jusqu’à 70.
80NonAucun80 est la clé maximale.

 

Pseudo-code — Successeur à partir de la racine

Fonction Successeur(racine, cle) : Reference

    courant <- Rechercher(racine, cle)

    Si courant = NULL Alors Retourner NULL

    Si courant.droite != NULL Alors

         Retourner Minimum(courant.droite)

    FinSi

    successeur <- NULL

    parcours <- racine

    TantQue parcours != courant Faire

        Si cle < parcours.cle Alors

             successeur <- parcours

             parcours <- parcours.gauche

        Sinon

             parcours <- parcours.droite

        FinSi

    FinTantQue

    Retourner successeur

FinFonction

 

Remarque — Le prédécesseur se calcule de façon symétrique : maximum du sous-arbre gauche ou premier ancêtre plus petit.

 

7.2.6 Suppression d’un nœud

La suppression est l’opération la plus délicate, car retirer une clé ne doit pas rompre la structure ni l’invariant d’ordre. L’algorithme commence par rechercher la clé, puis traite l’un des trois cas : feuille, un enfant ou deux enfants.

Pseudo-code — Suppression récursive générale

Fonction Supprimer(noeud, cle) : Reference

    Si noeud = NULL Alors Retourner NULL

    Si cle < noeud.cle Alors

         noeud.gauche <- Supprimer(noeud.gauche, cle)

    SinonSi cle > noeud.cle Alors

         noeud.droite <- Supprimer(noeud.droite, cle)

    Sinon

        Si noeud.gauche = NULL Alors Retourner noeud.droite

        Si noeud.droite = NULL Alors Retourner noeud.gauche

        succ <- Minimum(noeud.droite)

         noeud.cle <- succ.cle

         noeud.droite <- Supprimer(noeud.droite, succ.cle)

    FinSi

    Retourner noeud

FinFonction

 

Point essentiel — L’appelant doit réaffecter la racine : racine <- Supprimer(racine, cle), car la suppression de la racine peut produire une nouvelle racine.

 

7.3 Cas de suppression

7.3.1 Suppression d’un nœud feuille

Une feuille ne possède aucun enfant. Elle peut être détachée directement en remplaçant la référence du parent par NULL. Si la feuille est également la racine, l’arbre devient vide.

Suppression de la feuille 20

Avant :                 Après :

        30                      30

       /  \                       \

     20   40                     40

 

La référence gauche de 30 devient NULL.

 

Pseudo-code — Cas feuille

Si noeud.gauche = NULL ET noeud.droite = NULL Alors

     Liberer(noeud)

    Retourner NULL

FinSi

 

7.3.2 Suppression d’un nœud avec un enfant

Le nœud supprimé est remplacé par son unique enfant. Le sous-arbre porté par cet enfant reste intact et conserve sa position relative par rapport aux ancêtres.

Suppression du nœud 40, qui possède l’enfant droit 45

Avant :                 Après :

        30                      30

          \                      \

           40                     45

            \

             45

 

La référence droite de 30 pointe désormais vers 45.

 

Pseudo-code — Cas d’un seul enfant

Si noeud.gauche = NULL Alors

    enfant <- noeud.droite

     Liberer(noeud)

    Retourner enfant

FinSi

Si noeud.droite = NULL Alors

    enfant <- noeud.gauche

     Liberer(noeud)

    Retourner enfant

FinSi

 

7.3.3 Suppression d’un nœud avec deux enfants

Un nœud ayant deux enfants ne peut pas être remplacé directement par l’un d’eux sans perdre l’autre sous-arbre. On choisit une clé voisine dans l’ordre : le successeur, minimum du sous-arbre droit, ou le prédécesseur, maximum du sous-arbre gauche.

1. Trouver le successeur du nœud à supprimer.

2. Copier la clé et, le cas échéant, les données associées du successeur dans le nœud.

3. Supprimer le successeur de son emplacement d’origine.

4. Le successeur ne possède jamais d’enfant gauche ; sa suppression relève donc d’un cas plus simple.

Suppression de 50 en utilisant le successeur 55

Avant :                         Après :

            50                               55

         /      \                        /      \

       30        70                    30        70

              /  \                            /  \

            60   80                          60   80

            /

          55

 

55 remplace 50, puis l’ancien nœud 55 est supprimé.

 

Conservation de l’ordre — Le successeur est supérieur à toutes les clés du sous-arbre gauche et inférieur ou égal à toutes les autres clés du sous-arbre droit. Son remplacement préserve donc l’invariant.

 

7.3.4 Suppression avec données associées

Lorsque le nœud contient plusieurs champs, il faut copier l’enregistrement logique complet, pas uniquement la clé. Dans un répertoire, le numéro, le nom et les coordonnées associés au successeur doivent rester cohérents.

Pseudo-code — Copier les données du successeur

succ <- Minimum(noeud.droite)

noeud.cle <- succ.cle

noeud.valeur <- succ.valeur

noeud.droite <- Supprimer(noeud.droite, succ.cle)

 

Risque — Copier uniquement la clé et laisser les anciennes données du nœud crée une incohérence entre la clé et la valeur associée.

 

7.3.5 Suppression avec compteur de doublons

Avec la politique du compteur, une suppression décrémente d’abord le nombre d’occurrences. Le nœud n’est structurellement retiré que lorsque le compteur atteint zéro.

Pseudo-code — Suppression avec occurrences

Si cle = noeud.cle Alors

    Si noeud.occurrence > 1 Alors

         noeud.occurrence <- noeud.occurrence - 1

         Retourner noeud

    FinSi

    // appliquer ensuite la suppression structurelle

FinSi

 

7.3.6 Tableau récapitulatif

Cas

Transformation

Difficulté

Coût après localisation

FeuilleRemplacer le nœud par NULL.FaibleO(1)
Un enfantRelier le parent directement à l’enfant.FaibleO(1)
Deux enfantsCopier successeur/prédécesseur puis le supprimer.MoyenneO(h) au pire
RacineRéaffecter la référence racine.Attention particulièreSelon le cas

 

7.4 Analyse des performances

7.4.1 La hauteur comme paramètre central

Une recherche, une insertion ou une suppression suit au plus un chemin de la racine vers une feuille. Leur coût est donc proportionnel à la hauteur h de l’arbre, soit O(h). La valeur de h dépend directement de la forme de l’arbre et de l’ordre des insertions.

7.4.2 Arbre équilibré

Un arbre est équilibré lorsque les hauteurs de ses branches restent proches. Pour n nœuds, sa hauteur est alors de l’ordre de log2(n). Les opérations principales ont une complexité logarithmique.

Exemple équilibré — insertion de 4, 2, 6, 1, 3, 5, 7

              4

            /   \

            2     6

           / \   / \

          1   3 5   7

 

n = 7, hauteur h = 2

 

7.4.3 Arbre dégénéré

Si les clés sont insérées dans un ordre déjà trié, chaque nouvelle clé peut devenir l’enfant droit de la précédente. L’arbre dégénère alors en liste chaînée, avec une hauteur n - 1.

Exemple dégénéré — insertion de 1, 2, 3, 4, 5

1

 \

  2

    \

     3

      \

       4

        \

         5

 

Conséquence — Un ABR ordinaire ne garantit pas O(log n). Cette performance n’est obtenue que lorsque la hauteur reste logarithmique.

 

7.4.4 Meilleur cas, cas moyen et pire cas

Opération

Meilleur cas

Cas moyen attendu

Pire cas

RechercheO(1) : clé à la racineO(log n) si forme favorableO(n) : arbre dégénéré
InsertionO(1) dans un arbre videO(log n)O(n)
Minimum / maximumO(1) si pas de branche concernéeO(log n)O(n)
SuccesseurO(1) dans certains casO(log n)O(n)
SuppressionO(1) après localisation simpleO(log n)O(n)
Parcours completO(n)O(n)O(n)

 

7.4.5 Influence de l’ordre d’insertion

Les mêmes clés peuvent produire des arbres très différents selon leur ordre d’arrivée. La suite 1, 2, 3, 4, 5, 6, 7 crée une chaîne, tandis que la suite 4, 2, 6, 1, 3, 5, 7 crée un arbre parfait.

Ordre d’insertion

Hauteur obtenue

Coût maximal de recherche

1, 2, 3, 4, 5, 6, 7

6

7 comparaisons

4, 2, 6, 1, 3, 5, 7

2

3 comparaisons

4, 6, 2, 5, 7, 1, 3

2

3 comparaisons

 

7.4.6 Coût spatial

Chaque nœud stocke une clé, une valeur éventuelle et deux références. La mémoire totale de la structure est O(n). Les versions récursives utilisent en plus une pile d’appels de taille O(h). Dans un arbre dégénéré, cette pile peut atteindre O(n).

Élément

Mémoire

Nœuds de l’arbreO(n)
Recherche itérativeO(1) auxiliaire
Recherche récursiveO(h) pour les appels
Parcours infixe récursifO(h)
Parcours en largeurO(w), largeur maximale

 

7.4.7 Limites et arbres auto-équilibrés

Les arbres AVL et rouge-noir réorganisent automatiquement les nœuds après certaines insertions et suppressions. Ils garantissent une hauteur O(log n), au prix d’informations supplémentaires et d’opérations de rotation. Ils seront étudiés au niveau avancé.

Choix pratique — Un ABR simple convient pour apprendre les principes ou lorsque les données sont peu nombreuses. Une structure équilibrée est préférable lorsque des garanties de performance sont nécessaires.

 

Applications

Application 1 — Gestion d’un répertoire

Chaque entrée est indexée par une clé unique, par exemple un numéro de contact. La valeur associée peut contenir le nom, le téléphone et l’adresse électronique. L’ABR permet une consultation ordonnée et un parcours alphabétique si la clé est le nom normalisé.

Pseudo-code — Rechercher un contact

Fonction ChercherContact(racine, numero) : ContactOuNULL

    noeud <- Rechercher(racine, numero)

    Si noeud = NULL Alors Retourner NULL

    Retourner noeud.contact

FinFonction

 

  • Ajouter un contact avec une clé non utilisée.
  • Modifier les données sans changer la clé.
  • Supprimer un contact par numéro.
  • Afficher tous les contacts dans l’ordre des clés.

Application 2 — Classement de valeurs

Les valeurs sont insérées dans l’ABR, puis un parcours infixe produit le classement croissant. Pour conserver les doublons, chaque nœud peut contenir un compteur.

Pseudo-code — Afficher un classement avec occurrences

Procedure AfficherClassement(noeud)

    Si noeud != NULL Alors

         AfficherClassement(noeud.gauche)

        Pour i allant de 1 a noeud.occurrence Faire

             Afficher(noeud.cle)

        FinPour

         AfficherClassement(noeud.droite)

    FinSi

FinProcedure

 

Application 3 — Dictionnaire ordonné

La clé est un mot et la valeur sa définition. L’ordre lexicographique permet de rechercher un mot, de produire la liste alphabétique et d’extraire les entrées comprises dans un intervalle.

Pseudo-code — Afficher les mots entre deux bornes

Procedure AfficherIntervalle(noeud, debut, fin)

    Si noeud = NULL Alors Retourner

    Si debut < noeud.cle Alors

         AfficherIntervalle(noeud.gauche, debut, fin)

    FinSi

    Si debut <= noeud.cle ET noeud.cle <= fin Alors

         Afficher(noeud.cle, noeud.definition)

    FinSi

    Si noeud.cle < fin Alors

         AfficherIntervalle(noeud.droite, debut, fin)

    FinSi

FinProcedure

 

Application 4 — Recherche d’un étudiant par numéro

Le numéro d’inscription constitue la clé unique. Les autres champs forment la valeur associée : nom, prénom, filière et moyenne. L’ABR permet une recherche directe sans parcourir toute la liste.

Pseudo-code — Structure d’un nœud étudiant

Type NoeudEtudiant

    numero : Entier

    nom : Chaine

    prenom : Chaine

    filiere : Chaine

    moyenne : Reel

    gauche : Reference

    droite : Reference

FinType

 

Pseudo-code — Insérer un étudiant

Fonction InsererEtudiant(noeud, etudiant) : Reference

    Si noeud = NULL Alors Retourner NouveauNoeud(etudiant)

    Si etudiant.numero < noeud.numero Alors

         noeud.gauche <- InsererEtudiant(noeud.gauche, etudiant)

    SinonSi etudiant.numero > noeud.numero Alors

         noeud.droite <- InsererEtudiant(noeud.droite, etudiant)

    Sinon

         Signaler("Numéro déjà utilisé")

    FinSi

    Retourner noeud

FinFonction

 

Protection de l’index — Modifier une clé sur place peut violer l’ordre. Pour changer le numéro d’un étudiant, il faut supprimer l’ancienne entrée puis insérer la nouvelle.

 

Méthode de résolution et bonnes pratiques

1. Définir précisément la clé et sa relation d’ordre.

2. Choisir et documenter une politique de doublons.

3. Faire retourner la nouvelle racine par les opérations récursives.

4. Tester l’arbre vide, la racine, les feuilles et les nœuds internes.

5. Vérifier l’invariant après chaque insertion et suppression.

6. Utiliser le parcours infixe pour contrôler l’ordre des clés.

7. Mesurer la hauteur afin de détecter un déséquilibre important.

8. Copier toutes les données associées lors du remplacement par un successeur.

Erreurs fréquentes

Erreur

Conséquence

Correction

Comparer uniquement avec le parent immédiatUn descendant peut violer une borne d’ancêtre.Valider avec des intervalles min/max.
Oublier racine <- Inserer/SupprimerLa création ou le remplacement de la racine est perdu.Toujours récupérer la référence retournée.
Mélanger les politiques de doublonsRecherche et suppression incohérentes.Définir une convention unique.
Copier seulement la clé du successeurClé et valeur associée deviennent incohérentes.Copier l’enregistrement logique complet.
Supposer O(log n) dans tous les casSous-estimation du temps d’exécution.Exprimer le coût en O(h).
Supprimer un nœud à deux enfants directementPerte d’un sous-arbre.Utiliser successeur ou prédécesseur.

 

Travaux dirigés

TD 1 — Vérifier la propriété d’ordre

Pour chacun des arbres proposés par l’enseignant, déterminer s’il s’agit d’un ABR. Lorsqu’un arbre est invalide, identifier le premier nœud qui viole une borne héritée d’un ancêtre.

TD 2 — Construire un ABR

Construire successivement les arbres obtenus avec les suites suivantes et calculer leur hauteur :

  • 50, 30, 70, 20, 40, 60, 80 ;
  • 20, 30, 40, 50, 60, 70, 80 ;
  • 50, 70, 30, 80, 60, 40, 20.

TD 3 — Tracer une recherche

Dans l’arbre d’exemple, tracer la recherche des clés 55, 65 et 20. Indiquer les comparaisons, les décisions et le résultat final.

TD 4 — Minimum, maximum et successeurs

Déterminer le minimum, le maximum et le successeur de 20, 40, 45, 50, 60, 70 et 80.

TD 5 — Insertions

À partir de l’arbre d’exemple, insérer successivement 35, 65, 75 et 10. Dessiner l’arbre après chaque opération et vérifier son parcours infixe.

TD 6 — Suppressions

Effectuer indépendamment les suppressions suivantes : 20, 40, 30 et 50. Pour chaque opération, préciser le cas rencontré et l’éventuel successeur utilisé.

TD 7 — Politique de doublons

Insérer la suite 12, 7, 12, 5, 7, 12 avec : a) doublons à droite ; b) compteur d’occurrences. Comparer la hauteur, la mémoire et la facilité de suppression.

TD 8 — Analyse de complexité

Exprimer en fonction de h puis de n le coût de la recherche, de l’insertion, du minimum, du successeur, de la suppression et du parcours infixe.

TD 9 — Intervalle de clés

Concevoir un algorithme qui affiche uniquement les clés comprises entre a et b sans parcourir inutilement les sous-arbres qui ne peuvent contenir aucune réponse.

TD 10 — Index d’étudiants

Proposer les structures et les opérations nécessaires pour gérer des étudiants indexés par numéro : ajouter, rechercher, modifier la moyenne, supprimer et afficher dans l’ordre des numéros.

Corrigés indicatifs des travaux dirigés

Correction du TD 1

La vérification correcte propage un intervalle autorisé. Une clé peut respecter son parent immédiat tout en étant trop grande ou trop petite par rapport à un ancêtre. Le parcours infixe croissant est un contrôle utile, mais la méthode par bornes exprime directement l’invariant.

Correction du TD 2

Suite

Forme obtenue

Hauteur

50, 30, 70, 20, 40, 60, 80

Arbre parfait

2

20, 30, 40, 50, 60, 70, 80

Chaîne vers la droite

6

50, 70, 30, 80, 60, 40, 20

Arbre équilibré

2

 

Correction du TD 3

Clé

Chemin de recherche

Résultat

55

50 -> 70 -> 60 -> 55

Trouvée

65

50 -> 70 -> 60 -> NULL droite

Absente

20

50 -> 30 -> 20

Trouvée

 

Correction du TD 4

Clé

Successeur

20

30

40

45

45

50

50

55

60

70

70

80

80

Aucun

 

Correction du TD 5

35 devient l’enfant gauche de 40 ; 65 devient l’enfant droit de 60 ; 75 devient l’enfant gauche de 80 ; 10 devient l’enfant gauche de 20. Le parcours infixe final doit être : 10, 20, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80.

Correction du TD 6

Clé supprimée

Cas

Transformation

20FeuilleRéférence gauche de 30 mise à NULL.
40Un enfant droit 4545 remplace 40.
30Deux enfantsUtiliser 40 ou 45 selon l’arbre considéré.
50Deux enfants et racine55 peut remplacer 50 ; réaffecter la racine.

 

Correction du TD 7

La politique « égaux à droite » produit plusieurs nœuds et peut allonger fortement une branche. La politique du compteur conserve un seul nœud par clé distincte ; elle économise des références et simplifie le classement, mais impose de gérer occurrence lors des suppressions.

Correction du TD 8

Opération

En fonction de h

Équilibré

Dégénéré

Recherche

O(h)

O(log n)

O(n)

Insertion

O(h)

O(log n)

O(n)

Minimum / maximum

O(h)

O(log n)

O(n)

Successeur

O(h)

O(log n)

O(n)

Suppression

O(h)

O(log n)

O(n)

Parcours infixe

O(n)

O(n)

O(n)

 

Correction du TD 9

Pseudo-code — Affichage borné

Procedure AfficherEntre(noeud, a, b)

    Si noeud = NULL Alors Retourner

    Si a < noeud.cle Alors AfficherEntre(noeud.gauche, a, b)

    Si a <= noeud.cle ET noeud.cle <= b Alors Afficher(noeud.cle)

    Si noeud.cle < b Alors AfficherEntre(noeud.droite, a, b)

FinProcedure

 

Correction du TD 10

Le numéro est la clé. Les opérations AjouterEtudiant, ChercherEtudiant, ModifierMoyenne et SupprimerEtudiant réutilisent respectivement l’insertion, la recherche et la suppression de l’ABR. La modification de la moyenne ne change pas la structure. Un parcours infixe affiche les étudiants par numéro croissant.

Travail pratique — Gestion d’un index ordonné

Objectif

Implémenter un ABR complet permettant de gérer des étudiants indexés par leur numéro d’inscription, puis mesurer l’influence de l’ordre d’insertion sur la hauteur et le nombre de comparaisons.

Fonctionnalités minimales

  • Créer et vider l’arbre.
  • Insérer un étudiant en refusant les numéros dupliqués.
  • Rechercher un étudiant et compter les comparaisons.
  • Modifier les données non clés.
  • Afficher les étudiants par numéro croissant.
  • Calculer la taille et la hauteur.
  • Déterminer le minimum, le maximum et le successeur.
  • Supprimer un étudiant dans chacun des trois cas.
  • Vérifier automatiquement l’invariant d’ordre.

Jeux d’essai obligatoires

Scénario

Données

Résultat attendu

Arbre videRecherche et suppressionÉchec contrôlé sans erreur.
Insertion équilibrée50, 30, 70, 20, 40, 60, 80Hauteur 2.
Insertion triée10, 20, 30, 40, 50Arbre dégénéré de hauteur 4.
DoublonInsérer deux fois 30Deuxième insertion refusée.
Suppression feuilleSupprimer 20Invariant conservé.
Suppression un enfantCréer puis supprimer un nœud unaireEnfant reconnecté.
Suppression deux enfantsSupprimer 50Successeur utilisé ; ordre conservé.

 

Mesures expérimentales

1. Générer n clés dans un ordre aléatoire et mesurer la hauteur.

2. Insérer les mêmes clés dans l’ordre croissant et mesurer la hauteur.

3. Rechercher toutes les clés et calculer le nombre moyen de comparaisons.

4. Comparer les résultats avec log2(n) et n.

5. Expliquer pourquoi la forme observée influence les temps.

Grille d’évaluation

Critère

Points

Structures et invariant correctement définis

3

Recherche, insertion, minimum et maximum

4

Successeur et suppression des trois cas

5

Tests et gestion des erreurs

3

Mesures et analyse de complexité

3

Lisibilité et modularité

2

 

Synthèse du chapitre

Notion

À retenir

Invariant d’ordreToutes les clés de gauche sont plus petites et toutes celles de droite plus grandes selon la politique choisie.
RechercheUne comparaison par niveau ; coût O(h).
InsertionCréer une feuille à la première référence NULL compatible.
Minimum / maximumSuivre respectivement les références gauche / droite.
SuccesseurMinimum du sous-arbre droit ou premier ancêtre plus grand.
SuppressionTrois cas : feuille, un enfant, deux enfants.
Parcours infixeProduit les clés dans l’ordre croissant.
PerformanceO(log n) si la hauteur est logarithmique ; O(n) si l’arbre dégénère.

 

Glossaire

Terme

Définition

ABRArbre binaire respectant une propriété d’ordre sur les clés.
CléValeur utilisée pour organiser et retrouver un enregistrement.
InvariantPropriété qui doit rester vraie avant et après chaque opération.
SuccesseurPlus petite clé strictement supérieure à une clé donnée.
PrédécesseurPlus grande clé strictement inférieure.
Arbre équilibréArbre dont la hauteur reste proche de log2(n).
Arbre dégénéréArbre dont les nœuds forment presque une chaîne.
DoublonNouvelle donnée possédant une clé déjà présente.

 

Auto-évaluation

Je suis capable de…

Oui

À revoir

Vérifier la propriété d’ordre avec des bornes.

Expliquer une politique de gestion des doublons.

Tracer une recherche et une insertion.

Calculer minimum, maximum et successeur.

Traiter les trois cas de suppression.

Justifier le coût O(h) des opérations.

Comparer un arbre équilibré et un arbre dégénéré.

Concevoir une application indexée par une clé.

 

Conclusion — L’arbre binaire de recherche associe une organisation hiérarchique à une relation d’ordre. Il offre des opérations très efficaces lorsque sa hauteur reste faible, mais son comportement peut se dégrader sans mécanisme d’équilibrage.