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