Académique Documents
Professionnel Documents
Culture Documents
Présentation
La récursivité est un concept général qui peut être illustré dans
(quasiment) tous les langages de programmation, et qui peut être utile
dans de nombreuses situations.
La définition la plus simple d'une fonction récursive est la suivante :
C’est une fonction qui s'appelle elle-même.
Si dans le corps (le contenu) de la fonction, vous l'utilisez elle-même,
alors elle est récursive.
Récursivité
Premier exemple : fonction factorielle
La factorielle de n notée n! est le produit de tous les entiers de 1 à n. Une
méthode vue en première année consiste à programmer cette fonction de
manière itérative. Voici ce que donne le programme écrit en langage Python :
def fac_iterative(n):
res=1
for k in range(n):
res=res*(k+1) >>> fac_iterative(10)
return res 3628800
Récursivité
Cependant, si on ne fait que répéter à l'infini cette méthode, le calcul ne donnera
jamais de résultat. Pour cela, il faut définir un cas pour lequel on obtient le résultat.
Dans notre exemple ce cas est : 1!=1
A partir de ce résultat, on peut calculer n! pour tout n≥1.
Ainsi, de manière
récursive :
def fac_recursive(n):
if n==0: En pratique, l’appel fac_recursive(10) entraîne
return 1 l’appel fac_recursive(9), qui entraîne lui-même
return(n*fac_recursive(n-1)) l’appel fac_recursive(8) etc… et ainsi de suite,
jusqu’à l’appel fac_recursive(0) qui renvoie 1.
Récursivité
Qu’est-ce qui se passe?
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
La récursivité plus en détails
Pourquoi écrire une fonction récursive ?
On peut remarquer que si l’on a une liste de 4 joueurs, on peut résoudre le problème en
connaissant une liste de matchs pour les 3 premiers joueurs seulement : on prend cette
liste, et on y ajoute un match entre le quatrième joueur et chacun des trois autres. Ainsi,
on peut ramener le problème (obtenir une liste des matchs entre tous les joueurs) à un
sous-problème plus simple : obtenir une liste des matchs entre tous les joueurs, sauf un.
Récursivité
def matches(joueurs):
""" Fonction récursive qui renvoie une liste de matches à partir d'une liste de joueurs
"""
#s'il n'y a qu'un seul joueur, on n'organise aucun match
if len(joueurs)==1:
return [ ]
#on enleve le dernier joueur de la liste, et on demande les matchs sans lui
dernier_joueur = joueurs.pop()
vs=matches(joueurs) #on rajoute un match entre lui et tous les autres joueurs
for j in joueurs:
vs.append([j,dernier_joueur]) #on le remet dans la liste des joueurs, et on
renvoie la liste des match
joueurs.append(dernier_joueur)
return vs
Récursivité
Méthode structurelle et principe fondamental
Une fois qu'on a repéré que le problème que l'on doit résoudre se prête bien à
l'utilisation d'une fonction récursive, il faut écrire la fonction.
D'abord, on gère le cas simple, c'est-à-dire celui qui ne nécessite pas de rappeler
récursivement la fonction. Pour la factorielle, c'est le cas où n vaut 1. Pour la liste
des joueurs, c'est le cas où il y a un seul joueur (car il n'y a aucun match à
organiser).
Ensuite, on gère le ou les sous-problèmes récursifs, en rappelant la fonction
récursive pour chaque sous-problème à résoudre.
On peut énoncer le principe fondamental suivant, concernant les fonctions récursives :
Comme une fonction récursive fait appel à elle-même, il est indispensable de s’assurer
que le nombre d’appels à cette fonction sera fini.
>>> fac_recursive_erreur(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
nombre maximal
File "E:/Exemples/Factorielle.py", line 21, in
d’appels récursifs (de fac_recursive_erreur
l’ordre de 1000) return(n*fac_recursive_erreur(n-1))
...
RuntimeError: maximum recursion depth exceeded
Récursivité
Suites numériques et comparaison entre itératif et récursif
Définition explicite
Une suite numérique peut dans certains cas être définie de manière explicite : u0=f(n).
La détermination du nième terme est alors aisée. Il suffit d’évaluer f(n).
Exemple 1 : Puissances de 2
Problème : évaluer le nombre 2 à la puissance n de manière explicite, n .
def Pow2_explicite(n):
return 2**n
Récursivité
Relation de récurrence
Dans une suite définie de manière récurrente, il est possible de calculer le terme un
de la suite en connaissant les termes précédents.
Les égalités de la forme un = f(un-1), un = f(un-1, un-2), etc. s’appellent des relations de
récurrence. Les égalités qui définissent les premiers termes d’une suite sont
appelées des conditions de départ. Une suite récursive est donc définie par une
relation de récurrence et une(des) condition(s) de départ.
Premier exemple
Récursivité
Il est aussi possible de proposer un algorithme itératif permettant d’aboutir au
même résultat…
def Pow2_iterative(n):
res=1
for k in range(n):
res=res*2
return res
Récursivité
Deuxième exemple La suite de Fibonacci.
F0 0
Cette suite est définie de la façon suivante : F1 1
F F F
n2 n 1 n
Récursivité
On propose maintenant une version itérative, que l’on nommera FibI : F0 0
F1 1
def FibI(n):
F F F
if n==0: n2 n 1 n
return 0
a=0; b=1 #Premiers termes Que peut-on conclure si on compare ces deux
for k in range(1,n): fonctions ? On voit que si on demande un n
a,b=b,a+b très grand, le nombre d’appels de FibR devient
return b vite très important
def FibR(n):
if n<=1:
return n
return FibR(n-1)+FibR(n-2)
Récursivité
Analyse des programmes récursifs
Récursivité
def u(n):
if n==0:
return 2. Si n désigne la valeur de son argument, on
else: note C(n) ce nombre d’opérations. En suivant
x=u(n-1) la définition de la fonction u, on obtient les
return 0.5*(x+3./x) deux équations suivantes : C(0)=0
C(n)= C(n-1)+3
En effet, dans le cas n=0, on ne fait aucune opération
arithmétique. Et dans le cas n>0, on fait d’une part un appel
récursif sur la valeur n-1, d’où C(n-1) opérations, puis trois
opérations arithmétiques (une multiplication , une addition et
une division). Il s’agit d’une suite arithmétique de raison 3,
dont le terme général est :
C(n)=3n
Récursivité
Si en revanche, on avait écrit la fonction u de manière plus naïve, avec deux appels
récursifs u(n-1) :
def u(n):
if n==0:
return 2.
else:
return 0.5*(u(n-1)+3./u(n-1))
Récursivité
Récursivité imbriquée et croisée
Récursivité imbriquée
def Ackermann(m,n):
if m==0:
return n+1
elif n==0:
return Ackermann(m-1,1)
else:
return Ackermann(m-1, Ackermann(m,n-1))
Question : Que vaut Ackermann(2,2) ?
Réponse : 7
Récursivité
Récursivité croisée ou mutuelle
La possibilité de déclarer une fonction sans la définir prend tout son intérêt à propos de la
récursivité croisée. En effet, une fonction ne peut être utilisée qu’à condition qu’elle ait été
définie (ou déclarée) or, dans le cas de la récursivité croisée, on ne pourrait pas s’en sortir
juste à l’aide des définitions. La récursivité croisée consiste à écrire des fonctions qui
s’appellent l’une l’autre.
Prenons l’exemple simple suivant qui consiste à connaître la parité d’un entier naturel.
def estPair(n):
"""Cette fonction renvoie True si l'entier n est pair False sinon (on suppose
que n>=0)"""
if n==0:
return True
return estImpair(n-1)
def estImpair(n):
"""Cette fonction renvoie True si l'entier n est pair False sinon (on suppose
que n>=0)"""
if n==0:
return False
return estPair(n-1)
Récursivité
Récursivité terminale et non terminale
Une fonction récursive est dite non terminale si le résultat de l'appel récursif est utilisé
pour réaliser un traitement (en plus du retour d'une valeur).
def facNT(n):
if n==0:
return 1
return(n*facNT(n-1))
Récursivité
Une fonction récursive est dite terminale si aucun traitement n'est effectué à la remontée
d'un appel récursif (sauf le retour d'une valeur). Concrètement il n’y a pas de calcul entre
l’appel récursif et l’instruction return.
def facT(n,acc=1):
if n==0:
return acc Cette fois-ci, les calculs se font à la descente,
return facT(n-1,n*acc) comme c’est illustré ci-dessous, pour facT(3):
facT(3,1)
facT(2,3)
facT(1,6)
facT(0,6)
Récursivité
Exemple de la suite de Syracuse
La suite de Syracuse d’un nombre entier N est définie par récurrence de la façon
suivante :
n=3
while n!=1:
print(n)
if n%2==0:
def syracuse(n): n=n//2
if n == 1: else:
print 1 # on affiche 1 et on ne fait rien d ’ autre n=3*n+1
else :
print n print(1)
if n % 2 == 0:
syracuse(n/2)
else :
syracuse(3∗n + 1)
Récursivité