Année 2021/2022 - L2 Informatique, UE 4TIN402U Algorithmique des structures de données arborescentes TP Noté - 19 Avril 2022 Durée 1h20mn - Aucun document papier autorisé Collège Sciences et Technologies Implémentation des Arbres vert-noirs Le sujet consiste à implémenter plusieurs procédures sur les arbres verts-noirs que nous avons vus en DS. En particulier, on va implémenter l’algorithme d’insertion. Important : Corrigé du DS disponible en ligne Certaines des fonctions demandés sont l’implémentation d’algorithmes vus dans le DS. Le corrigé de ce même DS est disponible sur Moodle et vous pouvez le consulter. Consignes Le rendu s’effectue sur Moodle : — Chaque exercice correspond a un rendu Moodle différent (auto-évalué, vous pouvez faire des tests). — Vous devez également soumettre un fichier récapitulatif contenant toutes vos fonctions. Partie 1 : Définition On commence par rappeler la définition des arbres vert-noirs. Le texte est essentiellement repris du DS. On introduit en même un type OCaml pour les représenter. Arbres binaires colorés. Un arbre binaire coloré est un arbre binaire dans lequel chaque nœud est colorié soit avec la couleur noire, soit avec la couleur vert. On donne un exemple dans la Figure 1 ci-dessous. 6 3 8 5 1 9 Figure 1 – Un arbre binaire coloré contenant six nœuds : trois sont noirs et trois sont verts On rappelle que les représentent un arbre vide : ce ne sont pas des nœuds. Pour tout arbre binaire coloré t, on note h(t) sa hauteur (par convention, la hauteur de l’arbre vide est “−1”) et s(t) sa taille (son nombre total de nœuds). On définit deux types OCaml qu’on va utiliser pour représenter les arbre coloré. Le premier sert à coder les couleurs (vert et noir), et le second les arbres colorés eux-mêmes : 1 2 type c o l o r = Green | Black type ’ a c t r e e = Empty | Node of C o l o r ∗ ’ a ∗ ’ a c t r e e ∗ ’ a c t r e e Arbres vert-noirs. On définit une mesure spécifique aux arbres binaires colorés. Pour chaque branche d’un arbre binaire coloré t, la hauteur noire de cette branche est le nombre de nœuds noirs qu’elle contient. Enfin, la hauteur noire de l’arbre coloré t, notée hn(t), est le maximum parmi les hauteurs noires de toutes ses branches. Par exemple, l’arbre t de la Figure 1, contient des branches dont les hauteurs noires sont 1, 2, et 3. Il a donc lui-même pour hauteur noire hn(t) = 3. On notera que par définition, la hauteur noire de l’arbre vide est hn( ) = 0. Définitions des arbres verts-noirs Les arbres vert-noirs sont des arbres binaires colorés spéciaux (en particulier, ce sont des ABRs). Plus précisément, un arbre vert-noir est un arbre binaire coloré t qui satisfait les trois conditions suivantes : (a) t est un arbre binaire de recherche. (b) Pour tout nœud x de t, si g est le sous-arbre gauche de x et d est son sous-arbre droit, alors hn(g) = hn(d) (en d’autres termes, g et d ont la même hauteur noire). (c) Tous les nœuds verts de t sont soit sa racine, soit le fils gauche d’un nœud noir. On donne un exemple dans la Figure 1 ci-dessous (à l’inverse, l’arbre coloré de la Figure 1, n’est pas vert-noir) 7 4 2 9 6 8 Figure 2 – Un arbre vert-noir Fonction 1 Test des propriétés d’un arbre vert-noir Écrire une fonction is_greenblack : ’a ctree −> bool qui prend en entrée un arbre coloré et retourne true si celui-ci est vert-noir et false sinon. Attention, la fonction devra tester les trois propriétés dans la définition (en particulier, il faut tester si l’arbre pris en entrée est un ABR). Remarque : Pour cette question et toutes les suivantes, vous avez le droit de réutiliser/modifier des fonctions que vous avez codé lors des TP au cours du semestre. Partie 2 : Insertion On va maintenant se concentrer sur l’implémetation de l’insertion dans les arbres vert-noirs. Comme vu dans le DS, la procédure est basée sur une notion intermédiaire : les arbres quasi -vert-noirs. Commençons par rappeler la définition. De façon informelle, un arbre quasi-vert-noir est un arbre coloré qui a des propriétés moins fortes qu’un “vrai” arbre vert-noir : il satisfait les deux premières conditions dans la définition des arbres vert-noirs, mais il peut contenir au plus un nœud vert qui ne satisfait pas la troisième condition. Définitions des arbres quasi-verts-noirs Un arbre quasi-vert-noir est un arbre binaire coloré t qui satisfait les trois conditions suivantes : (a) t est un arbre binaire de recherche. (b) Pour tout nœud x de t, si g est le sous-arbre gauche de x et d est son sous-arbre droit, alors hn(g) = hn(d) (en d’autres termes, g et d ont la même hauteur noire). Fonction 2 (c) Il existe au plus un nœud vert de t qui n’est ni la racine, ni le fils gauche d’un nœud noir. Test des propriétés d’un arbre quasi-vert-noir Écrire une fonction is_quasigreenblack : ’a ctree −> bool qui prend en entrée un arbre coloré et retourne true si celui-ci est quasi-vert-noir et false sinon. Rappel : Corrigé du DS disponible en ligne Le corrigé peut se montrer utile pour les trois questions qui vont suivre. On reprend maintenant les arbres quasi-vert-noirs élémentaires. On rappelle que les trois premiers types sont les suivants : c b a c a t4 t3 a t4 b t1 b t1 t2 t3 Type 3 t1 t2 t2 Type 1 t3 Type 2 Figure 3 – Arbres quasi-vert-noirs de rang 1, 2 et 3. Fonction 3 Réparation d’un quasi-vert-noir de type 1, 2 ou 3 Écrire une fonction qgb_repair123 : ’a ctree −> ’a ctree qui prend en entrée un arbre coloré t. Si l’arbre t est quasi-vert-noir de type 1,2 ou 3, la fonction devra retourner un “vrai” arbre vert-noir contenant le même ensemble de clés et de même hauteur noire. Dans tous les autres cas, le fonction devra simplement retourner t lui-même. On demande ici une fonction dont la complexité est constante. On rappelle que les deux autres types sont les suivants : a b a b t1 t2 t3 Type 4 t1 t3 t2 Type 5 Figure 4 – Arbres quasi-vert-noirs de rang 4 et 5 Fonction 5 Fonction 4 Réparation d’un quasi-vert-noir de type 4 ou 5 Écrire une fonction qgb_repair45 : ’a ctree −> ’a ctree qui prend en entrée un arbre coloré t. Si l’arbre t est quasi-vert-noir de type 4 ou 5, la fonction devra retourner un “vrai” arbre vert-noir contenant le même ensemble de clés et dont la hauteur noire a été incrémentée de “1”. Dans tous les autres cas, le fonction devra simplement retourner t lui-même. On demande ici une fonction dont la complexité est constante. Insertion dans un arbre vert-noir Écrire une fonction qgb_insert : ’a ctree −> ’a −> ’a ctree qui prend en entrée un arbre vert-noir t et une clé k. Elle doit retourner un nouvel arbre vert-noir obtenu en insérant la clé k dans t. Vous pouvez (devez) bien sûr utiliser les fonctions des deux exercices précédents comme sous-procédure. Partie 3 : Création d’arbres vert-noirs Fonction 6 On veut maintenant utiliser notre fonction d’insertion pour créer des arbres vert-noirs. On va d’abord commencer par la création à partir d’une liste. Création d’un arbre vert-noir à partir d’une liste Écrire une fonction list_to_gb : ’a list −> ’a ctree qui prend en entrée une liste et retourne un arbre vert-noir dont les clés sont exactement les éléments présents dans la liste (si celle-ci contient un élément deux fois ou plus, on ne garde qu’un seule copie). On cherche maintenant à convertir un arbre coloré quelconque en arbre vert-noir. Pour cela, on va écrire une fonction qui convertit un arbre en liste (il suffit de combiner cette fonction avec celle de l’exercice précédent). On demande deux versions. La première est simple mais peu efficace car elle utilise la concaténation de listes. Fonction 7 Liste des étiquettes d’un arbre (version lente) Écrire une fonction get_keys : ’a ctree −> ’a list qui prend en entrée un arbre coloré et retourne la liste des clés qu’il contient dans l’ordre infixe. L’ordre infixe est défini récursivement. Si l’arbre est vide, la liste de ses clés est vide. Sinon, on commence par lister les clés dans le sous-arbre gauche, puis celle qui étiquette la racine, et enfin celles qui se trouvent dans le sous-arbre droit. Par exemple sur l’arbre de la figure 2, la liste obtenue est [2; 4; 6; 7; 8; 9]. Dans cette version, on pourra utiliser l’opérateur “@” de concaténation de listes. Fonction 8 Transformation en un arbre vert-noir (version rapide) Écrire une fonction get_keys_fast : ’a ctree −> ’a list qui prend en entrée un arbre coloré et retourne la liste des clés qu’il contient dans l’ordre infixe sans utiliser la concaténation de liste. On pourra utiliser une fonction auxiliaire get_keys_forest : ’a ctree list −> ’a list qui prend en entrée une liste d’arbre colorés a retourné la liste des clés des arbres contenus dans celle-ci dans l’ordre infixe. Fonction 9 Pour finir on va utiliser les arbres vert-noirs pour programmer un tri. Tri vert-noir Écrire une fonction gb_sort : ’a list −> ’a list qui prend en entrée une liste et retourne une version triée de celle-ci en ayant éliminé les copies multiples d’une même clé. La fonction devra être écrite en combinant celles des exercices précédents.