Title: LINF 1251: Rcursion sur les Listes
1LINF 1251Récursion 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
- Les listes
- Récursion sur les listes
- Pattern matching
- Développement descendant
- Complexité en temps
3Résumédu dernier cours
4Principes
- Une fonction récursive est comme une boucle dans
un langage impératif - Attention si vous avez deux boucles imbriquées,
vous avez besoin de deux fonctions récursives! - Si lappel récursif est le dernier appel, alors
la fonction récursive est exactement comme une
boucle - Espace mémoire constante, temps proportionnel au
nombre ditérations - La programmation avec accumulateurs est
recommandée - Pour assurer que lappel récursif soit le dernier
appel - On peut utiliser un invariant pour dériver un
accumulateur - Comment trouver un bon invariant?
5Comment trouver un bon invariant?
- Principe des vases communicants
- Une formule en deux parties
- Une partie disparaît lautre accumule le
résultat - Exemple calcul efficace des nombres de Fibonacci
- Définition F00, F11, FnFn-1Fn-2
- Invariant le triplet (n-i,Fi-1,Fi)
- Invariant parce que les trois parties du
triplet doivent toujours être dans cette relation - Un pas de lexécution (k,a,b) devient
(k-1,b,ab) - Valeur initiale (n-1,0,1)
6Calcul efficace des nombresde Fibonacci
- Raisonnement sur linvariant
- Invariant le triplet (n-i,Fi-1,Fi)
- Un pas de lexécution (k,a,b) devient
(k-1,b,ab) - Valeur initiale (n-1,0,1)
- Valeur finale (0,Fn-1,Fn)
- Définition de la fonctionfun Fibo K A B if
K0 then B else Fibo K-1 B AB endend - Appel initial Fibo N-1 0 1
7Environnement contextueldune procédure (1)
- Quand on définit une procédure, on fait deux
choses - Déclaration de lidentificateur
- Création de la procédure en mémoire il y a deux
parties, le code de la procédure et son
environnement contextuel - Une procédure se souvient de lendroit de sa
naissance (son environnement contextuel) - Quel est lenvironnement contextuel de cette
procédure?declarefun Iterate Si if IsDone
Si then Si else Iterate Transform Si endend
8Environnement contextueldune procédure (2)
- Pour bien distinguer la déclaration de
lidentificateur et la création de la procédure
en mémoire, on peut écriredeclareIterate
fun Si if IsDone Si then Si else
Iterate Transform Si end end - La syntaxe fun Si end représente une
fonction en mémoire (sans identificateur cest
une fonction anonyme) - Le prend la place de lidentificateur
- Lenvironnement contextuel contient doncIsDone,
Iterate, Transform
9Les listes
10Pourquoi les listes?
- Dans le dernier cours, on a vu la récursion sur
les entiers - Mais un entier est assez limité
- On voudrait faire des calculs avec des structures
plus complexes et avec beaucoup dentiers en même
temps! - La liste
- Une collection ordonnée déléments (une séquence)
- Une des premières structures utilisées dans les
langages symboliques (Lisp, dans les années 50) - La plus utile des structures composées
11Définition intuitive
- Une liste est
- la liste vide, ou
- une paire (un cons) avec une tête et une queue
- La tête est le premier élément
- La queue est une liste (les éléments restants)
12La syntaxe dune liste
- Avec la notation EBNFltList Tgt nil
T ltList Tgt - ltList Tgt représente une liste déléments de type
T et T représente un élément de type T - Attention à la différence entre et
13Notation pour les types
- ltIntgt représente un entier plus précisément
lensemble de tous les entiers - ltList ltIntgtgt représente lensemble de toutes les
listes dentiers - T représente lensemble de tous les éléments de
type T nous disons que T est une variable de
type - Ne pas confondre avec une variable en mémoire!
14Syntaxe pour les listes (1)
- Liste vide nil
- Liste non-vide HT
- Lopérateur infixe
- nil, 5nil, 56nil, 567nil
- nil, 5nil, 5(6nil), 5(6(7nil))
5
6
7
nil
15Syntaxe pour les listes (2)
- Il existe un sucre syntaxique plus court
- Sucre syntaxique raccourci de notation qui na
aucun effet sur lexécution - nil, 5, 5 6, 5 6 7
- Attention dans la mémoire de lordinateur, 5 6
7 et 567nil sont identiques!
5
6
7
nil
16La syntaxe complèteune liste est un tuple
- Une liste est un cas particulier dun tuple
- Syntaxe préfixe (lopérateur devant)
- nil(5 nil)(5 (6 nil))(5 (6
(7 nil))) - Syntaxe complète
- nil,(15 2nil)(15 2(16
2nil))(15 2(16 2(17 2nil)))
17La construction dune liste
X1
5
6
X2
- declare
- X15X2
- X26X3
- X37nil
7
nil
X3
18Résumé des syntaxes possibles
- On peut écrire
- X1567nil
- qui est un raccourci pour
- X15(6(7nil))
- qui est un raccourci pour
- X1(5 (6 (7 nil)))
- La plus courte (attention au nil!)
- X15 6 7
19Calculer avec les listes
- Attention une liste non vide est une paire!
- Accès à la tête
- X.1
- Accès à la queue
- X.2
- Tester si la liste X est vide
- if Xnil then else end
20La tête et la queue
- On peut définir des fonctions
- fun Head Xs
- Xs.1
- end
- fun Tail Xs
- Xs.2
- end
21Exemple avec Head et Tail
- Head a b c
- donne a
- Tail a b c
- donne b c
- Head Tail Tail a b c
- donne c
- Dessinez les arbres!
22Récursion surles listes
23Exemple derécursion sur une liste
- On a une liste dentiers
- On veut calculer la somme de ces entiers
- Définir la fonction Sum
- Définition inductive sur la structure de liste
- Sum de la liste vide est 0
- Sum dune liste non vide L est
- Head L Sum Tail L
24Somme des éléments dune liste (méthode naïve)
- fun Sum L
- if Lnil then
- 0
- else
- Head L Sum Tail L
- end
- end
25Somme des éléments dune liste (avec accumulateur)
- fun Sum2 L A
- if Lnil then
- A
- else
- Sum2 Tail L AHead L
- end
- end
26Transformer le programme pour obtenir
laccumulateur
- Arguments
- Sum L
- Sum2 L A
- Appels récursifs
- Head L Sum Tail L
- Sum2 Tail L AHead L
- Cette transformation marche parce que laddition
est associative - Sum fait (1(2(34))), Sum2 fait
((((01)2)3)4)
27Autre exemple la fonction Nth
- Définir une fonction Nth L N qui renvoie la
nième élément de L - Le type de Nth est ltfun ltList Tgt ltIntgtltTgtgt
- Raisonnement
- Si N1 alors le résultat est Head L
- Si Ngt1 alors le résultat est Nth Tail L N-1
28La fonction Nth
- Voici la définition complètefun Nth L N if
N1 then Head L elseif Ngt1 then Nth
Tail L N-1 endend - Quest-ce qui se passe si le nième élément
nexiste pas?
29Pattern matching
30Sum avec pattern matching
- fun Sum L
- case L
- of nil then 0
- HT then HSum T
- end
- end
31Sum avec pattern matching
- fun Sum L
- case L
- of nil then 0
- HT then HSum T
- end
- end
Une clause
- nil est la forme (pattern) de la clause
32Sum avec pattern matching
- fun Sum L
- case L
- of nil then 0
- HT then HSum T
- end
- end
Une clause
- HT est la forme (pattern) de la clause
33Pattern matching
- La première clause utilise of, les autres
- Les clauses sont essayées dans lordre
- Une clause correspond si sa forme correspond
- Une forme correspond, si létiquette (label) et
les arguments correspondent - Les identificateurs dans la forme sont alors
affectés aux parties correspondentes de la liste - La première clause qui correspond est exécutée,
pas les autres
34Longueur dune liste
- Définition inductive
- Longueur dune liste vide est 0
- Longueur dune paire est 1 longueur de la queue
- fun Length Xs
- case Xs
- of nil then 0
- XXr then 1Length Xr
- end
- end
35Longueur dune liste (2)
- Avec une forme en plus!
- fun Length Xs
- case Xs
- of nil then 0
- X1X2Xr then 2Length Xr
- XXr then 1Length Xr
- end
- end
36Longueur dune liste (3)
- Quelle forme ne sera jamais choisie?
- fun Length Xs
- case Xs
- of nil then 0
- XXr then 1Length Xr
- X1X2Xr then 2Length Xr
- end
- end
37Pattern matching en général
- Le pattern matching peut être utilisé pour
beaucoup plus que les listes - Toute valeur, y compris nombres, atomes, listes,
tuples, enregistrements - Nous allons voir les tuples dans le prochain
cours - Les formes peuvent être imbriquées
- Certains langages connaissent des formes encore
plus générales (expressions régulières)
38Calculs sur les listes
- Une liste est une liste vide ou une paire avec
une tête et une queue - Un calcul avec une liste est un calcul récursif
- Le pattern matching est une bonne manière
dexprimer de tels calculs
39Méthode générale pour la récursion sur les listes
- Il faut traiter les listes de façon récursive
- Cas de base la liste est vide (nil)
- Cas inductif la liste est une paire (cons)
- Une technique puissante et concise
- Le pattern matching (correspondance des formes)
- Fait la correspondance entre une liste et une
forme (pattern) et lie les identificateurs dans
la forme
40Développementdescendant
41Le triangle de Pascal (1)
- Nous allons définir la fonction Pascal N
- Cette fonction prend un entier N et donne la
Nième rangée du triangle de Pascal, représentée
comme une liste dentiers - Une définition classique est que Pascal N est
la liste des coefficients dans lexpansion de
(ab)n
1
1
1
1
2
1
1
3
3
1
(0)
(0)
1
4
6
4
1
42Le triangle de Pascal (2)
1
- Calculez la fonction Pascal N
- Pour la rangée 1, cela donne 1
- Pour la rangée N, déplacez à gauche la rangée N-1
et déplacez à droite la rangée N-1 - Alignez les deux rangées déplacées et
additionnez-les élément par élément pour obtenir
la rangée N
1
1
1
2
1
1
3
3
1
(0)
(0)
1
4
6
4
1
0 1 3 3 1 1 3 3 1 0
Déplacez à droite
Déplacez à gauche
43Schéma de la fonction
Pascal N
Pascal N-1
Pascal N-1
ShiftLeft
ShiftRight
AddList
44Code de la fonction
- declare
- fun Pascal N
- if N1 then 1
- else
- AddList
- ShiftLeft Pascal N-1
- ShiftRight Pascal N-1
- end
- end
Pascal N
Pascal N-1
Pascal N-1
ShiftLeft
ShiftRight
AddList
45Fonctions auxiliaires (1)
- fun ShiftLeft L
- case L of HT then
- HShiftLeft T
- else 0
- end
- end
- fun ShiftRight L 0L end
46Fonctions auxiliaires (2)
fun AddList L1 L2 case L1 of H1T1 then
case L2 of H2T2 then H1H2AddList T1 T2
end else nil end end
47Une définition plus courte dAddList
- Un exemple dune forme (pattern) plus
compliquéefun AddList L1 L2 case L1L2 of
(H1T1)(H2T2) then (H1H2)AddList T1
T2 else nil endend - L1L2 est une paire de deux variables
- Avec on peut grouper deux variables (un peu
comme ) - La forme (H1T1)(H2T2) fait la correspondance
avec L1 et L2 en même temps
48Développement descendant (top-down)
- Ce que nous avons fait avec Pascal est un exemple
de développement descendant (top-down) - Dabord, il faut comprendre comment résoudre le
problème à la main - On résoud le problème en le décomposant en de
tâches plus simples - La fonction principale (Pascal) est définie en
utilisant des fonctions auxiliaires (ShiftLeft,
ShiftRight et AddList) - On complète la solution en définissant les
fonctions auxiliaires
49Complexité en temps
50Temps dexécution
- Quel est le temps dexécution de Pascal N en
fonction de N? - Temps tPascal(N)
- Ce qui nous intéresse est la forme de la fonction
tPascal(N) - Si nous achetons un ordinateur plus rapide, le
temps diminuera tPascal(N)/10 par exemple - Mais la forme de la fonction ne changera pas!
- Quest-ce qui se passe quand N devient grand?
51Complexité en temps
- La complexité en temps O(f(n))
- t(n) est de lordre f(n) sil existe une
constante c telle que t(n) c.f(n) - On écrit t(n) O(f(n))
- Par exemple, si tShiftLeft(n) est le temps
dexécution de ShiftLeft L, on peut dire - tShiftLeft(n) O(n) avec nL
- Pour ShiftRight L cest plus simple
- tShiftRight(n) O(1)
52Complexité de Pascal N
- Quelle est la complexité de Pascal N?
- tPascal(N) O(2n)
- Cela grandit très vite quand N augmente
- Complexité exponentielle n est dans lexposant
- Lhistoire de linventeur des échecs et le shah
- Même avec N relativement petit on ne peut pas
calculer Pascal N dans un temps raisonnable - Pourquoi le temps augmente aussi vite?
- Parce quil y a deux appels récursifs Pascal N-1
53Complexité exponentielle
- declare
- fun Pascal N
- if N1 then 1
- else
- AddList
- ShiftLeft Pascal N-1
- ShiftRight Pascal N-1
- end
- end
Pascal N
Pascal N-1
Pascal N-1
ShiftLeft
ShiftRight
AddList
54FastPascal
- On peut faire un seul appel si on garde le
résultat dans une variable locale Lfun
FastPascal N if N1 then 1 else L in
LFastPascal N-1 AddList ShiftLeft
L ShiftRight L endend - La complexité devient O(n2)
- Complexité polynomiale un polynome en n
- Cest beaucoup plus rapide que O(2n)!
55Résumé
56Résumé
- Les listes
- Différentes syntaxes possibles, mais toujours la
même représentation en mémoire - Récursion sur les listes
- Pattern matching
- Développement descendant (top-down)
- Fonctions sur les listes
- Complexité en temps
- Complexité exponentielle et polynomiale