TD 2 : Arbres Rouge-Noir
Transcription
TD 2 : Arbres Rouge-Noir
TD 2 : Arbres Rouge-Noir Lycée Faidherbe 2014-2015 1 Introduction Les arbres binaires de recherche permettent de représenter des ensembles d’éléments pour lesquels on dispose d’une relation d’ordre. Les opérations de base sont effectuées en temps linéaire par rapport à la hauteur de l’arbre. Ces opérations sont donc efficaces si les arbres considérés sont bien équilibrés : leur temps d’exécution est alors logarithmique par rapport au nombre d’éléments de l’arbre. Cependant, si la hauteur de l’arbre est grande, leur performance peut ne pas être meilleure que pour une liste chaînée (i.e. linéaire en le nombre d’éléments). Un arbre rouge-noir est un arbre binaire de recherche donc chaque nœud contient une information supplémentaire, sa couleur, qui peut valoir soit rouge soit noir. En contrôlant la manière dont les nœuds sont colorés sur n’importe quel chemin allant de la racine à une feuille, les arbres rouge et noir garantissent qu’aucun des ces chemins n’est plus de deux fois plus long que n’importe quel autre, ce qui rend l’arbre approximativement équilibré. 2 Définition Nous représenterons en Caml les arbres rouge et noir grâce aux types suivants : type couleur = Rouge | Noir ;; type ’a arbreRN = Vide| N of couleur * ’a arbreRN * ’a * ’a arbreRN;; Un objet de type’a arbreRN représente un arbre binaire dont les nœuds sont colorés en rouge ou en noir et portent des étiquettes de type ’a. On supposera que l’on dispose d’une relation d’ordre sur ces éléments. Un tel arbre est dit de recherche si et seulement si pour tout nœud étiqueté par l’élément x, tous les éléments présents dans le sous-arbre gauche sont inférieurs à x et tous ceux du sous-arbre droit sont supérieurs à x. Un arbre binaire de recherche est un arbre rouge et noir s’il satisfait les deux propriétés suivantes : 1. Si un nœud est rouge alors ses fils sont noirs. 2. Depuis un nœud fixé toutes les branche reliant ce nœud à une feuille contiennent le même nombre de nœuds noirs. Option informatique, MP* Lycée Faidherbe Voici un exemple d’arbre rouge et noir, les nœuds noirs sont grisés : 22 13 28 18 11 31 16 Exercice 1 Écrivez une fonction mem qui cherche si un élément est présent dans un arbre rouge et noir. val mem: ’a -> ’a arbreRN -> bool Exercice 2 Écrivez une fonction verifRN qui teste si un arbre coloré vérifie la propriété 1, i.e. que tout fils d’un nœud rouge est noir. val verifRN: ’a arbreRN -> bool La hauteur noire hn(t) d’un arbre rouge et noir t est le nombre de nœuds noirs présents dans un chemin quelconque descendant de sa racine à n’importe quelle feuille. Exercice 3 Écrivez une fonction hauteurN qui calcule la hauteur noire d’un objet de type ’a arbreRN. Dans le cas où cette hauteur n’est pas définie (parce que l’arbre de vérifie pas la propriété 2), vous lèverez une exception. val hauteurN: ’a arbreRN -> int 3 Insertion d’un élément Le principe de l’insertion d’un élément x dans un arbre rouge et noir doit maintenir les conditions. On effectue tout d’abord une insertion en procédant comme pour un arbre binaire de recherche simple. Un nœud est donc créé à la place d’une feuille, à une position choisie de manière à respecter l’ordre entre éléments. On colorie ce nouveau nœud en rouge, ce qui permet de préserver la propriété 2. On rappelle la fonction d’insertion aux feuilles dans un arbre binaire de recherche : let rec simple_insert x = function |Vide -> N (Rouge, Vide, x, Vide) |N (c, t1, y, t2) -> if x < y then N(c, simple_insert x t1, y, t2) else N(c, t1, y, simple_insert x t2);; 2 TD 2 : Arbres Rouge-Noir Lycée Faidherbe Option informatique, MP* Ainsi, après cette première étape, seule la propriété 1 peut être violée : il se peut en effet que le père du nœud introduit soit lui aussi rouge : on dit qu’il y a conflit rouge. Nous allons essayer de régler ce conflit, il se peut alors que le conflit ”remonte” dans l’arbre. Voici, selon que les nœuds rouges successifs sont fils droit ou gauche les 4 possibilités d’apparition d’un conflit rouge dans un sous-arbre. a3 a3 a2 a1 t4 t4 a1 a2 t3 t1 t1 t2 t2 a1 t3 a1 a3 a2 t1 t1 a3 a2 t4 t2 t3 t2 t3 t4 t1 , t2 , t3 et t4 sont des arbres qui vérifient les propriétés 1 et 2 et ont la même hauteur noire. L’idée est alors de réarranger la structure de l’arbre en même temps que l’on remonte les appels récursifs en changeant astucieusement les nœuds et leurs couleurs de manière à remonter ce conflit tout en maintenant la propriété 2. Si on parvient à un conflit rouge à la racine il suffira d’imposer la couleur noire à la racine. Exercice 4 Écrivez une fonction racineNoire qui colore en noir la racine d’un arbre. val racineNoire: ’a arbreRN -> ’a arbreRN Exercice 5 Montrer que les 4 configurations ci-dessus peuvent se ré-arranger en arbre qui vérifie les propriétés 1 et 2 et qui a conservé la hauteur noire. Cet arbre aura le nœud a2 en racine, de couleur rouge. Exercice 6 TD 2 : Arbres Rouge-Noir 3 Option informatique, MP* Lycée Faidherbe Écrivez une fonction equilibreRN qui prend pour argument un objet de type ’a arbreRN. S’il s’agit d’un des 4 arbres ci-dessus la fonction réarrangera l’arbre comme dans la question précédente. Dans tous les autres cas, elle rendra l’arbre inchangé. val equilibreRN: ’a arbreRN -> ’a arbreRN Exercice 7 Écrire une fonction insertion en adaptant simple_insert de manière à résoudre les conflits lors de la remontée à l’aide de la fonction equilibreRN. val insertion: ’a -> ’a arbreRN -> ’a arbreRN 4 Suppression La suppression dans un arbre binaire de recherche se ramène toujours à la suppression d’une feuille : si l’élément à supprimer est porté par un nœud interne, on permute celui-ci avec le plus petit élément du sous-arbre droit ou le plus grand du sous-arbre gauche. La suppression d’une feuille préserve naturellement la propriété 1. Cependant, elle peut contredire la propriété 2 en introduisant un déséquilibre dans l’arbre si le nœud supprimé est noir. Les opérations que l’on va effectuer peuvent propager le déséquilibre : on devra gérer un déséquilibre sous la forme d’un nœud ayant deux fils qui sont des arbres rouge-noir mais de hauteurs noires différentes de 1. 1. Le premier cas est celui d’un nœud rouge : dans ce cas le fils du sous-arbre le plus haut en noir est noir et il suffit d’échanger les couleurs pour obtenir un arbre rouge-noir de hauteur noire rétablie. a1 -→ a1 a2 a2 t1 t1 t3 t2 t3 t2 Ici t1 , t2 et t3 sont des arbres rouge-noir de même hauteur noire. 2. Si le nœud est noir et le nœud du fils haut est noir aussi il suffit de changer ce dernier en rouge, on obtient alors un arbre rouge-noir mais sa hauteur noire correspond à la hauteur diminuée, il faudra gérer le déséquilibre au niveau supérieur. a1 -→ a1 a2 a2 t1 t1 t2 t3 t2 t3 t1 , t2 et t3 sont toujours des arbres rouge-noir de même hauteur noire. 4 TD 2 : Arbres Rouge-Noir Lycée Faidherbe Option informatique, MP* 3. Le dernier cas est celui d’un nœud noir pour lequel la racine du fils haut est rouge. Dans ce cas les petits fils sont de hauteur noire au moins un donc sont non vides et ont une racine noire. a1 a3 t1 a2 a4 t3 t2 t5 t4 t1 , t2 , t3 , t4 et t5 sont toujours des arbres rouge-noir de même hauteur noire. Une transformation qui restitue la hauteur noire est a3 a1 a4 a2 t1 t4 t2 t5 t3 On voit qu’en fait le nœud de racine a4 est inchangé. Dans toutes les configurations il y a la possibilité de parvenir à un conflit rouge qu’il faudra traiter Exercice 8 Écrire deux fonctions equilibreG, resp. equilibreD, qui rééquilibre un arbre dont le fils gauche, resp. droit, a une hauteur noire lacunaire de 1. On renverra un couple (arbre, booléen) formé de l’arbre équilibré et d’une variable siginfiant que l’arbre obtenu est encore lacaunaire. val equilibreG: ’a arbreRN -> ’a arbreRN*bool val equilibreD: ’a arbreRN -> ’a arbreRN*bool Exercice 9 Écrire une fonction supprimant un élément dans un arbre rouge-noir. On pourra s’inspirer de la fonction enlever des arbres binaires de recherche TD 2 : Arbres Rouge-Noir 5 Option informatique, MP* Lycée Faidherbe Solutions possibles Solution de l’exercice 1 La recherche dans un arbre rouge-noir s’effectue comme dans un arbre binaire de recherche, les couleurs n’intervenant pas. let rec mem x = function |Vide -> false |N(_,t1,y,t2) -> if x = y then true else if x < y then mem x t1 else mem x t2;; Solution de l’exercice 2 On recherche la présence de deux nœuds rouges successifs à la racine puis récursivement. let rec verifRN = function |Vide -> true |N(Rouge, N (Rouge, _, _, _), _, _) -> false |N(Rouge, _, _, N (Rouge, _, _, _)) -> false |N(_, t1, _, t2) -> verifRN t1 && verifRN t2;; Solution de l’exercice 3 On calcule récursivement et on compare les hauteurs noires des fils. On ajoute 1 à la valeur commune si la racine est noire. On peut alors rattraper l’éventuelle exception dans une fonction de test. exception hauteurNoire;; let rec hauteurN = function |Vide -> 0 |N(c, t1, _, t2) -> let h1 = hauteurN t1 in let h2 = hauteurN t2 in if h1 <> h2 then raise hauteurNoire else if c = Noir then 1 + h1 else h1;; let verifHN t = try let h = hauteurN t in true with hauteurNoire -> false;; Solution de l’exercice 4 let racineNoire = function |Vide -> Vide |N(_, t1, y, t2) -> N(Noir, t1, y, t2);; Solution de l’exercice 5 6 TD 2 : Arbres Rouge-Noir Lycée Faidherbe Option informatique, MP* a2 a3 a1 t1 t2 t3 t4 Solution de l’exercice 6 On détecte les quatres cas de conflits à l’aide d’un pattern-matching sur la structure de l’arbre. let equilibreRN = function |N(Noir, N(Rouge, N(Rouge, t1, x1, t2), x2, t3), x3, t4) N(Rouge, N(Noir, t1, x1, t2), x2, N(Noir, t3, x3, t4)) |N(Noir, N(Rouge, t1, x1, N(Rouge, t2, x2, t3)), x3, t4) N(Rouge, N(Noir, t1, x1, t2), x2, N(Noir, t3, x3, t4)) |N(Noir, t1, x1, N(Rouge, N(Rouge, t2, x2, t3), x3, t4)) N(Rouge, N(Noir, t1, x1, t2), x2, N(Noir, t3, x3, t4)) |N(Noir, t1, x1, N(Rouge, t2, x2, N(Rouge, t3, x3, t4))) N(Rouge, N(Noir, t1, x1, t2), x2, N(Noir, t3, x3, t4)) |t -> t;; -> -> -> -> Solution de l’exercice 7 La fonction aux effectue l’insertion comme simple_insert, mais traite les conflits lors de la remonté à l’aide de la fonction conflict. La fonction insertion effectue un appel à aux et s’assure que la racine de l’arbre obtenu est bien noire. let insertion x t = let rec aux x = function |Vide -> N (Rouge, Vide, x, Vide) |N (c, t1, y, t2) -> if x < y then equilibreRN (N (c, aux x t1, y, t2)) else equilibreRN (N (c, t1, y, aux x t2)) in racineNoire (aux x t);; Solution de l’exercice 8 let equilibreG= function |N(Rouge, t1, a1, N(Noir, t2, a2, t3)) -> equilibreRN(N(Noir, t1, a1, N(Rouge, t2, a2, t3))),false |N(Noir, t1, a1, N(Noir, t2, a2, t3)) -> equilibreRN(N(Noir, t1, a1, N(Rouge, t2, a2, t3))),true |N(Noir, t1, a1, N(Rouge, N(Noir, t2, a2, t3), a3, t4)) -> equilibreRN(N(Noir,N(Noir,t1,a1,N(Rouge,t2,a2,t3)),a3,t4)),false |t -> t,false;; let equilibreD= function |N(Rouge, N(Noir, t1, a1, t2), a2, t3) -> equilibreRN(N(Noir, N(Rouge, t1, a1, t2), a2, t3)),false |N(Noir, N(Noir, t1, a1, t2), a2, t3) -> equilibreRN(N(Noir, N(Rouge, t1, a1, t2), a2, t3)),true |N(Noir, N(Rouge, t1, a1, N(Noir, t2, a2, t3)), a3, t4) -> equilibreRN(N(Noir,t1,a1,N(Noir,N(Rouge,t2,a2,t3),a3,t4))),false |t -> t,false;; TD 2 : Arbres Rouge-Noir 7 Option informatique, MP* Lycée Faidherbe Solution de l’exercice 9 let rec max = function |Vide -> raise(Failure "Arbre vide") |N(_,_,n,Vide) -> n |N(_,_,_,d) -> max d;; let rec supprMax = function |Vide -> (Vide,false) |N(c,g,_,Vide) -> if c = Noir then (g,true) else (g,false) |N(c,g,n,d) -> let (t,b) = supprMax d in if b then equilibreD(N(c,g,n,t)) else (equilibreRN(N(c,g,n,t)),false);; let enleverRacine = function |Vide -> (Vide,false) |N(c,g,n,Vide) -> if c = Noir then (g,true) else (g,false) |N(c,g,n,d) -> let r = max g in let (t,b) = supprMax g in if b then equilibreG(N(c,t,r,d)) else (equilibreRN(N(c,t,r,d)),false);; let enlever x t = let rec aux x = function |Vide -> (Vide,false) |N(c,g,n,d) as arbre -> if (n = x) then enleverRacine arbre else if (x < n) then (let (tt,b) = aux x g in if b then equilibreG(N(c,tt,n,d)) else (equilibreRN(N(c,tt,n,d)),false)) else (let (tt,b) = aux x d in if b then equilibreD(N(c,g,n,tt)) else (equilibreRN(N(c,g,n,tt)),false)) in let (tt,b) = aux x t in racineNoire tt;; 8 TD 2 : Arbres Rouge-Noir