Une fois que l’on dispose d’une définition récursive pour une fonction, il est en général assez facile de la programmer en Python.
Il faut néanmoins faire attention à deux points importants :
Le code de la fonction somme(n)
rappelé ci-dessous,ne se comporte pas exactement comme la fonction mathématique.
def somme(n):
if n == 0:
return 0
else:
return n + somme(n - 1)
somme(5)
La principale différence est que la fonction mathématique est uniquement définie pour des entiers naturels,
alors que la fonction somme(n)
peut être appelée avec un entier Python arbitraire, qui peut être une valeur négative.
Bien que la fonction mathématique ne soit pas définie pour
n = −1, l’appel somme(-1)
ne provoque aucune erreur immédiate,
mais il implique un appel à somme(-2)
, qui déclenche un appel à somme(-3)
, etc.
Ce processus infini va finir par provoquer une erreur à l’exécution.
</ul>
somme(-1)
Pour éviter ce comportement, c'est de restreindre les appels à la fonction somme(n)
aux entiers positifs ou nuls.
Pour cela, on peut utiliser une instruction assert comme ci-dessous :
def somme(n):
assert n >= 0, "entrer un entier naturel"
if n == 0:
return 0
else:
return n + somme(n - 1)
somme(5)
somme(-1)
Bien que cette solution soit correcte, elle n’est pas encore complètement satisfaisante.
En effet, pour tout appel somme(n)
avec n >= 0, chaque appel récursif commencera par faire le test associé à l’instruction assert,
alors que chaque valeur de n, par la suite, sera nécessairement positive.
Une solution pour éviter ces tests inutiles est de définir deux fonctions :
somme_bis(n)
, implémente la définition récursive de la fonction
mathématique somme(n)
sans **vérifier son argument**.
def somme_bis(n):
if n == 0:
return 0
else:
return n + somme_bis(n - 1)
La seconde, somme(n)
, est la fonction « principale » qui sera appelée par l’utilisateur.
Cette fonction ne fait que vérifier (une et une seule fois) que
son argument n est positif puis, si c’est le cas, elle appelle la fonction
somme_bis(n)
.
def somme(n):
assert n >= 0, "entrer un entier naturel"
return somme_bis(n)
somme(5)
somme(-1)
def fact_for(n):
"""
Calcule la factorielle de n
paramètre:
n : (int) entier >= 0
retour:
un entier positif
"""
produit = 1
for i in range(2, n+1):
produit = produit * i
return produit
fact_for(3)
b) En utilisant le boucle "while"
def fact_while(n):
"""
Calcule la factorielle de n
paramètre:
n : (int) entier >= 0
retour:
un entier positif
"""
produit = 1
while n > 1:
produit = produit * n
n = n - 1
return produit
fact_while(3)
2) Fonction récursive
def fact_rec(n):
"""
Calcule la factorielle de n
paramètre:
n : (int) entier >= 0
retour:
un entier positif
"""
if n == 0:
return 1
else:
return n * fact_rec(n - 1)
fact_rec(5)
Calcul de pgcd de deux nombres entiers
def pgcd(a, b):
"""
Calcule la pgcd de a et b
paramètre:
a : (int) entier >= 0
b : (int) entier >= 0
retour:
un entier positif
"""
if b == 0:
return a
else:
r = a % b
return pgcd(b, r)
pgcd(220, 12)
Nombres d'adhérents
1)
def nombre(n):
"""
Calcule le nombre théorique d'adhérents
paramètre:
n : (int) entier >= 1
retour:
un flotant positif
"""
if n == 0:
return 2000
else:
return nombre(n-1) * 0.95 + 200
nombre(10)
2) Nombres d'adhérents au cours des 20 prochaines années
for i in range(1, 21):
print(nombre(i))
Suite de Fibonacci
def fibo(n):
"""
Calcule la valeur de la suite de Fibonacci pour n
paramètre:
n : (int) entier >= 0
retour:
un entier positif
"""
if n == 0 or n == 1:
return 1
else:
return fibo(n - 1) + fibo(n - 2)
for i in range(21):
print(fibo(i))
# Version récursive normale
def somme_rec(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier >= 0
b : (int) entier >= 0
retour:
un entier positif
"""
if b == 0:
return a
else:
return somme_rec(a, b-1) + 1
# Version récursive terminale
def somme_rec_term(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier >= 0
b : (int) entier >= 0
retour:
un entier positif
"""
if b == 0:
return a
else:
return somme_rec_term(a+1, b-1)
somme_rec(3, 5)
somme_rec_term(3, 5)
def somme(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier >= 0
b : (int) entier >= 0
retour:
un entier positif
"""
if b > 0:
while b > 0:
a = a + 1
b = b - 1
elif b < 0:
while b < 0:
a = a - 1
b = b + 1
return a
somme(-3, 5)
2) Version récursive normale
def somme_rec(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier relatif
b : (int) entier relatif
retour:
un entier relatif
"""
if b == 0:
return a
elif b > 0:
return somme_rec(a, b-1) + 1
else:
return somme_rec(a, b+1) - 1
somme_rec(-3, 5)
3) Version récursive terminale
def somme_rec_term(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier relatif
b : (int) entier relatif
retour:
un entier relatif
"""
if b == 0:
return a
elif b > 0:
return somme_rec(a, b-1) + 1
else:
return somme_rec(a, b+1) - 1
somme_rec_term(-3, 5)
Fonction paire
def pair(n):
"""
Détermine si un nombre entier positif est pair
paramètre:
n : (int) entier >= 0
retour:
un booléen
"""
if n > 0:
return pair(n - 2)
else:
return n == 0
pair(8)
Fonction puissance
1) Version récursive normale
def puissance(x, n):
"""
Calcule la puissance de x à l'exposant n
paramètre:
x : (flottant)
n : (int) entier relatif
retour:
un flottant
"""
if n == 0:
return 1
else:
return x * puissance(x, n-1)
puissance(7, 28)
2) Version récursive terminale - On utilise un accumulateur
def puissance(x, n, acc):
"""
Calcule la puissance de x à l'exposant n
paramètre:
x : (float)
n : (int) entier relatif
acc: (int) accumulateur
retour:
un flottant
"""
if n == 0:
return acc
else:
return puissance(x, n-1, x*acc)
puissance(7, 28, 1)
Fonction puissance deuxième version
On peut cependant utiliser une autre définition de la fonction mathématique
puissance(x, n)
qui réduit drastiquement le nombre d’appels récursifs emboîtés.
D'après l'énoncé, on peut décomposer la fonction puissance en utilisant la fonction carre. On peut le faire avec deux cas récursifs qui distinguent la parité de n et deux cas de base (n = 0 et n = 1), comme ci-dessous :
puissance(x, n) =
1 si n = 0,
x si n = 1,
carre(puissance(x, n//2)) si n > 1 et n est pair,
x * carre(puissance(x, (n - 1)//2)) si n > 1 et n est impair.
Pour le codage en Python
carre(x)
est simplement remplacé par la multiplication r * r
.
Le test de parité est réalisé par un **test à zéro du reste de la division entière par 2** (soit r % 2 == 0
).
def puissance(x,n):
"""
Calcule la puissance de x à l'exposant n
paramètre:
x : (flottant)
n : (int) entier relatif
retour:
un flottant
"""
if n == 0:
return 1
elif n == 1:
return x
else:
r = puissance(x, n // 2)
if n % 2 == 0:
return r * r
else:
return x * r * r
puissance(7, 28)
Fonction somme sur les élément d'une liste
1) On donne ici trois solutions possibles
def somme1(liste):
"""
Calcule la somme des éléments d'une liste
paramètre:
liste : (list) une liste de nombres
retour:
un flottant
"""
if liste == []:
return 0
else:
return liste[0] + somme1(liste[1:])
def somme2(liste):
"""
Calcule la somme des éléments d'une liste
paramètre:
liste : (list) une liste de nombres
retour:
un flottant
"""
if liste == []:
return 0
else:
return somme2(liste[:-1]) + liste[-1]
def somme3(liste):
"""
Calcule la somme des éléments d'une liste
paramètre:
liste : (list) une liste de nombres
retour:
un flottant
"""
if liste == []:
return 0
else:
x = liste.pop() # Enlève et reourne la dernière valeur de la liste. la liste est modifiée etvide à la fin !
return somme3(liste) + x
ex_liste = [4, 7, 2]
somme1(ex_liste)
somme2(ex_liste)
somme3(ex_liste)
2) Explication du déroulement
On utilise la fonction somme1(list)
et la liste ex_liste = [4, 7, 2]
en paramètre.
- > en attente, doit renvoyer : 4 + somme1([7, 2])
--- > en attente, doit renvoyer : 4 + (7 + somme1([2]))
----- > en attente, doit renvoyer : 4 + (7 + (2 + somme1([])))
------- > arrêt des appels récursifs
------- > renvoi de somme1([]) : 4 + (7 + (2 + 0))
----- > renvoi de (2 + 0) : 4 + (7 + 2)
--- > renvoi de (7 + 2) : 4 + 9
--- > renvoi de 13
Fonction mystere
1) On reconnait les divisions euclidiennes successives par 2.
A chaque étape, on garde le reste et on recommence avec le quotient.
Cette fonction renvoie donc l'écriture binaire de l'entier naturel n, sous la forme d'une chaîne de caractères.
2) On va utiliser une fonction à deux paramètres.
D'après le cours de première, il suffit d'ajouter 2^n si r est négatif.
En utilisant la fonction mystere(n)
de l'énoncé, on obtient :
def mystere(n):
"""
Détermine l'écriture binaire d'un nombre entier naturel
paramètre:
n : (int) un entier naturel
retour:
chaîne de caractères
"""
if n < 2:
return str(n)
else:
return mystere(n//2) + str(n % 2)
mystere(18)
2) On va utiliser une fonction à deux paramètres.
D'après le cours de première, il suffit d'ajouter 2^n si r est négatif.
En utilisant la fonction mystere(n)
de l'énoncé, on obtient :
def binaire(r, n): # on suppose -2**(n-1) <= n < 2**(n-1)
"""
Détermine l'écriture binaire d'un nombre entier relatif
paramètre:
r : (int) entier relatif
n : (int) un entier naturel stritement positif
retour:
chaîne de caractères
"""
if r < 0:
r = r + 2**n
if r < 2:
return str(r)
else:
return binaire(r//2, n) + str(r % 2)
binaire(18, 8)
binaire(-18, 8)
3) Résultat codé avec n caractères. On peut avoir eventuellement des 0 au début.
def binaire(r, n, cpt = 0): # on suppose -2**(n-1) <= n < 2**(n-1)
"""
Détermine l'écriture binaire d'un nombre entier relatif
paramètre:
r : (int) entier relatif
n : (int) un entier naturel stritement positif
cpt: (int) compteur
retour:
chaîne de caractères
"""
if r < 0:
r = r + 2**n
if r < 2:
return (n -cpt - 1) * '0' + str(r)
else:
return binaire(r//2, n, cpt+1) + str(r % 2)
binaire(-18, 8)
Fonction inverse.
Cette fonction inverse une chaîne de caractères.
def inverse(ch):
"""
Inverse l'ordre d'une chaîne de caractères
paramètre:
ch : (str) chaîne de caractères
retour:
chaîne de caractères
"""
if ch == "":
return ch
else:
return inverse(ch[1:]) + ch[0]
inverse("azerty")
Fonction nettoie.
Cette fonction elimine les doublons dans une liste.
Version itérative de l'énoncé :
def nettoie(liste):
"""
Elimine les doublons d'une liste
paramètre:
liste : (list) une liste de nombres
retour:
une liste
"""
n = len(liste)
k = 0
while k < n - 1:
if liste[k] != liste[k+1]:
k = k + 1
else:
del liste[k]
n = len(liste)
Version récursive :
def nettoie_rec(liste, k = 0):
"""
Elimine les doublons d'une liste
paramètre:
liste : (list) une liste de nombres
retour:
une liste
"""
if k < len(liste) - 1:
if liste[k] != liste[k+1]:
nettoie_rec(liste, k+1)
else:
del liste[k]
nettoie_rec(liste, k)
ex_liste = [1, 1, 2, 6, 6, 6, 8, 8, 9, 10]
nettoie(ex_liste)
ex_liste
ex_liste = [1, 1, 2, 6, 6, 6, 8, 8, 9, 10]
nettoie_rec(ex_liste)
ex_liste