Arbres de recherche, tas et files de priorité
Cours · informatique (MP2I/MPI), chapitre 11 · MP2I et MPI · le début du chapitre, la suite sur Adloun
11.1 Deux invariants, deux structures
Le chapitre précédent s'est achevé sur une inégalité : la hauteur d'un arbre à nœuds est comprise entre et . Comme toutes les opérations coûtent , il ne suffit pas d'avoir un arbre : il faut y maintenir un invariant qui l'empêche de dégénérer, et qui réponde à la question qu'on lui pose.
Ce chapitre présente deux invariants, et ils sont différents parce que les questions le sont.
| Arbre binaire de recherche | Tas | |
|---|---|---|
| Invariant | gauche racine droit | racine ses deux fils |
| Question | « est-il présent ? » | « quel est le minimum ? » |
| Forme | quelconque, à équilibrer | toujours complet |
Un tas ne sait pas chercher un élément quelconque ; un arbre de recherche ne donne pas son minimum en . Le chapitre chap:abstraction l'annonçait : une structure ne répond bien qu'aux questions pour lesquelles elle est faite.
11.2 L'arbre binaire de recherche
Un arbre binaire étiqueté par un ensemble totalement ordonné est un arbre binaire de recherche si, en tout nœud d'étiquette :
- toutes les étiquettes du sous-arbre gauche sont ;
- toutes celles du sous-arbre droit sont .
Le programme note « l'importance de munir l'ensemble des clés d'un ordre total » : sans comparabilité de deux clés quelconques, la descente n'a pas de sens.
C'est la faute classique. L'arbre ci-dessous vérifie la condition en chaque nœud pris avec ses deux fils immédiats, et n'est pourtant pas un ABR :
le place bien à droite de , mais il est dans le sous-arbre gauche de , où tout doit être . Une recherche de partirait à droite et ne le trouverait jamais.
Pour tout arbre binaire de recherche , la liste infixe a est strictement croissante.
Démonstration
Par induction structurelle. Pour , la liste vide est triée.
Soit un ABR. Alors et en sont aussi, donc par hypothèse d'induction infixe g et infixe d sont triées. Le parcours infixe rend leur concaténation avec au milieu. Or toutes les étiquettes de sont et toutes celles de sont : la liste obtenue est donc croissante à la jonction comme à l'intérieur de chaque morceau.
Ce théorème fournit la manière la plus sûre de vérifier qu'un arbre est un ABR : parcourir en infixe et contrôler que la suite croît. C'est en , et cela teste l'invariant global, là où une vérification nœud par nœud laisserait passer le contre-exemple ci-dessus.
11.2.1 Rechercher, insérer
(* Renvoie true si x figure dans l'ABR a. Complexité : O(h). *)
let rec appartient x = function
| Vide -> false
| Noeud (g, e, d) ->
if x = e then true
else if x < e then appartient x g (* tout ce qui est > e est à droite *)
else appartient x d
(* Renvoie l'ABR obtenu en insérant x ; si x y figure déjà, renvoie a inchangé. *)
let rec insere x = function
| Vide -> Noeud (Vide, x, Vide) (* on insère TOUJOURS en feuille *)
| Noeud (g, e, d) as a ->
if x = e then a
else if x < e then Noeud (insere x g, e, d)
else Noeud (g, e, insere x d)
Exercices du chapitre
- Le test local ne suffit pas corrigé
- Chercher dans un tas coûte corrigé
- Fusionner deux tas : réinsérer ou reconstruire ? corrigé
- Le -ième plus petit en corrigé
- Une file de priorité sur des couples, et la diminution de clé corrigé
- Problème — La suppression dans un ABR, et la dégradation qu'elle provoque corrigé