TP 9 - Free

Transcription

TP 9 - Free
Faculté des Sciences de Nice
DEUG MIAS MP2 2004-2005
Introduction à la programmation fonctionnelle
Feuille n° 9 : Trier une liste
Opération fondamentale en programmation : de la gestion de la Sécurité Sociale à la construction de l’enveloppe
convexe d’un ensemble de points, il est souvent vital d’ordonner les éléments d’une liste d’objets par-rapport à une
certaine relation de comparaison [ce ne sont pas nécessairement des nombres]…
9.1 Reconnaître si une liste est triée
Exercice 9.1 a) Ecrire un prédicat (triee?
la relation de comparaison r? :
L r?)
retournant
#t
si et seulement si la liste
L
est triée par-rapport à
(and (triee? ’(-4 –2 1 7 7 10 12) <=) (triee? ’(3 3 3 2) >=))
(or (triee? ’(1 2 3 4 0 5) <=)
(triee? ’(12 10 7 1 7 –2 –4) >=))
→
→
#t
#f
N.B. Le fait de passer la relation d’ordre en paramètre permet de trier des objets de nature variée : des nombres,
des points du plan, des cartes d’un jeu de belote, etc. On dit que la fonction triée? est p o l y m o r p h e.
Exercice 9.2 Ecrire un prédicat (permutation? L1 L2) retournant #t si et seulement si la liste L1 est une
permutation de la liste L2. Les éléments des listes L1 et L2 sont de types quelconques… Aucune relation d’ordre ici.
(permutation? ’(1 3 1 sol 2) ’(sol 2 1 1 3)) → #t
(permutation? ’(1 3 1 sol 2) ’(sol 2 1 3))
→ #f
• Notez au passage que lorsque les éléments d’une liste sont comparables, on peut en profiter pour accélérer la recherche
d’un élément :
Exercice 9.3 Ecrire une fonction efficace(member-ord x Lt r?) prenant une liste Lt triée pour la relation
retournant [comme la primitive member] la portion de Lt débutant à la première occurrence de x, ou bien #f :
(member-ord 5 ’(2 3 5 5 8 10) <=) → (5 5 8 10)
(member-ord 9 ’(2 3 5 5 8 10) <=) → #f
r?
et
9.2 Trier une liste
Enfin un peu d’algorithmique intéressante. Il s’agit de partir d’une liste L de nombres dans le désordre [pour une
relation r?] et de construire une copie triée de L :
(tri ’(3 6 –1 2 10 6 4) <=) → (-1 2 3 4 6 6 10)
(tri ’(3 6 –1 2 10 6 4) >=) → (10 6 6 4 3 2 -1)
Vous allez raisonner simplement, par récurrence sur la liste L. Rappelez-vous ce que cela signifie :
Pour traiter par récurrence une liste L, une stratégie courante est la suivante :
• On commence à vérifier que l’on sait traiter la liste vide ().
• On fait l’hypothèse de récurrence que l’on sait traiter (cdr L) et l’on en déduit le traitement de L.
Exercice 9.4 a) A vous… Programmez un tri en suivant cette idée. Vous allez tomber sur ce que l’on nomme le
tri par insertion, ou « tri du joueur de carte ». Nommez-le donc (tri-ins L r?)…
b) Testez votre algorithme sur une liste de 20 entiers aléatoires de [0,99] en utilisant Lrandom . Faites afficher la liste
de départ et la liste triée en croissant, puis en décroissant.
c) Définissez deux listes L500 [resp. L1000] contenant 500 [resp. 1000] entiers aléatoires
chronométrer les temps de calcul des tris par insertion de chacune de ces listes :
(time (pair? (tri-ins L500 <=)))
< 104.
Utilisez
time
pour
; pair? pour ne pas afficher la très longue liste !
Essayez de conjecturer la loi d’évolution du temps de calcul t = f(n) en fonction de la longueur n de la liste. Vérifiez
votre conjecture sur une liste L1500 à 1500 éléments…
d) Prouvez votre conjecture mathématiquement. La technique consiste à noter cn le coût du tri par insertion d’une liste
L de longueur n, et à lire le texte qui définit la fonction en produisant un système d’équations récursives sur la suite
(cn), dont on calculera alors, avec une mathématique élémentaire ou sophistiquée, un équivalent du terme général cn
pour n → +∞. Typiquement ici : c0 = 0 et cn = f(cn-1) que l’on résoud à l’infini.
N.B. On sait faire mieux que cet algorithme de tri, facile à programmer et qui est raisonnablement efficace pour des
listes de longueur n < 50. On peut en effet montrer que l’efficacité optimale pour un algorithme de tri général se
comporte proportionnellement à n log(n). Le dernier exercice propose de programmer un tel tri optimal…
9.3 Profiter du « polymorphisme »
Le polymorphisme de la fonction tri-ins consistait à faire abstraction de la relation d’ordre r? de manière à pouvoir
trier n’importe quels objets. Par exemple, si l’on souhaite trier une liste de noms par ordre alphabétique, il suffit de
prendre pour r? le prédicat primitif string<=? :
> (tri-ins ’(”laura” ”claudia” ”patricia” ”carla” ”sonia” ”priscilla”) string<=?)
(”carla” ”claudia” ”laura” ”patricia” ”priscilla” ”sonia”)
Exercice 9.5 Quelle relation r? prendriez-vous pour que dans le résultat fasse apparaître les nombres impairs à
gauche des nombres pairs, chaque section étant elle-même triée en croissant ?… Exemple :
(tri-ins '(3 6 2 8 9 1 5 2 11 0))  (1 3 5 9 11 0 2 2 6 8)
Exercice 9.6 Une « carte » sera une liste (h c) où h est une « hauteur » [élément de la liste croissante
et où c est une « couleur » [élément de la liste croissante *couleurs*] :
*hauteurs* ]
(define *hauteurs* ’(7 8 9 10 valet dame roi as))
(define *couleurs* ’(trèfle carreau cœur pique))
Par exemple (valet
a)
carreau)
et (8
trèfle)
sont deux cartes.
Programmer un type abstrait « carte » avec un constructeur
et (couleur cart).
(carte
haut
coul)
et deux accesseurs
(hauteur cart)
b)
Ecrire une fonction (random-main) retournant une main formée de 13 cartes aléatoires distinctes !
c)
La hauteur la plus forte est l’as et
(carte<=? cart1 cart2) retournant #t
la couleur la plus forte est le pique. Programmer une relation d’ordre
si et seulement si la carte cart1 est classée avant la carte cart2 pour
l’ordre suivant : si les hauteurs sont différentes, les hauteurs seules décident. A hauteurs égales, on compare les
couleurs. Par exemple :
(carte<=? ’(10 pique)
’(dame carreau))  #t
(carte<=? ’(valet coeur) ’(valet trèfle))  #f
d)
e)
Ecrire une fonction (random-main-triée) retournant une main triée de 13 cartes aléatoires distinctes !
On verra le reste à l’examen de février  Exemple de question : la main contient-elle une paire ?…
9.4 Exercice complémentaire : programmer un meilleur algorithme de tri !
Exercice 9.7 Essayez de faire travailler votre imagination, et trouvez une autre méthode pour ranger des nombres en
ordre croissant. Il y a plus d’une dizaine d’algorithmes de tri !… Tiens, en voici un plus performant que tri-ins
[vous vérifierez avec time après l’avoir programmé] qui fournirait là aussi un exercice typique d’examen :
Pour trier une liste L :
- on scinde L en deux sous-listes L1 et L2 de même longueur ou presque [si L comporte un nombre impair
d’éléments, l’une des deux listes L1 ou L2 aura un élément de plus que l’autre]. L’ordre des éléments de L1 et L2
n’a aucune importance puisque L est dans le désordre.
- On prétend par hypothèse de récurrence que l’on sait calculer des versions triées L1t et L2t de L1 et L2.
- On fusionne les listes triées L1t et L2t en une seule liste triée qui sera le résultat final.
Autrement dit, on utilise comme tactique la dichotomie…
a) Programmez-le en écrivant 3 fonctions (tri-fusion L r?), (scission L) et (fusion L1t L2t r?) . Lire la
remarque qui suit…
b) Allez les matheux : un peu plus difficile que l’analyse du coût en n2 de l’algorithme tri-ins. Montrez que le
coût de cet algorithme [dit du « tri par fusion »] se comporte proportionnellement à n log(n) . Indication :
on pourra supposer que n est une puissance de 2, poser n=2k et étudier la suite d’indice k…
N.B. La fonction (scission L) retourne deux résultats L1 et L2 . En fait, elle retournera la liste (L1 L2) . Par
exemple, la scission de la liste (6 2 8 3 5) pourrait produire ((6 8 5) (2 3)) ou ((5 2) (8 3 6)) ou ce que
vous voudrez… Vous savez [voir le texte qui précède l’exercice 8.3] qu’il est conseillé d’opter en priorité pour une
itération lorsque l’on doit programmer une fonction à plusieurs résultats sur une liste…
Vous avez vraiment tout fini ? Vous êtes insatiables ! Et que pensez-vous de générer la liste des n! permutations
[dans un ordre quelconque] d’une liste de n éléments distincts, ça devrait vous occuper quelque temps [il s’agit donc
d’un défi] bien que ce soit parfaitement faisable avec tout ce que vous savez et une bonne dose de récurrence :
> (permutations ’(a b c))
((a b c) (a c b) (b c a) (b a c) (c a b) (c b a))