Chap5 Récursivité

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 5

IPEIGB AU : 2023/2024

CHAPITRE V: LA RECURSIVITE

1. Définition
Un algorithme est dit récursif s'il est défini en fonction de lui-même. La récursivité est un
principe puissant permettant de définir une entité à l'aide d'une partie de celle-ci. Alors,
chaque appel successif travaille sur un ensemble d'entrées toujours plus affinée, en se
rapprochant de plus en plus de la solution d'un problème.
Prenons un exemple classique : le calcul de la factorielle.

Solution récursive :
Solution itérative : n! = ∏
{
( )
def Fact(n) : def Fact_rec(n) :
f=1 if n==0 :
for i in range(1,n+1): return 1
f=f*i else :
return(f) return(n*Fact_rec(n-1))

2. Evolution d’un appel récursif


L'exécution d'un appel récursif passe par deux phases, la phase de descente et la phase de
la remontée.
2.1. Phase de descente
Dans la phase de descente, chaque appel récursif fait à son tour un appel récursif. Cette
phase se termine lorsque l'un des appels atteint une condition terminale. C’est la condition
pour laquelle la fonction doit retourner une valeur au lieu de faire un autre appel récursif.
Exemple:
4!= Fact_rec(4)=4*Fact_rec(3)
Fact_rec(3)=3*Fact_rec(2)
Fact_rec(2)=2*Fact_rec(1) Condition terminale :
Fact_rec(1)=1*Fact_rec(0) => n==0
Fact_rec(0) = 1
2.2. Phase de la remontée
En arrivant à la condition terminale, on commence la phase de la remontée. Cette phase se
poursuit jusqu'à ce que l'appel initial soit terminé, ce qui termine le processus récursif.
Exemple:

Sections : MP1, PC1, T1 1


IPEIGB AU : 2023/2024

3. Les types de récursivité


3.1. La récursivité simple
La récursivité simple où l’algorithme contient un seul appel récursif dans son corps.
Exemple de la récursivité simple est la fonction factorielle (Fact_rec).
3.2. La récursivité multiple
La récursivité multiple où l’algorithme contient plus d’un appel récursif dans son corps.
Exemple:
{

def Combinaisons(n,p) :
if p==0 or p==n:
return(1)
else :
return(Combinaisons(n-1,p)+ Combinaisons(n-1,p-1))

3.3. La récursivité mutuelle


Des modules sont dits mutuellement récursifs s’ils dépendent les unes des autres.
Exemple : la définition de la parité d'un entier peut être écrite de la manière suivante :
( ) { ( ) {
( ) ( )
def pair(n) : def impair(n) :
if n==0 : if n==0 :
return(True) return(False)
return(impair(n-1)) return(pair(n-1))

3.4. La récursivité imbriquée


La récursivité imbriquée consiste à faire un appel récursif à l'intérieur d'un autre appel
récursif. Exemple de la récursivité imbriquée est la fonction d’Ackermann définie comme
suit :

( ) { ( )
( ( ))
def Ackermann(m,n) :
if m==0 :
return(n+1)
if n==0 :
return(Ackermann(m-1,1))
return(Ackermann(m-1, Ackermann(m,n-1)))
>>> Ackermann(3,4)
125

Limites de la récursivité : On remarque lors de l’appel à Ackermann(100,0) produit un


message d’erreur dont l’intitulé est RuntimeError : maximum recursion depth
exceeded. En d’autres termes, le nombre maximal d’appels de fonctions imbriqués a été
atteint. En Python, ce niveau est fixé à 1000. Cette valeur arbitraire peut être augmentée mais
elle est là pour éviter un dépassement de capacité de la mémoire réservée. Dans ce cas, il vaut
mieux donc utiliser une méthode itérative.

Sections : MP1, PC1, T1 2


IPEIGB AU : 2023/2024

4. Complexité d’une fonction récursive


Pour estimer la complexité en temps d’une fonction récursive, on explicite la « taille » n
de l’argument, et on note T(n) le nombre d’opérations pour l’évaluation de la fonction avec
un argument de taille n (ou encore le coût de la fonction). On établit une relation de
récurrence satisfaite par T(n), pour en déduire l’expression de T(n) et son ordre de grandeur
O(n) lorsque n  .
Par la suite, le calcul de la complexité d’une fonction récursive se fait par la résolution d’une
équation de récurrence en éliminant la récurrence par substitution de proche en proche ou en
utilisant des formes mathématiques.
Remarque : Résolution des récurrences des algorithmes
La résolution des relations de récurrence déduites des algorithmes récurrents se fait selon trois
cas fréquents :

 Suite arithmétique :
( ) { ( ) ( )
( )
 Suite arithmético-géométrique :
( ) { ( ) ( ( ) )+r
( )
𝑏
Tel que : 𝑟
𝑎
 Relation de récurrence de forme :
( ) ( ) ( ) ( )
( )
o Si ( ) ( )
o Si ( ) ( ( ))
o Si ( ) ( ( )) ( )

Exemple : La fonction factorielle. On a déjà dit que n! se calculait en complexité linéaire


avec la fonction fact_rec. Vérifions-le.
On a donc :
( ) {
( )
Il s’agit d’une suite arithmétique de raison 2, dont le terme générale est 2n. On vérifie que
T(n) = 2n + 1 est la solution de cette récurrence, on déduit donc que T(n) = O(n)
Exercice : On considère la suite (un) suivante, qui calcule une approximation de √ :

On explique ici comment calculer le coût d’une fonction récursive, à savoir le nombre
d’opérations élémentaires qu’elle effectue.

def u(n):
if n == 0:
return 2.
else:
x = u(n-1)
return 0.5 * (x + 3. / x)

Sections : MP1, PC1, T1 3


IPEIGB AU : 2023/2024

Evaluons le nombre d’opérations arithmétiques (addition, multiplication et division) et


élémentaires qu’elle effectue.
on obtient les deux équations suivantes :
( ) {
( )
En effet, dans le cas n = 0, il n’y a rien à faire d’autre que de retourner 1. Et dans le cas n > 0,
on fait d’une part un appel récursif sur la valeur n−1, d’où T(n−1) opérations avec une
opération d’affectation, puis trois opérations arithmétiques avec une opération de return. Il
s’agit d’une suite arithmétique de raison 5, dont le terme général est : T(n) = 5n+1
Le nombre d’opérations arithmétiques effectuées par la fonction u est donc proportionnel à n.
Il s’agit donc, d’une complexité linéaire : O(n).
Si en revanche on avait écrit la fonction u plus naïvement, avec deux appels récursifs u(n-1),
c’est-à-dire :
def u(n):
if n == 0:
return 2.
else:
return 0.5 * (u(n-1) + 3. / u(n-1))

Alors les équations définissant T(n) seraient les suivantes :

( ) {
( ) ( )
En effet, il convient de prendre en compte le coût T(n − 1) des deux appels à u(n-1). Il s’agit
maintenant d’une suite arithmético-géométrique, dont le terme général est :
( ) ( ( ) )+r Avec : , a= 2 , b= 4 et T(0)=1
Alors :
( ) ( ( )) + (-4) = 5*2n - 4
Il s’agit donc, d’une complexité exponentielle : O(2n).

5. Conclusion sur la récursivité


On a vu dans ce cours les avantages et les inconvénients de la récursivité.
- Inconvénients :
 Il faut faire attention à ne pas faire trop d’appels récursifs imbriqués
 Il faut faire attention à ne pas faire plusieurs fois les même calculs, sous peine
de voir la complexité exploser.
 Lorsque deux solutions sont équivalentes, l’une en récursif, l’autre en itératif,
il est en général préférable d’utiliser la version itérative.
- Avantage :
 Dans l’ensemble, il est plus facile de prouver un algorithme récursif que son
équivalent itératif.
 L’écriture d’un programme récursif est souvent plus claire (plus
mathématique), que son équivalent itératif.
 Parfois, et c’est là où la récursivité est vraiment importante, il n’est pas du tout
aisé de transformer un algorithme récursif en algorithme itératif. C’est en
général le cas des algorithmes « diviser pour régner ».

Sections : MP1, PC1, T1 4


IPEIGB AU : 2023/2024

TD Chapitre VI : La Récursivité
Exercice n°1 :
Soient x et n∈N. On peut définir xn par récurrence à partir des relations: x0 = 1 et xn = x * xn-1 si x > 1.
Ecrire une fonction en Python Puissance(x,n) qui calcule xn selon le principe présenté ci-dessus.
Déterminer le type de récursivité de cette fonction.
Exercice n°2:
Ecrire une fonction récursive en Python Somme_Chiffre(N) permettant de calculer la somme des
chiffres d'un entier positif passé en paramètre. Donner la version itérative et comparer l'efficacité.
Exercice n°3 :
Ecrire une fonction récursive en Python Palindrome(ch) qui vérifie si une chaîne de caractère est un
palindrôme ou non.
Rappel : un palindrôme est un mot qui se lit de la même façon de gauche à droite et de droite à gauche.
Exemple Maram, SOS
Exercice n°4 :
Ecrire une fonction récursive Renverse(L) qui réarrange les éléments d’une liste en ordre inverse.
Exercice n°5 :
Soit la fonction Test(L, k) où L est une liste d'entiers non vide et k vérifiant 0 ≤ k < len(L).
def Test ( L , k ) :
if k == len ( L ) - 1 :
return True
else:
if L [ k ] > L[ k+1] :
return False
else:
return Test ( L , k+1)
1) Soit L = [6, 9, 4, 8, 12]
a. Que retourne Test(L, 2) (Donner la liste des appels récursifs) ?
b. Que retourne Test(L, 0) (Donner la liste des appels récursifs) ?
2) Que fait la fonction Test dans le cas général ?
3) Calculer le cout et déduire la complexité de cette fonction.
Exercice n°6 :
On considère la suite définie par :

1. Ecrire une fonction itérative, intitulée U_iter, qui prend comme paramètre un entier naturel n
et calcule le terme Un de la suite.
2. Ecrire une fonction récursive, intitulée U_rec, qui prend comme paramètre un entier naturel n
et calcule le terme Un de la suite.
3. Calculer le coût des deux fonctions précédentes en déduisant leur complexité puis comparer
leur efficacité.

Sections : MP1, PC1, T1 5

Vous aimerez peut-être aussi

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy