Chapitre 1 : introduction `a la r´ecursivit´e
Table des mati`eres
1 evisions et compl´ements sur les fonctions 1
1.1 Les notions et le vocabulaire `a maˆıtriser . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Une fonction peut appeler une autre fonction et mˆeme renvoyer une autre fonction ! 2
2 Nouveaut´e : une fonction peut s’appeler elle-mˆeme 2
2.1 D´efinition et parall´elisme avec la r´ecurrence . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 Comment ¸ca marche une fonction ecursive ? . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Points importants `a retenir pour une fonction ecursive . . . . . . . . . . . . . . . . . . 4
3 Versions r´ecursives d’algorithmes vus en premi`ere ann´ee 5
3.1 L’algorithme d’Euclide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2 Algorithme de Horner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2.1 M´ethode naturelle (mais qui demande d´ej`a une bonne ´education) d’´evaluation
d’un polynˆome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2.2 ethode plus rus´ee : l’id´ee de la m´ethode de Horner (cf. 1`ere ann´ee) 6
3.2.3 Algorithme it´eratif pour Horner . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2.4 Ecriture r´ecursive de Horner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 Exponentiation rapide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3.1 L’algorithme naif pour le calcul des puissances . . . . . . . . . . . . . . . . 7
3.3.2 Rappels sur l’id´ee de l’exponentiation rapide et impl´ementation r´ecursive . . 7
3.3.3 Comparaison avec les algorithmes it´eratifs vus en premi`ere ann´ee . . . . . . . 7
3.4 Une morale provisoire : le ecursif c’est plus facile ? . . . . . . . . . . . . . . . . . . . . 8
4 Encore plus de r´ecursion : r´ecursion multiple 8
4.1 Eviter de multiplier les appels r´ecursifs inutiles . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Des fonctions qui sont vraiment doublement r´ecursives . . . . . . . . . . . . . . . . . . 9
4.3 Des suites r´ecurrentes crois´ees l’une avec l’autre : ecursivit´e crois´ee . . . . . . . . . . 10
5 Les trois questions qu’on doit se poser sur un algorithme : le cas des fonctions
ecursives 10
5.1 Rappel de premi`ere ann´ee : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.2 Le cas des fonctions r´ecursives sur l’exemple de l’exp. rapide . . . . . . . . . . . . . . . 10
1 R´evisions et compl´ements sur les fonctions
1.1 Les notions et le vocabulaire `a maˆıtriser
efinition : Une fonction informatique fest un objet qui prend des arguments (ou dit
aussi param`etres) et qui renvoie des valeurs de retours (ou pas). Une fonction peut modifier
son ou ses arguments si les arguments en question sont des objets modifiables a(des listes
par exemple).
a. on dit aussi mutables
efinition d’une fonction avec le mot-clef def :en Python, on sait que la syntaxe de
d´efinition d’une fonction est, par exemple pour la fonction math´ematique fxx2:
def f(x) : # x est ici l’unique argument de f
return x*x
1
Le fait de calculer f(2) s’appelle un appel de la fonction f. Dans le langage informatique, on
dit aussi qu’on passe 2 comme argument `a la fonction f.
En python, il suffit de taper f(2).
efinition d’une fonction avec le mot-clef lambda : la mˆeme fonction peut ˆetre d´eclar´ee
en une ligne comme suit :
f=lambda x : x*x
Pour les optionnaires d’info. comparer `a la syntaxe Caml ... 1
On peut encore appeler f(2). Mais on va voir ci-apr`es qu’un int´erˆet de la d´eclaration avec
lambda est ´eventuellement de ne pas donner de nom `a la fonction.
Un exemple de fonction qui ne retourne rien, mais modifie son argument :
def ajoute0(L):
"""prend une liste en argument et la modifie en rajoutant 0"""
L.append(0)
Question Qu’obtient-on pour Msi on fait :
L=[1,2]
M=ajoute0(L)
1.2 Une fonction peut appeler une autre fonction et mˆeme renvoyer une
autre fonction !
a) Pour le premier point, vous le savez bien. Si vous avez cr´e´e une fonction qui r´esout un
probl`eme, vous pouvez vous en servir `a l’inerieur d’une autre. C’est mˆeme une recommandation
utile pour vos devoirs ´ecrits : utilisez les fonctions que vous avez d´ej`a d´efinies !
b) Le deuxi`eme point est peut-ˆetre plus surprenant pour l’instant, voyons un exemple mettant
en valeur l’usage de fonctions lambda :
def f_additionneur(n):
""" renvoie la fonction x-> x+n"""
return lambda x: x+n
f=f_additionneur(2)
g=f_additionneur(3)
2 Nouveaut´e : une fonction peut s’appeler elle-mˆeme
2.1 D´efinition et parall´elisme avec la r´ecurrence
efinition Une fonction r´ecursive est une fonction ftelle que le code de d´efinition de f
contienne un (ou plusieurs) appel(s) `a f. Ces appels sont appel´es appels r´ecursifs.
Comme on va le voir dans les exemples ci-dessous, cette m´ethode de d´efinition de fonction est
tr`es proche de la notion de efinition par r´ecurrence en maths.
Exemple 1 : En maths, on peut d´efinir la factorielle d’un entier nNpar
0! =1,
nN, n!=n×(n1)!
Une d´ef. r´ecursive de la factorielle en Python, calqu´ee sur la d´ef. math´ematique pr´ec´edente,
est la suivante :
def fact(n):
if n==0 :
return 1
else :
return n*fact(n-1)
1. let f x : x*x ;;
2
Remarque : On utilise la mˆeme syntaxe de d´ef. de fonctions : il n’y pas de d´eclaration particuli`ere
pour les fonctions r´ecursives (important pour les habitu´es `a Caml).
Exemple 2, exercice : (i) Si (un)est d´efinie par r´ec. par
u0=0,
nN, un+1=2+un
, d´efinir une
fonction r´ecursive uen Python qui renvoie la valeur u(n)=unpour tout nN.
(ii) Exp´erimentation : Que se passe-t-il si on veut calculer u1000 ?
(iii) Calculer u1000 `a l’aide d’un algorithme it´eratif (boucle).
2.2 Comment ¸ca marche une fonction r´ecursive ?
Un scema intuitif
On peut sch´ematiser les op´erations faites pour le calcul de fact(3) comme suit :
1.2 Profondeur de pile
Afin de protéger le système contre la saturation mémoire engendrée par les boucles
infinies, Python est muni d’une protection simple. Le nombre maximal d’appels récursifs
autorisé par une même fonction est limité. Ce paramètre limite s’appelle la
profondeur de
pile, et vaut 1000 dans les installations Python standard.
Console python
1>>> import sys
2>>> sys.getrecursionlimit()
31000
Cela signifie simplement qu’une fonction récursive ne peut pas s’appeler plus de
1000
fois.
C’est un paramètre réglable par la commande
sys.setrecursionlimit()
. Ainsi, l’appel
des fonctions précédentes,
r1()
ou
r2()
, conduit systématiquement au message d’erreur
RuntimeError: maximum recursion depth exceeded.
Exercice 1
Fixer la limite de la pile à 10. Créer une fonction récursive qui affiche un comp-
teur permettant de vérifier que l’erreur se produit au bout du 10eappel.
Réponse 1
_______________________________________________________
_______________________________________________________
_______________________________________________________
_______________________________________________________
_______________________________________________________
1.3 Les 3 règles de la programmation récursive
Pour éviter qu’une fonction récursive ne finisse en boucle infinie, elle doit toujours possé-
der une condition d’arrêt inévitablement déclenchée par un test.
De façon générale, trois propriétés sont à respecter pour s’assurer du bon fonctionnement
d’une fonction récursive :
elle doit contenir un cas de base ;
elle doit modifier son état pour pouvoir se ramener au cas de base ;
elle doit s’appeler elle-même.
Vérifions cette définition dans le cas de la fonction factorielle
n!=!1 si n=0
n×(n1)! si n1
On constate bien ici que le cas de base existe, 0!
=
1, que la fonction modifie son état par la
relation (n1) et s’appelle elle-même,(n1)!.
Implémenté sous forme récursive, la factorielle nécessite l’utilisation de la commande
return qui doit renvoyer à l’étage précédent la valeur calculée.
Console python
1>>> def fact(n):
2... if n==0:
3... return 1
4... else:
5... return n*fact(n-1)
Console python
1>>> fact(5)
2120
Le déroulement des opérations nécessaires est présenté ci-après. Il y a diminution pro-
gressive de la valeur à calculer, lors de la « descente », jusqu’à arriver au cas de base, qui
déclenche alors la « remontée » des valeurs du contexte pour donner la valeur finale.
FIGURE 1 – Factorielle récursive
Exercice 2
Implémenter une version itérative de la fonction factorielle.
Réponse 2
_______________________________________________________
_______________________________________________________
_______________________________________________________
_______________________________________________________
_______________________________________________________
2 Différents types de récursivité
Il s’agit surtout de citer les différentes situations de récursivité qui existent. Les définitions
parlent d’elles-mêmes.
2/7
La gestion informatique de ce scema
Lorsqu’on appelle fact(3), dans l’espace m´emoire local de la fonction, on d´efinit n=3, le else
s’ex´ecute et donc voudrait ex´ecuter le return 3*fact(2).
Mais cette ex´ecution est diff´er´ee car pour ex´ecuter ce return, on doit d’abord appeler fact(2).
Se cr´ee alors un nouveau sous-espace m´emoire d´edi´e `a l’appel de cette fonction fact avec une
variable locale n=2 dans laquelle va s’ex´ecute fact.
Pendant toute la phase de descente du sch´ema pr´ec´edent, on cr´ee donc quatre espaces de va-
riables locales qu’on nommera ici espace 3,2,1,0, avec des variables locales correspondantes qu’on
indicera par le num´ero de l’espace correspondant n3=3,...,n0=0.
Dans l’espace 0, on peut calculer fact(0).
Avec cette valeur, on peut enfin ex´ecuter le return 1* fact(0) dans l’espace 1 et ainsi de
suite.
Comment rendre ce d´eroulement explicite `a l’aide d’un script ?
def fact(n):
if n==0 :
return 1
else :
print(’--’*n+’> appel de fact’,n-1)
resultat=n*fact(n-1) # on a s´epar´e le calcul du return pour permettre l’affichage
#de la ligne suivante
print(’--’*n+’> retour de fact’,n-1)
return resultat
Qui donne pour fact(3) :
3
------> appel de fact 2
----> appel de fact 1
--> appel de fact 0
--> retour de fact 0
----> retour de fact 1
------> retour de fact 2
Remarque : Commentez la place des deux instructions, print par rapport aux deux autres lignes
(appel et retour).
2.3 Points importants `a retenir pour une fonction r´ecursive
Ce que dit le lien avec les r´ecurrences math´ematiques
D’une fa¸con g´en´erale, deux propri´et´es sont `a respecter pour s’assurer du bon fonctionnement
d’une fonction r´ecursive :
elle doit contenir un cas de base ;
elle doit s’appeler elle-mˆeme, en modifiant son ´etat, pour pouvoir se ramener au
cas de base.
La modification de l’´etat est une modification d’au moins un des arguments de la fonction.
Dans l’exemple de la fonction fact, on a :
Un cas de base fact(0)=1 ;
un appel `a fact(n-1) qui va de proche en proche nous ramener `a fact(0).
Ce que dit la gestion informatique de la m´emoire
Une fonction r´ecursive peut rapidement devenir tr`es gourmande en m´emoire !
Exemple : Le calcul de u1000 plus haut donne le message d’erreur :
RuntimeError: maximum recursion depth exceeded
Le module sys de Python permet de r´egler le nombre maximum d’appels r´ecursifs autoris´e.
Par d´efaut ce nombre est de 1000 comme en t´emoignent les instructions :
import sys
sys.getrecursionlimit()
Une fonction r´ecursive risque de ne pas s’arrˆeter
Que se passe-t-il si on appelle fact(-1) ?
En fait elle s’arrˆete grˆace `a ....
Mais on est dans un cas d’erreur du programme. On peut utiliser la commande assert qui
permettra de d´etecter tout de suite l’erreur.
def fact(n):
assert n >=0
if n==0 :
return 1
etc
Alors fact(-1) provoquera une AssertionError. On peut mˆeme rajouter un message pour
pr´eciser l’erreur 2
2. Avec la syntaxe : assert n>=0, ’Attention n doit ^etre positif’.
4
3 Versions r´ecursives d’algorithmes vus en premi`ere ann´ee
C’est aussi l’occasion de r´eviser des algo. qu’il faut savoir mettre en oeuvre !
3.1 L’algorithme d’Euclide
En premi`ere ann´ee, on a ´etudi´e l’algo. d’Euclide pour trouver le pgcd de deux entiers naturels
aet b.Une version r´ecursive de cet algorithme :
def Euclide2(a,b):
if b==0 :
return a
else :
r=a%b
return Euclide2(b,r)
Question : A l’aide ou bien de vos souvenirs de premi`ere ann´ee, ou bien de l’algo. ci-dessus,
redonner une version it´erative (boucle while) pour ce mˆeme algo.
Commentaires : Qu’est ce qui permet de transformer ici l’algorithme r´ecursif en algorithme
it´eratif (ou r´eciproquement) ?
3.2 Algorithme de Horner
3.2.1 ethode naturelle (mais qui demande d´ej`a une bonne ´education) d’´evaluation
d’un polynˆome
Pour ´evaluer P(x)=anxn++a1x+a0, une premi`ere m´ethode raisonnable serait la suivante :
(on suppose que polynˆome Pest donn´e par P=[a0,..,an] la liste des coefficients)
def evaluation(P,x):
resultat=0
puissancex=1
for i in range(len(P)):
resultat=resultat+P[i]*puissancex
puissancex=puissancex*x
return resultat
Question : Calculer le nombre d’op´erations n´ecessaires pour l’´evaluation d’un polynˆome de degr´e
n? Comparer `a la m´ethode tr`es na¨ıve o`u on ferait plutˆot :
for i in range(len(P)):
resultat=resultat+P[i]*x**i
Le fait d’utiliser la boucle simultan´ement pour le calcul des xifait partie des bonnes pratiques indispensables !
5
1 / 10 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !