Université Paris Diderot – Paris 7 L3 Informatique Algorithmique Année 2010-2011, 1er semestre TD n◦2 Arbres Binaire de Recherche Le type de donné “arbre" sera utilisé pour indiquer l’ensemble de toutes les Arbres Binaires Étiquetés (ABEs) par des clés de type entier. La taille de un ABE a est par définition le nombre de clés contenues dans a. Nous rappelons que un Arbres Binaire de Recherche (ABR) a est un ABE tel que tout nœud interne b de a contient un clé – supérieure ou égale à toutes le clés contenues dans le sous-arbre gauche de b ; – inférieure strictement à toutes le clés contenues dans le sous-arbre droit de b. Exercice 1 Est-ce que on peut utiliser la procédure suivante pour tester si un ABE a est un ABR ? 1 2 3 4 Fonction estABR(a : arbre) : booléen début si (estVide(a)) alors retourner vrai; si (estVide(G(a))) alors gauche := clé(a); 5 6 sinon gauche := clé(G(a)); 7 8 si (estVide(D(a))) alors droite := clé(a); 9 10 sinon droite := clé(D(a)); 11 12 retourner (gauche ≤ clé(a) ≤ droite ∧ estABR(G(a)) ∧ estABR(D(a))); 13 14 fin Sinon écrivez une fonction qui teste si un ABE a est un ABR. Pour un tableau A[1, . . . , n] la définition de “k-ème élément" est très simple à comprendre et l’accès au k-ème élément est une opération élémentaire (c’est à dire, avec complexité Θ(1)). Au contraire un arbre binaire n’est pas une structure linéaire et nous pouvons definire plusieur notions de “k-ème élément", selon la facon dans laquelle nous parcourons l’arbre. 1 Étant donné un ABE quelconque on choisit la façon suivante de numéroter les nœuds de l’arbre : Fig. 1 – Numérotation des nœuds d’un ABE Exercice 2 [Accès au k-ème élément] Soit a un ABR. Question 1. Proposez une méthode pour retourner le k-ème élément de a en utilisant : – une procédure VisiteGRD(a : arbre) qui parcourt complètement l’arbre a. – un tableau d’entiers T . Quelle est la complexité de cette méthode en fonction de la taille de a ? Question 2. En supposant d’avoir à disposition le type de donnée booléen × entier, proposez une fonction RecherchePos(a : arbre, n : entier) : booléen×entier telle que si (b, k) = RecherchePos(a, n) alors – si la taille de a est inférieure à n alors b = faux et k est la taille de a ; – si la taille de a n’est pas inférieure à n alors b = vrai et k est la valeur de la k-ème clé. Quelle est la complexité de cette méthode ? Question 3. En supposant qu’on dispose d’une fonction taille(a : arbre) : entier calculant la taille d’un arbre a en Θ(1), proposez une fonction RecherchePos(a : arbre, k : entier) : arbre telle que si b = RecherchePos(a, k) alors – si taille(a) < n, alors b = ArbreVide() ; – si taille(a) ≥ n, alors clé(b) est la k-ème clé dans l’arbre a. Évaluez la complexité de la procédure en fonction de la hauteur de l’arbre a. Question 4. En acceptant de modifier légèrement la structure des ABRs, pouvez-vous proposer une fonction taille(a : arbre) : entier ayant complexité Θ(1) ? Vérifierez que votre modification ne change pas la complexité des fonctions d’insertion et de suppression d’un nœud dans un ABR. Exercice 3 [Recherche du successeur] Modifiez légèrment la définition de ABR de telle sorte que toutes les clés soyent distinctes. On appelle strict un ABR qui satisfait cette définition. Soit a un ABR strict. Le successeur de un nœud x (s’il existe) est par définition le nœud y ayant la plus petit clé entre le clés plus grand que clé(x). Question 1. Montrer rigoureusement que dans a : (a) l’élément minimum se trouve à un nœud sans fils gauche. (b) si un nœud a un fils droit, son successeur est le minimum de son sous arbre droit. En déduire que si un nœud a un fils droit, alors son successeur n’a pas de fils gauche. (c) si un nœud n’a pas de fils droit, son successeur, s’il existe, est le premier de ses ancètres dont le fils gauche est aussi l’un de ses ancètres. Question 2. Écrire une fonction succ(b : arbre) : arbre qui retourne le sous arbre de a dont la racine est le successeur de b. Quelle est la complexité en temps de cet algorithme ? 2 Exercice 4 Soit a un ABR strict, soient x un nœud feuille et y son parent. Montrer que clé(x) est soit la plus petite clé de a supérieure à clé(y), soit la plus grande clé de a inférieure à clé(y). Exercice 5 On peut trier un tableau T de nombres entiers en commençant par construire par insertions successives un ABR contenant ces nombres puis en effectuant un parcours infixe de l’arbre. Quels sont les temps d’exécution de cet algorithme en fonction de la taille de T dans le pire et dans le meilleur des cas ? Exercice 6 [Insertion à la racine] Dans un arbre binaire de recherche, avec la méthode d’insertion classique, toutes les nouvelles valeurs sont placées aux feuilles de l’arbre. Si l’on souhaite accéder à un nœud inséré récemment dans l’arbre, il faudra parcourir toute la hauteur de l’arbre. Dans certaines applications, on souhaite accéder plus fréquemment aux derniers éléments insérés. Il s’agit du principe LRU 1 . Dans ce cas particulier, il peut être intéressant d’insérer à la racine. En procédant de la sorte, les valeurs auxquelles on souhaite accéder le plus souvent ont plus de chance d’être à une faible profondeur. En considérant l’exemple de la figure ?? : Question 1. Tracez le chemin qui va de la racine au nœud où classiquement il faudrait insérer le nœud 33. Question 2. À partir des réponses aux questions précédentes, proposez une procédure insertionRacine(a : arbre, k : entier) d’insertion à la racine dans un ABR. Évaluer la complexité de cet algorithme dans le pire des cas. Fig. 2 – un arbre binaire de recherche 1 pour Least Recently Used ! 3