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.1 | Invariant d’ordre et gestion des doublons | 2 h |
| 7.2 | Recherche, insertion, extrema, successeur et suppression | 5 h |
| 7.3 | Étude détaillée des trois cas de suppression | 3 h |
| 7.4 | Performances selon la hauteur et la forme de l’arbre | 2 h |
| Applications | Répertoire, classement, dictionnaire et étudiants | 2 h |
| TD / TP | Construction, traces, tests et implémentation | 4 à 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 |
|---|---|---|
| 50 | 20, 30, 40, 45 | 55, 60, 70, 80 |
| 30 | 20 | 40, 45 |
| 70 | 55, 60 | 80 |
| 40 | Aucune | 45 |
| 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 |
|---|---|---|---|
| Interdiction | Une clé ne peut apparaître qu’une fois. | Invariant simple ; opérations claires. | Ne conserve pas les occurrences multiples. |
| Compteur | Chaque nœud stocke une clé et un nombre d’occurrences. | Structure compacte ; suppression progressive. | Le nœud contient un champ supplémentaire. |
| Égaux à gauche | cleGauche <= cleParent < cleDroite | Implémentation simple. | Peut créer des chaînes de clés égales. |
| Égaux à droite | cleGauche < cleParent <= cleDroite | Convention fréquente. | Même risque de déséquilibre. |
| Liste de valeurs | Un 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 |
|---|---|---|---|
| 40 | Oui : racine 45 | 45 | Minimum du sous-arbre droit. |
| 45 | Non | 50 | Premier ancêtre plus grand. |
| 60 | Non | 70 | Remontée jusqu’à 70. |
| 80 | Non | Aucun | 80 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 |
|---|---|---|---|
| Feuille | Remplacer le nœud par NULL. | Faible | O(1) |
| Un enfant | Relier le parent directement à l’enfant. | Faible | O(1) |
| Deux enfants | Copier successeur/prédécesseur puis le supprimer. | Moyenne | O(h) au pire |
| Racine | Réaffecter la référence racine. | Attention particulière | Selon 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 |
|---|---|---|---|
| Recherche | O(1) : clé à la racine | O(log n) si forme favorable | O(n) : arbre dégénéré |
| Insertion | O(1) dans un arbre vide | O(log n) | O(n) |
| Minimum / maximum | O(1) si pas de branche concernée | O(log n) | O(n) |
| Successeur | O(1) dans certains cas | O(log n) | O(n) |
| Suppression | O(1) après localisation simple | O(log n) | O(n) |
| Parcours complet | O(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’arbre | O(n) |
| Recherche itérative | O(1) auxiliaire |
| Recherche récursive | O(h) pour les appels |
| Parcours infixe récursif | O(h) |
| Parcours en largeur | O(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édiat | Un descendant peut violer une borne d’ancêtre. | Valider avec des intervalles min/max. |
| Oublier racine <- Inserer/Supprimer | La 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 doublons | Recherche et suppression incohérentes. | Définir une convention unique. |
| Copier seulement la clé du successeur | Clé et valeur associée deviennent incohérentes. | Copier l’enregistrement logique complet. |
| Supposer O(log n) dans tous les cas | Sous-estimation du temps d’exécution. | Exprimer le coût en O(h). |
| Supprimer un nœud à deux enfants directement | Perte 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 |
|---|---|---|
| 20 | Feuille | Référence gauche de 30 mise à NULL. |
| 40 | Un enfant droit 45 | 45 remplace 40. |
| 30 | Deux enfants | Utiliser 40 ou 45 selon l’arbre considéré. |
| 50 | Deux enfants et racine | 55 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 vide | Recherche et suppression | Échec contrôlé sans erreur. |
| Insertion équilibrée | 50, 30, 70, 20, 40, 60, 80 | Hauteur 2. |
| Insertion triée | 10, 20, 30, 40, 50 | Arbre dégénéré de hauteur 4. |
| Doublon | Insérer deux fois 30 | Deuxième insertion refusée. |
| Suppression feuille | Supprimer 20 | Invariant conservé. |
| Suppression un enfant | Créer puis supprimer un nœud unaire | Enfant reconnecté. |
| Suppression deux enfants | Supprimer 50 | Successeur 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’ordre | Toutes les clés de gauche sont plus petites et toutes celles de droite plus grandes selon la politique choisie. |
| Recherche | Une comparaison par niveau ; coût O(h). |
| Insertion | Créer une feuille à la première référence NULL compatible. |
| Minimum / maximum | Suivre respectivement les références gauche / droite. |
| Successeur | Minimum du sous-arbre droit ou premier ancêtre plus grand. |
| Suppression | Trois cas : feuille, un enfant, deux enfants. |
| Parcours infixe | Produit les clés dans l’ordre croissant. |
| Performance | O(log n) si la hauteur est logarithmique ; O(n) si l’arbre dégénère. |
Glossaire
Terme | Définition |
|---|---|
| ABR | Arbre binaire respectant une propriété d’ordre sur les clés. |
| Clé | Valeur utilisée pour organiser et retrouver un enregistrement. |
| Invariant | Propriété qui doit rester vraie avant et après chaque opération. |
| Successeur | Plus petite clé strictement supérieure à une clé donnée. |
| Prédécesseur | Plus 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. |
| Doublon | Nouvelle 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. |