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 and type(n) == int , "entrer un entier naturel"
if n == 0:
return 0
else:
return n + somme(n - 1)
somme(5)
somme(-1)
somme(3.8)
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 and type(n) == int , "entrer un entier naturel"
return somme_bis(n)
somme(5)
somme(-1)
Fonction Factorielle
def fact_for(n):
"""
Calcule la factorielle de n
paramètre:
n : (int) entier >= 0
retour:
un entier positif
"""
assert k >= 0 and isinstance(k, int),"Vous devez entrer 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
"""
assert k >= 0 and isinstance(k, int),"Vous devez entrer un entier positif"
produit = 1
while n > 1:
produit = produit * n
n = n - 1
return produit
fact_while(3)
n! = n x (n-1) x ... x 1
n! = n x (n-1)!
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)
Analyser un programme récursif
On considère la fonction mystere
ci-dessous :
def mystere(liste):
if len(liste) == 1:
return liste[0]
else:
if liste[0] < liste[1]:
liste.pop(1)
else:
liste.pop(0)
return mystere(liste)
liste = [1, 5, -3, 4]
mystere(liste)
liste = [1, 5, 3, 4]
mystere(liste)
Cette fonction retourne la plus petite valeur de la liste
def mystere_iter(liste):
valeur = liste[0]
for elt in liste:
if elt < valeur:
valeur = elt
return valeur
liste = [1, 5, -3, 4]
mystere_iter(liste)
liste = [1, 5, 3, 4]
mystere_iter(liste)
Comprendre un programme récursif
a x 0 = 0
a x b = a + a x (b - 1)
def produit(a,b):
if b == 0:
return 0
else:
return a + produit(a, b-1)
produit(5, 3)
produit(5, 2980)
produit(10, 400)
a
et b
sont tous deux supérieurs à la taille maximale.def produit(a,b):
if a > 2950 or b > 2950:
return "a ou b dépassent le nombre d'appels recursif possible"
if b == 0:
return 0
else:
return a + produit(a, b-1)
Additions et soustractions
On suppose qu'on ne dispose que de deux opérations : ajouter 1 ou retrancher 1.
# Avec une boucle while
def somme(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier
b : (int) entier
retour:
un entier
"""
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)
# Avec une boucle for
def somme2(a, b):
"""
Calcule la somme de a et b
paramètre:
a : (int) entier
b : (int) entier
retour:
un entier
"""
if b > 0:
for i in range(b):
a = a + 1
elif b < 0:
for i in range(-b):
a = a - 1
return a
somme2(3, -5)
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(8, -5)
Comparaison de deux chaines de caractères
Ecrire de façon itérative, une fonction compare(chaine1,chaine2)
qui renvoie le nombre de fois où chaine1
et chaine2
ont le même caractère au même emplacement.
A titre d'exemples :
compare("recursif","iteratif")
renvoie 2,compare("Python","Javascript")
renvoie 0.def compare(chaine1, chaine2):
compteur = 0
long = min(len(chaine1), len(chaine2))
for i in range(long):
if chaine1[i] == chaine2[i]:
compteur += 1
return compteur
compare("recursif","iteratif")
compare("Python","Javascript")
def compare_rec(chaine1, chaine2):
long = min(len(chaine1), len(chaine2))
if long == 0:
return 0
else:
if chaine1[0] == chaine2[0]:
return 1 + compare_rec(chaine1[1:], chaine2[1:])
return compare_rec(chaine1[1:], chaine2[1:])
compare_rec("recursif","iteratif")
compare_rec("Python","Javascript")
Comprendre la récursivité
def f(n):
if n==0:
print("Partez !")
else:
print(n)
f(n-1)
f(5)
a. Qu'affiche la commande f(5) ?
b. Pourquoi dit-on de cette fonction qu'elle est récursive ?
def ajouter(s,liste):
res = []
for m in liste:
res = res + [s + m]
return res
ajouter("b",["a","b","c"])
ajouter("a",[""])
def produit(s, n):
if n == 0:
return [""]
else:
res = []
for i in range(len(s)):
res = res + ajouter(s[i], produit(s, n-1))
return res
produit("ab",0)
produit("ab",1)
produit("ab",2)
produit("ab",3)
Mélange d'une liste
def echange(lst, i1, i2):
c = lst[i2]
lst[i2] = lst[i1]
lst[i1] = c
l = [2,3,4,5]
echange(l,1,2)
l
def echange2(lst, i1, i2):
lst[i1],lst[i2] = lst[i2],lst[i1]
echange2(l,0,3)
l
Recherche dichotomique dans un tableau trié
def recherche_dichotomie(x, tableau):
gauche = 0
droite = len(tableau) - 1
while gauche <= droite:
milieu = (gauche + droite) // 2
if tableau[milieu] == x:
return True
elif tableau[milieu] > x:
droite = milieu - 1
else:
gauche = milieu + 1
return False
T = [5, 7, 12, 14, 23, 27, 35, 40, 41, 45]
recherche_dichotomie(9, T)
T = [5, 7, 12, 14, 23, 27, 35, 40, 41, 45]
recherche_dichotomie(14, T)
def recherche_dichotomie_rec(x, tableau, gauche, droite):
if gauche > droite:
return False
milieu = (gauche + droite) // 2
if tableau[milieu] > x:
return recherche_dichotomie_rec(x, tableau, gauche, milieu - 1)
elif tableau[milieu] < x:
return recherche_dichotomie_rec(x, tableau, milieu + 1, droite)
else:
return True
T = [5, 7, 12, 14, 23, 27, 35, 40, 41, 45]
recherche_dichotomie_rec(40, T, 1, len(T))
T = [5, 7, 12, 14, 23, 27, 35, 40, 41, 45]
recherche_dichotomie_rec(-1, T, 1, len(T))
Recherche la valeur et affiche l'indice ou -1 si la valeur n'est pas dans la liste
def indice_recursive(x, tableau, gauche, droite):
if gauche > droite:
return -1
milieu = (gauche + droite) // 2
if tableau[milieu] > x:
return indice_recursive(x, tableau, gauche, milieu - 1)
elif tableau[milieu] < x:
return indice_recursive(x, tableau, milieu + 1, droite)
else:
return milieu
nombres = [2, 3, 5, 7, 11, 13, 17]
indice_recursive(13, nombres, 0, len(nombres)-1)
T = [5, 7, 12, 14, 23, 27, 35, 40, 41, 45]
indice_recursive(14,T , 0 , len(T)-1)
indice_recursive(70,T , 0 , len(T)-1)
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)
# Version simplifiée
def pgcd_simp(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:
return pgcd(b, a % b)
pgcd_simp(220, 12)
# Autre version
def pgcd_bis(a, b):
"""
Calcule la pgcd de a et b
paramètre:
a : (int) entier >= 0
b : (int) entier >= 0
retour:
un entier positif
"""
if a % b == 0:
return b
else:
return pgcd(b, a % b)
pgcd_bis(220, 12)
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(f"F({i}) = {fibo(i)}")
#print("F(",i,") = ",fibo(i))