Définition succincte
Une fonction sera dite programmée récursivement lorsqu'elle fait appel à elle-même dans le corps de sa définition.
Une fonction sera dite programmée récursivement lorsqu'elle fait appel à elle-même dans le corps de sa définition.
Le programme qui suit vous propose une fonction définie récursivement. Sa seule utilité est de vous permettre, notamment à l'aide d'affichages, de comprendre le principe.
def compteARebours(n) :
if n == 0 : pass # pass est une instruction qui "ne fait rien"
else :
print(n, end = " ")
compteARebours(n-1)
compteARebours(5)
Réponse de python :
5 4 3 2 1
L'instruction qui suit le test if n==0
est ce que l'on nomme "le cas de base",
c'est ce qui permet de stopper
les appels récursifs.
Si l'on oublie le cas de base en écrivant :
def compteARebours(n) :
print(n, end = " ")
compteARebours(n-1)
compteARebours(5)
les appels récursifs seront sans fin, ce qui est une erreur de programmation. Dans la pratique, en python, un nombre maximum d'appels récursifs par défaut arrêtera la boucle sur une erreur : "RuntimeError: maximum recursion depth exceeded".
Le cas de base doit être atteint pour jouer son rôle.
Dans la première programmation, notre cas de base correspondait à
n == 0
.
Si l'appel intial est fait avec l'argument 5, on finira par atteindre ce cas puisque chaque appel récursif fait
décroître d'une unité la valeur de l'argument.
Mais si un utilisateur appelle notre fonction avec n = -5, on se retrouve dans le cas d'appels récursifs infinis.
Il vaudrait donc mieux programmer notre première fonction ainsi :
def compteARebours(n) :
if n <= 0 : pass
else :
print(n, end = " ")
compteARebours(n-1)
compteARebours(5)
Une modification du cas de base change également le résultat. Essayez par exemple ceci :
def compteARebours(n) :
if n <= -10 : pass
else :
print(n, end = " ")
compteARebours(n-1)
compteARebours(5)
Nous reprenons l'exemple précédent, mais nous aimerions maintenant que le décompte se fasse dans l'ordre croissant.
Par exemple compte(5)
doit afficher "1 2 3 4 5 ".
Il suffit d'échanger deux lignes du programme précédent pour obtenir cet effet.
Essayez de trouver par vous-même cette modification avant de lire le code ci-dessous.
def compte(n) :
if n == 0 : pass
else :
compte(n-1)
print(n, end = " ")
compte(5)
Réponse de python :
1 2 3 4 5
Le principe est le suivant :
pass
).print(n, end=" ")
.
Cette ligne est donc exécutée : la valeur 1 s'affiche à l'écran.print(n, end = " ")
à exécuter. Elle est donc exécutée, et 2 est donc
imprimé à l'écran.print(n, end = " ")
à exécuter. Elle est donc exécutée, et 3 est donc
imprimé à l'écran.print(n, end = " ")
à exécuter. Elle est donc exécutée, et 4 est donc
imprimé à l'écran.print(n, end = " ")
à exécuter. Elle est donc exécutée, et 5 est donc
imprimé à l'écran.L'exemple suivant calcule la somme des entiers 1 + 2 + 3 + ... + n.
Cherchez à comprendre son déroulement.
def somme(n) :
if n == 0 : return 0
else :
return n + somme(n-1)
print(somme(5))
Réponse de python :
15
Le principe est le suivant :
Dans cette page, vous pouvez coller le code de la fonction python et visualiser pas à pas son exécution.
Nous compliquons (un peu artificiellement !) l'exemple précédent du compte à rebours avec des valeurs de retour pour la fonction. Le but est de décomposer cet exemple pour bien saisir le déroulement des appels récursifs.
def d(n) :
if n == 0 :
return 1
else :
print(n)
y = d(n-1)
return 5*y
n = 3
print( "Valeur de d({}) : {}.".format(n, d(n)) )
Réponse de python :
3 2 1 Valeur de d(3) : 125.
Schématisons le déroulement pour tenter de mieux saisir le fonctionnement.
Tout d'abord, la 'descente'.
Un premier appel de la fonction d avec l'argument 3 :
Profondeur | Instructions | n=n1 | y1 | Affichage | Valeur retournée |
---|---|---|---|---|---|
1 | Appel de la fonction d | 3 | - | ||
1 | (n==0) faux | 3 | - | ||
1 | print(n) | 3 | - | 3 | |
1 | y= | 3 | ▢ |
Lors de cette exécution de d(3), un appel à d avec l'argument 2 a lieu :
Profondeur | Instructions | n1 | y1 | n=n2 | y2 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|
2 | d(n-1) | 3 | ▢ | 2 | - | ||
2 | (n==0) faux | 3 | ▢ | 2 | - | ||
2 | print(n) | 3 | ▢ | 2 | - | 2 | |
2 | y= | 3 | ▢ | 2 | ▢ |
Dans cette exécution de d(2), un appel à d avec l'argument 1 a lieu :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n=n3 | y3 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|
3 | d(n-1) | 3 | ▢ | 2 | ▢ | 1 | - | ||
3 | (n==0) faux | 3 | ▢ | 2 | ▢ | 1 | - | ||
3 | print(n) | 3 | ▢ | 2 | ▢ | 1 | - | 1 | |
3 | y= | 3 | ▢ | 2 | ▢ | 1 | ▢ |
Lors de l'exécution de d(1), un appel à d avec l'argument 0 a lieu :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n=n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
4 | d(n-1) | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | ||
4 | (n==0) vrai | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | ||
4 | return 1 | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | d(0) = 1 |
Ensuite, on 'remonte' :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
3 | sortie de 'd(0)' | 3 | ▢ | 2 | ▢ | 1 | ▢ | - | ||
3 | affectation y=d(n-1) | 3 | ▢ | 2 | ▢ | 1 | 1 | - | ||
3 | return 5*y | 3 | ▢ | 2 | ▢ | 1 | 1 | - | d(1) = 5 | |
2 | sortie de 'd(1)' | 3 | ▢ | 2 | ▢ | - | - | - | ||
2 | Affectation y=d(n-1) | 3 | ▢ | 2 | 5 | - | - | - | ||
2 | return 5*y | 3 | ▢ | 2 | 5 | - | - | - | d(2) = 25 | |
1 | sortie de 'd(2)' | 3 | ▢ | - | - | - | - | - | ||
1 | Affectation y=d(n-1) | 3 | 25 | - | - | - | - | - | ||
1 | return 5*y | 3 | 25 | - | - | - | - | - | d(3) = 125 | |
0 | sortie de 'd(3)' | - | - | - | - | - | - | - |
La dernière étape se fait en-dehors de la fonction :
print( "Valeur de d({}) : {}.".format(n, d(n)) )
affiche la valeur de d(3), c'est à dire 125.
On présente une petite variante du programme précédent.
Seules deux lignes sont interverties dans le programme par rapport au précédent.
Chercher à analyser ce que sera l'affichage avant de tester le programme.
def c(n) :
if n == 0 :
return 1
else :
y = c(n-1)
print(n)
return 5*y
n = 3
print( "Valeur de c({}) : {}.".format(n, c(n)) )
Réponse de python :
1 2 3 Valeur de c(3) : 125.
On constate que les affichages intermédiaires (les affichages internes à la fonction) sont inversés par rapport au programme précédent.
Schématisons le déroulement pour tenter de mieux saisir le fonctionnement.
Tout d'abord, la 'descente' :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
1 | Appel de la fonction d | 3 | - | - | - | - | - | - | ||
1 | (n==0) faux | 3 | - | - | - | - | - | - | ||
1 | y= | 3 | ▢ | - | - | - | - | - | ||
2 | c(n-1) | 3 | ▢ | 2 | - | - | - | - | ||
2 | (n==0) faux | 3 | ▢ | 2 | - | - | - | - | ||
2 | y= | 3 | ▢ | 2 | ▢ | - | - | - | ||
3 | c(n-1) | 3 | ▢ | 2 | ▢ | 1 | - | - | ||
3 | (n==0) faux | 3 | ▢ | 2 | ▢ | 1 | - | - | ||
3 | y= | 3 | ▢ | 2 | ▢ | 1 | ▢ | - | ||
4 | c(n-1) | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | ||
4 | (n==0) vrai | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | ||
4 | return 1 | 3 | ▢ | 2 | ▢ | 1 | ▢ | 0 | c(0) = 1 |
Ensuite, la 'remontée' :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
3 | sortie de 'c(0)' | 3 | ▢ | 2 | ▢ | 1 | ▢ | - | ||
3 | affectation y=c(n-1) | 3 | ▢ | 2 | ▢ | 1 | 1 | - | ||
3 | print(n) | 3 | ▢ | 2 | ▢ | 1 | 1 | - | 1 | |
3 | return 5*y | 3 | ▢ | 2 | ▢ | 1 | 1 | - | c(1) = 5 |
Et on continue :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
2 | sortie de 'c(1)' | 3 | ▢ | 2 | ▢ | - | - | - | ||
2 | Affectation y=c(n-1) | 3 | ▢ | 2 | 5 | - | - | - | ||
2 | print(n) | 3 | ▢ | 2 | 5 | - | - | - | 2 | |
2 | return 5*y | 3 | ▢ | 2 | 5 | - | - | - | c(2) = 25 |
On poursuit :
Profondeur | Instructions | n1 | y1 | n2 | y2 | n3 | y3 | n4 | Affichage | Valeur retournée |
---|---|---|---|---|---|---|---|---|---|---|
1 | sortie de 'c(2)' | 3 | ▢ | - | - | - | - | - | ||
1 | Affectation y=c(n-1) | 3 | 25 | - | - | - | - | - | ||
1 | print(n) | 3 | 25 | - | - | - | - | - | 3 | |
1 | return 5*y | 3 | 25 | - | - | - | - | - | c(3) = 125 | |
0 | sortie de 'c(3)' | - | - | - | - | - | - | - |
La dernière étape se fait en-dehors de la fonction :
print( "Valeur de c({}) : {}.".format(n, c(n)) )
affiche la valeur de c(3), c'est à dire 125.