Adloun

Probleme – La suppression dans un ABR, et la dégradation qu'elle provoque

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 11 — Arbres de recherche, tas et files de priorité

Énoncé

Le chapitre donne la recherche et l'insertion, jamais la suppression.

Corrigé

1. Les trois cas.


(* Renvoie le minimum de l'arbre. Précondition : a n'est pas vide. *)
let rec minimum = function
  | Vide -> failwith "arbre vide"
  | Noeud (Vide, e, _) -> e            (* le minimum est TOUT À GAUCHE *)
  | Noeud (g, _, _) -> minimum g

(* Renvoie l'ABR privé de x. Si x est absent, renvoie l'arbre inchangé.
   Précondition : a est un ABR. Complexité : O(h). *)
let rec supprime x = function
  | Vide -> Vide
  | Noeud (g, e, d) ->
      if x < e then Noeud (supprime x g, e, d)
      else if x > e then Noeud (g, e, supprime x d)
      else match g, d with
        | Vide, _ -> d                 (* (a) et (b) : au plus un fils *)
        | _, Vide -> g
        | _, _ ->                      (* (c) deux fils : le SUCCESSEUR remonte *)
            let s = minimum d in
            Noeud (g, s, supprime s d)

(a) Feuille : on rend Vide. (b) Un seul fils : on rend ce fils — les deux premiers motifs traitent les deux cas d'un coup. (c) Deux fils : on ne peut supprimer le nœud sans le remplacer, et le seul remplaçant valide est le successeur — le plus petit du sous-arbre droit — ou le prédécesseur. On le remonte, puis on le supprime de sa position d'origine ; ce second appel tombe forcément dans le cas (a) ou (b), puisque le minimum d'un arbre n'a pas de fils gauche.

Préservation de l'invariant (cas (c), les autres étant immédiats). Soit le minimum de . Toutes les étiquettes de sont , donc : l'invariant tient à gauche. Toutes celles de sont par minimalité de : il tient à droite. Terminaison : chaque appel descend d'un niveau, le variant est la hauteur du sous-arbre. Complexité : pour la descente, plus pour le minimum et la suppression secondaire, soit .

Mesuré sur : retirer (feuille), (un fils), (deux fils) ou (absent) rend à chaque fois un ABR valide, contrôlé par la croissance du parcours infixe.

2. Ce qu'on peut craindre. Le procédé prend toujours dans le sous-arbre droit. Supprimer un nœud à deux fils allège donc systématiquement la droite et laisse la gauche intacte. Répété, ce biais doit déséquilibrer l'arbre vers la gauche — et rien dans la structure ne le corrige, puisqu'un ABR nu ne se rééquilibre jamais.

3. La mesure. On part d'un ABR de clés insérées en ordre aléatoire, puis on exécute couples « supprimer une clé au hasard, la réinsérer ». La taille reste à chaque instant — vérifié. Mesuré :

profondeur moyenneaprès Hibbardvariante symétrique

La crainte était fondée. À , la profondeur moyenne passe de à — l'arbre est devenu presque deux fois plus profond, et la hauteur maximale de à . La variante symétrique — qui tire à pile ou face entre successeur et prédécesseur — reste à , c'est-à-dire sous sa valeur de départ. La correction tient en une ligne :


| _, _ ->
    if Random.bool ()
    then let s = minimum d in Noeud (g, s, supprime s d)         (* successeur *)
    else let p = maximum g in Noeud (supprime p g, p, d)         (* prédécesseur *)

La théorie prédit que la profondeur moyenne sous suppression asymétrique croît en — ce qui donnerait pour à la limite ; nos opérations en montrent la moitié du chemin, et la tendance est nette.

La leçon. Une opération correcte peut détruire une propriété qu'aucune de ses postconditions ne mentionne. supprime rend toujours un ABR valide — sa spécification est respectée à la lettre, à chaque appel. Ce qu'elle dégrade est la forme, dont on n'a rien promis, et dont dépend pourtant toute la complexité. C'est précisément pour ne plus dépendre d'une forme non spécifiée que l'on passe à l'arbre bicolore, où l'équilibrage fait partie du contrat.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.