Programmation Fonctionnelle Avancée – Master 1 TP 2

publicité
Programmation Fonctionnelle Avancée – Master 1
TP 2
Mehdi Dogguy
On appelle arbre AVL (Adelson-Velskii et Landis) un arbre binaire de recherche globalement équilibré, i.e. la différence entre la hauteur du sous-arbre
gauche et droite est au plus égale à 1.
En Haskell, une structure d’arbre dont les éléments sont de type a peut être
définie de la manière suivante :
data Tree a =
Empty | Node a ( Tree a ) ( Tree a ) d e r i v i n g Show
Exercice 1 :
Un arbre binaire de recherche
Implémentez les fonctions suivantes :
1. empty :: Tree a -> Bool qui renvoie vrai quand l’arbre donné en argument est vide, et faux sinon.
2. depth :: Tree a -> Int qui calcule la hauteur d’un arbre.
3. search :: Ord a => Tree a -> a -> Bool qui renvoie vrai quand
l’élément de type a passé en argument apparaı̂t dans l’arbre.
(⋆) Gardez en tête que tous les élément dans le sous-arbre gauche sont
inférieurs à la racine, et ceux du sous-arbre droit sont supérieurs.
4. path :: Ord a => Tree a -> a -> [a] qui renvoie le chemin à suivre
depuis la racine pour trouver l’élément recherché.
5. insert :: Ord a => Tree a -> a -> Tree a qui insère un nouvel
élément dans l’arbre, et qui ne fait rien si l’élément y est déjà.
Exercice 2 :
Un arbre AVL
Notez que la fonction d’insertion définie dans l’exercice précédent ne
préserve pas l’équilibrage d’un arbre. Pour pouvoir fournir une implémentation
d’insértion correcte pour les arbres AVL, il est utile de définir quelques rotations
d’arbre.
1. Implémentez delta :: Tree a -> Tree a -> Int qui calcule la
différence entre la hauteur des deux arbres passés en arguments.
2. Implémentez le prédicat balanced :: Tree a -> Bool qui renvoit vrai
quand l’arbre donné en argument est équilibré, et faux sinon.
Il existe deux rotations simples : la rotation gauche et la rotation droite. On
effectue une rotation gauche quand le sous-arbre gauche est plus haut (i.e. le
delta est égal à 2) que le sous-arbre droit. Ansi, la transformation effectuée
peut être représentée par la figure suivante :
se transforme en
A
B
B
BG
C
BG
BD
A
BD
C
La rotation droite est l’opération inverse (et est définie de façon symétrique).
2. Définissez la fonction balanceL :: Tree a -> Tree a qui effectue la rotation gauche.
3. Définissez la fonction balanceR :: Tree a -> Tree a qui effectue la rotation droite.
Il existe les double-rotations gauche-droite et droite-gauche. La transformation effectuée par une rotation gauche-droite est représentée ci-dessous.
se transforme en
A
B
BG
BD
C
B
A
BD
DG
DD
BG
DG
DD
C
4. Définissez la fonction balanceLR :: Tree a -> Tree a qui effectue la
rotation gauche-droite.
5. Déduisez la fonction balanceRL :: Tree a -> Tree a qui effectue la rotation droite-gauche.
En utilisant ces rotations, implémentez les fonctions suivantes :
6. insert :: Ord a => Tree a -> a -> Tree a qui insère un élément de
type a dans l’arbre, tout en préservant l’équilibrage. L’algorithme est assez
simple : Suivant la valeur de l’élément e à insérer et celle de la racine, on
sait où insérer e.
Considérons l’arbre Tree r g d où e < r et g’ = insert g e. Si g’ est
plus haut que d (i.e. delta g’ d > 2), alors un équilibrage est nécessaire :
Si e est plus grand que la racine de g, alors on effectue une rotation gauche
et sinon une rotation gauche-droite. L’autre cas (i.e. insertion à droite)
est symétrique.
7. load :: Ord a => Tree a -> [a] -> Tree a qui construit un arbre à
partir d’une liste d’éléments.
8. Déduisez une manière de trier une liste d’éléments et implémentez la fonction sort :: Ord a => [a] -> [a]
Téléchargement