C4.1 : Récursivité
Présentation
Première approche
• Considérons le code suivant :
def afficheNombres(debut, fin):
if debut > fin:
print("FIN")
else:
print(debut)
afficheNombres(debut+1, fin)
afficheNombres(20, 24)
A faire : dérouler le programme "à la main" (sans utiliser l'ordinateur) et expliquer ce qu'il va afficher dans le shell.
• Considérons maintenant le code précédent, légèrement modifié comme suit :
def afficheNombres(debut, fin):
if debut > fin:
print("FIN")
else:
print(debut)
afficheNombres(debut+1, fin)
print("Après ", debut)
afficheNombres(20, 24)
A faire : dérouler le programme "à la main" (sans utiliser l'ordinateur) et expliquer ce qu'il va afficher dans le shell.
Bilan d'étape
Généralités
Une fonction récursive s’appelle elle-même
Lors d’une récursivité, les instructions (ou portions d’instructions) en attente sont placées dans une pile puis dépilées.
C’est pour cela que la récursion peut nécessiter beaucoup de mémoire (En Python, par défaut, la pile est de taille 1000 au maximum).
Pour qu'un programme qui appelle une fonction récursive se termine, il est nécessaire que la fonction récursive contienne une condition, dite condition d'arrêt :
- - si la condition d'arrêt est vérifiée, la fonction n'est pas rappelée et le code correspondant au cas de base est exécuté ;
- - si la condition d'arrêt n'est pas vérifiée, le code contenant l'appel récursif à la fonction est exécuté.
Méthodologie :
- 1) Repérer le sous-problème qui se répète, à un « niveau inférieur », ou « imbriqué ».
- 2) Repérer la condition d’arrêt, et le cas de base.
Bien comprendre la pile de récursivité (ou pile d'exécution)
A faire : observer le deuxième code avec le mode "Pas à pas" de Thonny.
A faire : observer le deuxième code dans PythonTutor.
Application
Application n° 1 : afficher les nombres par ordre décroissant
Proposer deux fonctions récursives à un seul paramètre n qui permettent, pour l'une d'afficher les nombres de 1 à n, pour l'autre d'afficher les nombres de n à 1.
Application n° 2 : afficher les puissances de 2
Proposer une fonction récursive qui permet d'afficher les n premières puissances de 2.
Application n° 3 : "Bonjour !"
Écrire une fonction récursive qui affiche n fois le message "Bonjour !".
Application n° 4 : carrés emboités
En utilisant le module PIL, écrire un programme avec :
- - une fonction qui permet de tracer un rectangle centré de côté c passé en paramètre ;
- - une fonction recursive qui permet de tracer l'ensemble des carrés comme le montre l'image ci-dessous ;
- - le corps du programme.
Fonctions récursives avec renvoi d'une valeur
Analyse d'un code
On considère le code ci-dessous :
def s(n:int) -> int:
if n == 0:
return 0
else:
return n + s(n-1)
1) Quelle valeur va renvoyer s(5) ?
2) Détailler le déroulement pas à pas du programme en précisant les instructions stockées dans la pile d'appel (pile d'exécution).
Deux exemples pour commencer
Application n° 1 : Factoriel
En mathématique, la fonction "factoriel(n)" renvoie le produit des nombres de 1 à n.
Ainsi :
- factoriel(0) = 1 (Par définition)
- factoriel(1) = 1 (Par définition)
- factoriel(2) = 2
- factoriel(3) = 6
- factoriel(4) = 24
- ...
On souhaite programmer cette fonction.
On observe que factoriel(n) = n * factoriel(n-1). Ainsi, la fonction pourra être récursive.
Proposer une fonction récursive qui permet de calculer factoriel n pour n ≥ 0.
Application n° 2 : 2 à la puissance n
A faire : proposer une fonction récursive qui prend un nombre entier n en paramètre et revoie 2 à la puissance n. Cette fonction ne devra pas utiliser l'opérateur **, mais seulement l'opérateur *.
Autres applications
Application n° 1 : Inverser une chaine de caractères
Écrire une fonction récursive qui prend une chaine de caractères en paramètre et renvoie une chaine avec les caractères dans l'ordre inverse.
Information
Si ch est une chaine :
- •
ch[i:j]renvoie la sous-chaine qui va du caractère en positioniau caractère en positionj - 1; - •
ch[:j]renvoie la sous-chaine qui va du premier caractère au caractère en positionj - 1; - •
ch[i:]renvoie la sous-chaine qui va du caractère en positioniau dernier caractère.
Application n° 2 : Conversion de la base 10 à la base 2
Écrire une fonction récursive qui prend un nombre entier en base 10 en paramètre et renvoie une chaine de caractères correspondant à la valeur en binaire de l'entier.
Application n° 3 : Somme des chiffres d'un entier positif
Écrire une fonction récursive qui prend un nombre entier en paramètre et renvoie la somme des chiffres de cet entier.
Applications plus complexes
Application n° 1 : Être ou ne pas être une puissance de 2
Écrire une fonction récursive estPuissance2(n) qui renvoie True si n (entier strictement positif) est une puissance de 2 et False sinon.
Application n° 5 : Être ou ne pas être un palindrome
Écrire un fonction récursive qui renvoie True si la chaine de caractères passée en paramètre est un palindrome et False dans le cas contraire.
Application n° 6 : Tirage du loto
A faire : écrire une fonction pour faire le tirage des 6 numéros du loto à l’aide d’une fonction récursive. Les 6 numéros doivent être différents et compris entre 1 et 49. La fonction prendra en paramètre une liste de numéros déjà tirés. Ainsi, le tirage du loto sera lancé par loto([]).