Programmation Fonctionnelle I, 2009-2010

publicité
TP7
Programmation Fonctionnelle I, 2009-2010
http://deptinfo.unice.fr/~roy
COMPLEMENT DE COURS : DIFFERENCE ENTRE STRUCTURES ET LISTES
€
1. Comment une structure est-elle représentée en mémoire ? En première approximation, par un bloc compact contenant les
divers champs de la structure. Par exemple, une structure « colored-posn » ayant trois champs x, y [les coordonnées] et c [la
couleur] sera représentée par un bloc compact comme celui-ci :
3
-5
”blue”
2. Comment une liste est-elle représentée en mémoire ? Non pas sous la forme d’un bloc compact de données mais par un
ensemble de cellules dans la mémoire centrale de l’ordinateur, chacune étant reliée à la suivante par un « pointeur de
chaînage ». Ce pointeur n’est autre que l’adresse [numéro de la case mémoire] de la cellule suivante. Par exemple, la liste
(a b c d) pourra se présenter ainsi en mémoire :
b
a
d
c
Dans un tel schéma, chaque flèche représente un pointeur, c’est à dire l’adresse de la cellule suivante. La dernière cellule a un
pointeur de chaînage vide, représenté par une croix [la liste vide]. On voit alors bien ce que fait la fonction cons : elle crée
une cellule à deux champs first et rest, où first est l’information portée par la cellule, et rest le pointeur de chaînage.
Et le résultat de cons est un pointeur vers la cellule de tête ! Les cellules de listes sont ainsi éparpillées dans la mémoire de
l’ordinateur. La liste ci-dessus peut être définie sous l’une des deux formes équivalentes :
(define L (list ’a ’b ’c ’d))
(define L (cons ’a (cons ’b (cons ’c (cons ’d empty)))))
Exercice 7.1 Familiarisez-vous avec les chaînages :
a) Dessinez le chaînage en mémoire de la liste (a b (c d) e). Appelez votre enseignant pour vérifier.
b) Définissez une variable L dont la valeur soit cette liste. Quelle est la longueur de L ? Vérifiez votre réponse au toplevel.
c) Quelle est l’expression en fonction de L qui permet d’accéder à l’information c de cette liste ?
d) Si L1 = (1 2 3) et L2 = (a b c d), dessinez sur un même schéma les chaînages de L1, de L2 et de (append L1 L2).
T RAVAIL SUR LES L ISTES
Exercice 7.2 a) Programmez une fonction (somme
L)
prenant une liste de nombres L, et retournant la somme de ces nombres.
(somme ’(6 3 1 8 2))  20
b) En déduire une fonction (moyenne
L)
retournant la moyenne de la liste de nombres L :
(moyenne ’(6 3 1 8 2))  4
Exercice 7.3 En utilisant la primitive build-list, programmez les fonctions suivantes :
a) La fonction (entiers n) prenant un entier n ≥ 0 et retournant la liste des entiers de [0,n] :
(entiers 6)  (0 1 2 3 4 5 6)
b) La fonction (impairs
c)
n) prenant un entier n ≥ 0 et retournant la liste des entiers impairs de [0,n] :
(impairs 10)  (1 3 5 7 9), (impairs 11)  (1 3 5 7 9 11)
La fonction (intervalle
a b)
prenant deux entiers a ≤ b, et retournant les entiers de [a,b].
(intervalle 5 10)  (5 6 7 8 9 10)
Exercice 7.4 Programmez récursivement [sans utiliser build-list] les fonctions suivantes :
a) La fonction (nomul3 n) prenant un entier n ≥ 0 et retournant la liste des entiers de [0,n] non multiples de 3. Quelle est
la complexité de votre fonction, si l’on mesure le nombre d’appels à cons ? Si elle est quadratique [O(n2)], vous êtes
priés d’en produire une à complexité linéaire [O(n)]…
b) La fonction (Lrandom n max) prenant deux entiers n et max ≥ 0 , et retournant une liste de longueur n comportant des
entiers aléatoires de [0,max]. Exemple : (Lrandom 10 100)  (84 11 25 91 97 65 11 78 24 9).
Cette fonction est bien pratique pour chronométrer des algorithmes sur de grandes listes.
c) La fonction (iota n x s) retournant une liste de n nombres débutant par x et espacés de s. Exemples :
(iota 6 4 3)
 (4 7 10 13 16 19)
