La récursivité et le tri
Fonction récursive
●
Il est légal qu'une fonction en appelle une autre ; il est également légal pour une
fonction de s'appeler elle-même. C'est l'une des choses les plus magiques qu'un
programme puisse faire. Par exemple, regardez la fonction suivante :
def countdown(n):
if n <= 0:
print('Blastoff!')
else:
print(n)
countdown(n-1)
Si n est 0 ou négatif, il affiche le mot "Blastoff!" Sinon, il affiche n puis appelle une
fonction nommée countdown - elle-même - en passant n-1 comme argument. Que se
passe-t-il si nous appelons cette fonction comme ceci ?
Fonction récursive
>>> countdown(3)
L'exécution du countdown commence avec n=3, et comme n est supérieur à 0, il
affiche la valeur 3, puis s'appelle…
L'exécution du countdown commence avec n=2, et comme n est supérieur à
0, il sort la valeur 2, puis s'appelle…
L'exécution du countdown commence avec n=1, et comme n est
supérieur à 0, il affiche la valeur 1, puis s'appelle lui-même..
L'exécution du countdown commence avec n=0, et comme n n'est
pas supérieur à 0, il affiche le mot « Blastoff ! » puis revient.
Le countdown qui a obtenu n=1 revient.
Le countdown qui a obtenu n=2 revient.
Le countdown qui a obtenu n=3 revient.
Fonction récursive
●
Et puis vous êtes de retour dans __main__.(le programme principal)
●
Ainsi, la sortie totale ressemble à ceci :
3
2
1
Blastoff
Fonction récursive
Diagrammes de pile pour les fonctions récursives
Chaque fois qu'une fonction est appelée, Python crée un cadre pour
contenir les variables locales et les paramètres de la fonction.
●
Pour une fonction récursive, il peut y avoir plus d'une image sur la pile en
même temps.
Fonction récursive
●
●
Comme d'habitude, le haut de la pile est le cadre de __main__. Il est vide
car nous n'avons pas créé de variables dans __main__ ni passé
d'arguments.
Les quatre cadres de countdown ont des valeurs différentes pour le
paramètre n. Le bas de la pile, où n = 0, est appelé le cas de base. Il ne
fait pas d'appel récursif, il n'y a donc plus de cadres.
Récursivité infinie
●
●
●
Si une récursivité n'atteint jamais un cas de base, elle continue à faire des
appels récursifs indéfiniment et le programme ne se termine jamais. C'est
ce qu'on appelle la récursivité infinie. Voici un programme minimal avec
une récursivité infinie :
def recurse() :
recurse()
Si vous écrivez une récursivité infinie par accident, passez en revue votre
fonction pour confirmer qu'il existe un cas de base qui ne fait pas d'appel
récursif.
Et s'il existe un cas de base, vérifiez si vous êtes assuré de l'atteindre.
Fonction récursive
Récursivité terminale et récursivité non terminale
●
●
On peut différencier deux algorithmes de récursivité : les fonctions
récursives pour lesquelles il n'y a aucun traitement entre l'appel récursif et
le retour de la fonction, et celles pour lesquelles il y a des opérations entre
l'appel et le retour.
Exemple
def S(n1,n2) :
if n1 > n2
return 0
else :
return S(n1,n2-1) + n2
pour calculer S(1, 4), on aura
le schéma suivant :
Fonction récursive
●
Comme les opérations extérieures à l'appel récursif ne sont pas traitées au
fur et à mesure, on conçoit bien que cet empilage/dépilage n'est pas très
performant. Considérons maintenant la variante suivante
def S(n1,n2,res=0)
if n1 > n2 :
return res
return S(n1,n2-1,res+n2)
Ici, le retour est directement l'appel récursif,
il n' y aucune tâche à traiter.
Dans cette situation,le schéma d'exécution
sera le suivant pour le calcul de S( 1,4,0).
●
D'un point de vue théorique, on voit qu'on gagne donc en rapidité
d'exécution. Ce dernier type de fonctions récursives, avec retour direct de
l'appel récursif s'appelle récursivité terminale.
Fonction récursive TD
Exercice 1:
Quelle est la sortie du programme suivant ? Dessinez un diagramme de
pile qui montre l'état du programme lorsqu'il imprime le résultat.
Que se passerait-il si vous appeliez cette fonction ainsi : recurse(-1, 0) ?
Fonction récursive TD
Exercice 2:
●
Écrivez une fonction récursive appelée is_palindrome qui prend une chaîne
en argument et renvoie True s'il s'agit d'un palindrome et False sinon.
Exercice 3:
●
●
Un nombre, a, est une puissance de b s'il est divisible par b et a/b est une
puissance de b. Écrivez une fonction appelée is_power qui prend les
paramètres a et b et renvoie True si a est une puissance de b.
Remarque : vous devrez penser au cas de base.
Exercice 4 :
●
Écrivez une fonction appelée pgcd qui prend les paramètres a et b et
renvoie leur plus grand diviseur commun.
Une façon de trouver le PGCD est basée sur l'observation que si r est le
reste quand a est divisé par b, alors pgcd (a, b) = pgcd (b, r) . Comme cas
de base, nous pouvons utiliser pgcd (a, 0) = a.
Fonction récursive TD
Exercice 5
Écrire une fonction puissance qui calcule la puissance entière d'un
nombre. On pourra écrire une fonction récursive non terminale puis la
transformer en une fonction récursive terminale.