Programmation fonctionnelle : TP5
Exercice 1 [Arbres binaires]
Chaque nœud d'un arbre polymorphe possède une valeur, un
sous-arbre gauche et un sous-arbre droit.
- Définir bintree le type des arbres binaires
polymorphes
- Écrire la fonction values: 'a bintree -> 'a list qui
renvoie l'ensemble des valeurs présentes dans un arbre (avec
doublons). Les valeurs apparaîtront dans l'ordre suivant : racine,
sous-arbre gauche puis sous-arbre droit. Vous définirez et utiliserez
une fonction auxiliaire afin d'éviter les concaténations de liste.
- Écrire la fonction map_tree: ('a -> 'b) -> 'a bintree -> 'b
bintree qui renvoie un arbre dans lequel toutes les valeurs ont
été remplacées par leur image par la fonction donnée en premier
argument.
- Écrire la fonction fold_tree: ('a -> 'b -> 'b) -> 'a bintree
-> 'b -> 'b qui est la fonction équivalente à
List.fold_right pour les arbres binaires. L'exploration de
l'arbre est faite dans l'ordre suivant : sous-arbre droit, racine puis
sous-arbre gauche.
Exercice 2 [Arbres binaires de recherche]
- Définir abr le type des arbres binaires de recherche
polymorphes.
- Donner des constructeurs intelligents pour le type
abr. Ces constructeurs devront permettre de respecter la
structure d'abr. On utilisera la fonction de comparaison générique
Pervasives.compare pour les comparaisons.
- Écrire la fonction values: 'a bintree -> 'a list qui
renvoie l'ensemble des valeurs présentes dans un arbre (avec
doublons). Les valeurs apparaîtront dans l'ordre suivant : racine,
sous-arbre gauche puis sous-arbre droit. Vous définirez et utiliserez
une fonction auxiliaire afin d'éviter les concaténations de liste.
- Écrire la fonction de recherche d'une valeur dans un abr. Cette
fonction aura le type 'a -> 'a abr -> bool.
- Redéfinir les fonctions map_tree et fold_tree
pour les abr.
- On appelle coupure d'un abr a suivant une valeur
v la séparation de cet abr en deux abr a1 et
a2 tels que tous les éléments de a1 sont inférieurs
ou égaux à v et tous ceux de a2 sont strictement
supérieurs à v et tels que le multi-ensemble des éléments de
a1 et a2 est celui des éléments de a.
Écrire une fonction coupure permettant de réaliser la
coupure d'un abr suivant une valeur. Cette fonction ne devra parcourir
qu'une (partie) d'une branche de l'abr.
- Proposer une fonction de fusion de deux abr utilisant la fonction
de coupure.
- Proposer une fonction permettant de retirer un élément d'un
abr. Cette fonction retournera l'arbre passé en argument si la valeur
n'est pas présente dans cet arbre.
- L'un des problèmes majeurs des abr est leur tendance à dégénerer
en liste (entraînant un accroissement de complexité à l'ajout et lors
de la recherche).
Proposer une fonction create : int -> int
abr permettant de créer un abr résultant de l'ajout des entiers
entre 0 et n (où n est le paramètre de la fonction) dans cet ordre
(moralement create n = add n (add (n-1) .... (add 0 empty))).
Tester cette fonction avec un entier grand (de l'ordre de 10000)
expliquer rapidement la raison du temps d'exécution.
Exercice 3 [AVL]
Afin de palier le problème des abr nous allons maintenant équilibrer
nos arbres.
- Définir avl le type des arbres AVL polymorphes.
- Donner des constructeurs intelligents pour le type abr.
Ces constructeurs devront permettre de respecter la structure d'AVL.
On utilisera la fonction de comparaisons générique compare
pour les comparaisons.
- Reprendre les questions de l'exercice 2 pour les AVL.