; j’en veux 6 à partir de 4 espacés de 3
(iota 4 3+2i 1-i)  (3+2i 4+i 5 6-i)
d) La même fonction intervalle qu’en 6.4c, avec puis sans iota.
Exercice 7.5 Le cours définit la fonction (tri-ins L rel) qui trie une liste L de nombres avec l’algorithme du tri par
insertion, par-rapport à la relation d’ordre rel . Nous avons vu que la complexité de ce tri était quadratique, en O(n2). Nous
nous proposons de vérifier expérimentalement ce résultat théorique.
a) Définissez deux listes L2000 et L4000 constituées respectivement de 2000 et 4000 entiers aléatoires de [0,100].
b) Comparez les temps de calcul du tri par insertion de ces deux listes [utilisez la primitive time]. Si l’algorithme est
vraiment quadratique, vous devriez trouver un temps environ 4 fois plus long pour L4000 que pour L2000. Que dit le chrono ?
N’oubliez pas de jeter la grosse liste triée à la poubelle en enveloppant le tri par un appel à la fonction void [on ne
s’intéresse pas au résultat, seulement à la mesure du temps].
Exercice 7.6 Programmez la fonction (que-les-impairs L) prenant une liste d’entiers L , et retournant une liste formée des
mêmes éléments que L, dans le même ordre, mais en ne conservant que les entiers impairs. Exemple :
(que-les-impairs ’(7 4 6 3 9 12 21 8 1))  (7 3 9 21 1)
Exercice 7.7 TRES IMPORTANT. L’inconvénient de votre solution à l’Exercice 7.3 pour calculer la moyenne est qu’elle
procède en deux parcours sur la liste L : un premier parcours pour calculer la somme, suivi d’un second parcours pour
calculer la longueur [même si c’est la primitive length qui le fait] !
a) Vous allez programmer une fonction (som&long L) retournant deux résultats sous la forme d’une liste (s n) où s est la
somme et n la longueur de la liste L de nombres. Cette fonction n’effectuera qu’un seul passage sur la liste L pour calculer les
deux résultats en même temps [donc interdiction d’utiliser length !]. Exemple :
(som&long ’(6 3 1 8 2))  (20 4)
b) En déduire une nouvelle version de la fonction (moyenne L). Faites en sorte que le résultat soit un nombre inexact !
c) Dans le même ordre d’idées, programmez une fonction (parite L) retournant deux résultats sous la forme d’une liste
(L1 L2) où L1 est la liste des pairs et L2 celle des impairs, dans le même ordre. Exemple :
(parite '(7 4 6 3 9 12 21 8 1))  ((4 6 12 8) (7 3 9 21 1))
Exercice 7.8 TRES IMPORTANT. a) Programmez le tri par fusion décrit dans le cours page 18. Vous serez amenés à définir
successivement :
- la fonction (scission L) retournant une liste (L1 L2) où L1 et L2 sont « de même longueur ou presque ».
- la fonction (fusion LT1 LT2) retournant un « mélange trié » des listes triées LT1 et LT2.
- Enfin la fonction (tri-fusion L) réalisant le tri par fusion, et utilisant les deux fonctions scission et fusion.
E XERCICES COMPLEMENTAIRES OPTIONNELS
Exercice 7.9 Supposez que vous êtes dans un Scheme étrange [voire dans un autre langage de programmation], qui ne
possède pas les fonctions cons, first et rest. Mais vous avez les structures !
a) Montrez que vous pourriez simuler ces fonctions $cons, $first et $rest avec des structures. Indication : une cellule de
liste est une structure…
b) Comment représenteriez-vous la liste vide dans une variable LISTE-VIDE ? Programmez alors le prédicat $empty?
Définissez la liste MUSIC dont les éléments sont fa , mi et sol . Faites-la afficher avec printf . Demandez quel est le
second élément de cette liste.
La difficulté avec cette implémentation des listes réside dans l’affichage [difficile]…
Exercice 7.10 Prouvez que la complexité du tri par fusion est en O(n log n). On mesure le nombre d’appels à cons.
Indication : on peut sans perdre de généralité puisque n est grand, supposer que n est une puissance de 2, donc n = 2k .
Raisonnez alors sur k pour trouver la valeur du coût cn de trier par fusion une liste de longueur n. On mesure le nombre
d’appels à cons.
Téléchargement