Title: LINF1251: Algorithmes sur les Listes
1LINF1251Algorithmes sur les Listes
- Peter Van Roy
- Département dIngénierie Informatique, UCL
- pvr_at_info.ucl.ac.be
2Ce quon va voir aujourdhui
- Résumé du dernier cours
- Techniques de programmation
- Utilisation de variables non-liées
- Amélioration de lefficacité avec un accumulateur
- Utilisation dun type pour construire une
fonction récursive - Algorithme de tri Mergesort
- Programmer avec plusieurs accumulateurs
- Programmer avec un état
3Résumédu dernier cours
4Récursion sur les listes
- Définir une fonction Nth L N qui renvoie la
nième élément de L - Raisonnement
- Si N1 alors le résultat est L.1
- Si Ngt1 alors le résultat est Nth L.2 N-1
- Voici la définition complètefun Nth L N if
N1 then L.1 elseif Ngt1 then Nth L.2
N-1 endend
5Pattern matching
- Voici une fonction avec plusieurs formes
- fun Length Xs
- case Xs
- of nil then 0
- XXr then 1Length Xr
- X1X2Xr then 2Length Xr
- end
- end
- Comment les formes sont-elles choisies?
-
6Complexité en temps
- Voici une version efficace pour calculer le
triangle de Pascalfun FastPascal N if N1
then 1 else L in LFastPascal N-1
AddList ShiftLeft L ShiftRight L
endend - La complexité en temps est O(n2)
- Complexité polynomiale un polynome en n
7Techniques de programmation
8Techniques de programmation
- Nous avons déjà vu quelques fonctions récursives
sur les listes - Nous allons maintenant approfondir les techniques
de programmation sur les listes - Utiliser les variables non-liées pour permettre
les appels récursifs en dernier (exemple
dAppend) - Utiliser un accumulateur pour augmenter
lefficacité dun algorithme (exemple de Reverse) - Utiliser un type pour définir une fonction
récursive (exemple de Flatten)
9La fonction Append
- Définissons une fonction Append Xs Ys qui
construit une liste qui est la concaténation de
Xs et Ys - Le résultat contient les éléments de Xs suivi par
les éléments de Ys - Nous faisons un raisonnement inductif sur le
premier argument Xs - Si Xsnil alors le résultat est Ys
- Si XsXXr alors le résultat est XAppend Xr Ys
10Exécution dAppend
- Append 1 2 a b 1 Append 2 a b 1
2 Append nil a b 1 2 a b
11Définition dAppend
- Voici la définition de Appendfun Append Xs
Ys case Xs of nil then Ys XXr then
XAppend Xr Ys endend - Est-ce que cette définition fait lappel récursif
en dernier? - Pour le savoir, il faut la traduire en langage
noyau
12Append en langage noyau (1)
- Voici une traduction naïve de cette
définitionproc Append Xs Ys Zs case Xs of
nil then ZsYs XXr then local Zr
in Append Xr Ys Zr ZsXZr
end endend - Lappel récursif nest pas le dernier appel!
13Append en langage noyau (2)
- Voici la vraie traduction de la définition
dAppendproc Append Xs Ys Zs case Xs of nil
then ZsYs XXr then local Zr in
ZsXZr Append Xr Ys Zr
end endend - Lappel récursif est le dernier appel!
- On peut faire ZsXZr avant lappel parce que Zr
est une variable qui nest pas encore liée - Technique dans la construction de listes, on
peut utiliser les variables non-liées pour mettre
lappel récursif en dernier
14La fonction Reverse
- Définissons une fonction qui prend une liste et
qui renvoie une liste avec les éléments dans
lordre inversé - Reverse 1 2 3 3 2 1
- Voici une définition qui utilise Appendfun
Reverse Xs case Xs of nil then nil XXr
then Append Reverse Xr X endend
15Exécution de Reverse
- Xs1 2 3 4
- XXr1 2 3 4 X1, Xr2 3 4
- Reverse Xr4 3 2
- Append Reverse Xr X Append 4 3 2
1 4 3 2 1
16Complexité en temps de Reverse
- La fonction Reverse Xs a un temps dexécution
qui est O(n2) avec nXs - Cest curieux que le calcul de linverse dune
liste de longueur n prend un temps proportionnel
au carré de n! - On peut faire beaucoup mieux en utilisant un
accumulateur - Notez que la première définition nutilise pas
daccumulateur
17Reverse avec un accumulateur
- Il faut un invariant
- Prenons linvariant suivantL reverse(L2)
L1 - Ici, et reverse sont des fonctions
mathématiques - fait la concaténation des listes
- Pas des fonctions écrites en Oz!
- Rappel un invariant est une formule mathématique
- Nous avons donc une paire (L1, L2)
- Quelles sont les transitions de cette paire?
18Vases communicants
- L11 2 3 4, L2nil
- L12 3 4, L21
- L13 4, L22 1
- L14, L23 2 1
- L1nil, L24 3 2 1
19Transitions de laccumulateur
- Nous avons une paire (L1,L2)
- Létat initial est (L,nil)
- La transition est
- (XL1,L2) (L1,XL2)
- Ceci marche parce que si L reverse(L2)(XL1)a
lors L reverse(XL2)L1
20Définition de Reverse avec un accumulateur
- Voici la nouvelle définitionfun Reverse L1
L2 case L1 of nil then L2 XX1 then
Reverse X1 XL2 endend - Exemple dun appel Reverse 1 2 3 nil
- La complexité de cette définition est de O(n)
avec nL1
21La fonction Flatten
- Pour finir avec la première partie, voici une
fonction un peu plus compliquée - Nous voulons définir la fonction Flatten Xs qui
prend une liste Xs qui peut contenir des éléments
qui sont eux-mêmes des listes, et ainsi de suite,
et qui renvoie une liste de tous ces éléments - Exemple Flatten a b c nil d a b c d
22Utiliser un type pour définir une fonction
- Pour définir Flatten Xs, nous allons dabord
définir le type de largument Xs - En suivant le type, la définition sera alors
simple - ltNestedList Tgt nil ltNestedList Tgt
ltNestedList Tgt T ltNestedList Tgt - Pour que le choix de lalternatif soit
non-ambigu,il faut que T ne soit ni nil ni une
paire de liste (un cons) - fun IsCons X case X of _ _ then true else
false end end - fun IsList X Xnil orelse IsCons X end
23Définition de Flatten
- Voici la définitionfun Flatten Xs case
Xs of nil then nil XXr andthen IsList X
then Append Flatten X Flatten Xr XXr
then XFlatten Xr endend - Pour les avertis faire une version de Flatten
qui utilise un accumulateur!
24Algorithmes de tri
25Algorithmes de tri
- Un algorithme de tri prend une liste déléments
et renvoie une liste avec les mêmes éléments
rangés selon un ordre - Il y a beaucoup dalgorithmes de tri différents
- Tri par sélection, tri par insertion
- Mergesort (tri par divisions et fusions
récursives) - Heapsort (tri par construction de heap)
- Quicksort (tri par partitionnement récursif)
26Mergesort
- Cet algorithme peut trier une liste de taille n
en un temps maximal de O(n log n) - Lalgorithme peut facilement être programmé dans
le modèle déclaratif - Lalgorithme utilise une technique générale
appelée diviser pour régner - Diviser la liste en deux listes
- Utiliser mergesort récursivement pour trier les
deux listes - Fusionner les deux listes pour obtenir le résultat
27Exemple de Mergesort (1)
- Prenons la liste L5 2 6 4 3
- Diviser L en deux listes
- L15 2, L26 4 3
- Trier chacune des deux listes
- S12 5, S23 4 6
- Fusionner les deux listes S1 et S2
- Ceci est la clé de lalgorithme!
- On peut le faire en traversant chaque liste au
maximum une fois (voir dessin sur le tableau) - Le résultat est la liste triée S2 3 4 5 6
28Exemple de Mergesort (2)
L11
S11
L1
S1
split
merge
L12
S12
L
S
split
merge
L21
S21
L2
S2
split
merge
L22
S22
- Observez comment est faite la récursion!
29Définition de Mergesort
- fun Mergesort Xs case Xs of nil then nil
X then X else Ys Zs in Split Xs Ys
Zs Merge Mergesort Ys Mergesort
Zs endend
30Définition de Split
- proc Split Xs Ys Zs case Xs of nil then
Ysnil Zsnil X then YsXs Zsnil
X1X2Xr then Yr Zr in YsX1Yr
ZsX2Zr Split Xr Yr Zr endend
31Définition de Merge
- fun Merge Xs Ys case XsYs of nilYs then
Ys Xsnil then Xs (XXr)(YYr) then
if XltY then XMerge Xr Ys else YMerge
Xs Yr end endend
32Programmer avecdes accumulateurs
33Programmer avec plusieurs accumulateurs
- Nous avons déjà vu comment écrire une fonction
avec des accumulateurs - Nous avons vu que lutilisation daccumulateurs
est une bonne idée pour lefficacité (appel
récursif en dernier) - Maintenant, nous pouvons voir les accumulateurs
comme une technique de programmation avec un état
(state)
34Programmer avec un état
- Létat est passé partout dans le programme et
transformé successivement pour obtenir un
résultat - Létat S contient plusieurs composants S(X,Y,Z
, ) - Chaque composant peut être transformé
individuellement - Pour chaque procédure P, lentête devient proc
P Xin Xout Yin Yout Zin Zout - Chaque composant de létat devient une paire
létat dentrée et létat de sortie
35Schéma généraldune procédure (1)
- Létat S contient plusieurs composants S(X,Y)
- Voici la définition de la procédure P proc P
X0 X Y0 Y P1 X0 X1 Y0 Y1 P2 X1 X2 Y1
Y2 . Pm Xn X Yn Y end - Si le nombre daccumulateurs est plus grand
quun, comme ici, alors il est plus facile
dutiliser des procédures au lieu des fonctions
36Schéma généraldune procédure (2)
- Voici un diagramme qui montre la définition de la
procédure P qui a deux accumulateurs
P
X0
X1
X2
X
X0
X
Xn
Y0
Y1
Y2
Y
Y0
Y
Yn
37Exemple avec deux accumulateurs
- Supposons quon dispose dune machine à pile pour
évaluer des expressions arithmétiques - Par exemple (14)-3
- La machine exécute les instructions
suivantespush(1)push(4)pluspush(3)minus
1
5
5
2
4
3
38Compilateur pourmachine à pile (1)
- Définissez une procédure qui prend une expression
arithmétique, exprimée comme une structure de
données, et qui fait deux choses une liste
dinstructions pour une machine à pile, et un
compte du nombre dinstructions - Lexpression (14)-3 est exprimée comme 1 plus
4 minus 3 - La procédure a lentête suivanteproc ExprCode
Expr Cin Cout Nin Nout - Il y a deux accumulateurs, C et N
- Cin liste dinstructions initiale
- Cout liste dinstructions finale
- Nin compte dinstructions initial
- Nout compte dinstructions final
39Compilateur pourmachine à pile (2)
- proc ExprCode Expr C0 C N0 N case Expr of E1
plus E2 then C1 N1 in C1plusC0 N1N01 S
eqCode E2 E1 C1 C N1 N E1 minus E2 then
C1 N1 in C1minusC0 N1N01 SeqCode E2
E1 C1 C N1 N I andthen IsInt I
then Cpush(I)C0 NN01 endend
40Compilateur pourmachine à pile (3)
- proc SeqCode Es C0 C N0 N case Es of nil then
CC0 NN0 EEr then C1 N1 in ExprCode E C0
C1 N0 N1 SeqCode Er C1 C N1 N endend
41Un autre exemple (1)
- On peut faire une version de Mergesort qui
utilise un accumulateur - proc Mergesort1 N S0 S Xs
- N est un entier
- S0 est une liste à trier
- S est le reste de S0 après que les premiers N
éléments sont triés - Xs est la liste triée des premiers N éléments de
S0 - La paire (S0,S) est un accumulateur
- La définition utilise une syntaxe de procédure
parce quelle a deux sorties, S et Xs
42Un autre exemple (2)
proc Mergesort1 N S0 S Xs if N0 then SS0
Xsnil elseif N1 then case S0 of XS1
then SS1 XsX end else S1
Xs1 Xs2 NL NR in NLN div 2
NRN-NL Mergesort1 NL S0 S1 Xs1
Mergesort1 NR S1 S Xs2 XsMerge Xs1
Xs2 end end
- fun Mergesort Xs
- Ys in
- Mergesort1 Length Xs Xs _ Ys
- Ys
- end
43Résumé
44Résumé
- Techniques de programmation
- Utilisation dune variable non-liée pour
construire une liste avec lappel récursif en
dernier - Utilisation dun accumulateur pour augmenter
lefficacité - Utilisation dun type pour construire une
fonction - Algorithme de Mergesort
- Exemple de diviser pour règner
- Programmer avec plusieurs accumulateurs
- Programmer avec un état qui est passé partout
dans un programme - Exemple dun compilateur pour machine à pile