You are on page 1of 5

La rÄcursivitÄ

Ä Une fonction rÅcursive est une fonction rÅcursive Ç

La r€cursivit€ est une notion importante de la programmation qui permet de r€gler des
probl•mes extr‚mement complexes avec seulement quelques lignes. C’est cependant une
m€thode avec laquelle il est facile de se perdre et d’avoir des r€sultats impr€visibles ou
erron€s. Lorsque bien utilis€e, c’est cependant un outil simplifiant, lisible, efficace et souvent
sous estim€.
DÅfinition : La r€cursivit€ est un m€canisme qui permet • une fonction d’effectuer un
appel d’elle mƒme.
Par exemple : Calcul de : ∑
FONCTION Addition (N : entier) entier
0 Debut
1 SI (N > 1)
2 RETOURNE N + Addition(N-1)
3 SINON
4 RETOURNE 1
Fin
La fonction Addition() est r€cursive puisqu’elle comprend un appel de Addition() „ la ligne 3.
Attention! : Pour qu’une fonction r€cursive fonctionne, elle doit n€cessairement contenir
une condition sur cet appel. En effet, si une fonction r€cursive n’a pas de condition, elle
effectuera l’appel „ chaque it€ration et une erreur se produira lorsque la pile (voir plus loin)
sera pleine. Cette condition peut-‚tre un SI… ALORS…, un POUR…FAIRE… ou un TANT
QUE… FAIRE… Quoiqu’il soit naturel de retrouver un simple SI… ALORS…SINON.
Analysons maintenant la r€cursion lors de l’implantation de la fonction Addition en C.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int Addition (int N);
5
6 main (){
7 int Nombre =3;
8
9 printf ("Quel nombre voulez vous?");
10 scanf ("%i", &Nombre);
11
12 printf ("Le resultat est : %i", Addition (Nombre));
13
14 }
15
16 int Addition (int N)
17 {
18 int R;
19 printf ("Debut, valeur: %i\n",N);
20
21 if (N > 1)
22 R = N + Addition (N-1);
23 else
24 R = 1;
25
26 printf ("Fin, valeur: %i, Retour: %i\n", N, R);
27 return R;
28 }
Voyons ce qui se passe. Premi•rement lorsqu’un appel d’une fonction est fait, l’information
sur cette fonction (ligne en ex€cution, adresse des variables, etc) sont mises dans la pile et le
saut est fait. Lorsque la fonction est termin€e, l’information est prise dans la pile. Prenons un
exemple : la fonction Addition() ayant une valeur de 3 re†ue.
Voici ce qui appara‡t sur l’€cran d’ex€cution :
Quel nombre voulez vous?3
Debut, valeur: 3
Debut, valeur: 2
Debut, valeur: 1
Fin, valeur: 1, Retour: 1
Fin, valeur: 2, Retour: 3
Fin, valeur: 3, Retour: 6
Le resultat est : 6

Occupation de la mÅmoire
Effectuons une trace d’ex€cution sur cette entr€e. Ajoutons cependant un nouvel €l€ment, la
pile. Lorsqu’un appel est effectu€, nous allons garder dans une pile la ligne qui effectue un
appel et l’adresse des variables. Lorsqu’une fonction effectue son retour, la ligne sur le
dessus de la pile sera d€pil€e et l’ex€cution se continuera „ cette ligne. Les variables en
caract•re gras sont celles dont la ligne en ex€cution est dans la port€e. Aux lignes qui ne font
que de l’impression „ l’€cran, nous ne copierons pas le tableau, pour simplifier.
Supposons que les lignes 1 „ 11 ont €t€ ex€cut€es et que nous avons „ la ligne 12 la situation
suivante :
12 : printf ("Le resultat est : %i", Addition (Nombre));
Adresse Identificateur Valeur Pile
AF01 … …
AF02 Nombre 3
AF03 …
AF04 …
AF05 …
AF06 …
AF07 …
AF08 …
16 : int Addition (int N)
18 : int R ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 …
AF06 …
AF07 … 
AF08 … 12, AF02
19 : printf ("Debut, valeur: %i\n",N);
21 : if (N>1)
22 : R = N + Addition (N-1)
16 : int Addition (int N)
18 : int R ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2
AF06 R 
AF07 … 22, AF03, AF04
AF08 … 12, AF02
19 : printf ("Debut, valeur: %i\n",N);
21 : if (N > 1)
22 : R = N + Addition (N-1) ;
16 : int Addition (int N)
18 : int R ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2 
AF06 R 22, AF05, AF06
AF07 N 1 22, AF03, AF04
AF08 R 12, AF02
19 : printf ("Debut, valeur: %i\n",N);
21 : if (N > 1)
24 : R = 1 ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2
AF06 R 22, AF05, AF06
AF07 N 1 22, AF03, AF04
AF08 R 1 12, AF02
26 : printf (ˆ Fin, valeur : %i, Retour : %i\n ‰, N, R) ;
27 : return R ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2 
AF06 R 22, AF05, AF06
AF07 N 1 22, AF03, AF04
AF08 R 1 12, AF02
22 : R = N + 1 // 1 est la valeur retournÄe par Addition au dernier appel
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2
AF06 R 3
AF07 22, AF03, AF04
AF08 12, AF02
26 : printf ("Fin, valeur : %i, Retour : %i\n", N, R) ;
27 return R ;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R
AF05 N 2
AF06 R 3 
AF07 22, AF03, AF04
AF08 12, AF02
22 : R = N + 3
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R 6
AF05
AF06
AF07
AF08 12, AF02
26 : printf (" Fin, valeur : %i, Retour : %i\n ", N, R) ;
27 : return R;
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03 N 3
AF04 R 6
AF05
AF06
AF07 
AF08 12, AF02
12 : printf ("Le resultat est : %i", 6);
Adresse Identificateur Valeur Pile
AF01 …
AF02 Nombre 3
AF03
AF04
AF05
AF06
AF07
AF08
Retour au syst•me d’exploitation
RÅcursivitÅ et itÅration.
Il existe certains probl•mes dont la d€finition est r€cursive. Ce genre de probl•me se
programme simplement „ l’aide d’une fonction r€cursive. Les probl•mes qui se solutionnent
„ l’aide de la r€cursivit€ peuvent toujours ‚tre r€solu „ l’aide d’algorithme s€quentiel non-
r€cursif, mais souvent cela est plus complexe.
Exemples : Calcul du factoriel, Calcul des puissances, Suites r€currentes, Tours de Hanoi,
Fonction d’Ackermann, pgcd r€cursif, Recherche Dichotomique, Tri rapide, Tri fusion
Exemple : la suite de Fibonnaci (Suite r€currente)
La suite de Fibonnaci est d€finie comme suit :
n fib(n)
0 1
1 1
2 2
3 3
4 5
5 8
… …
n fib(n-1) + fib(n-2)
On peut facilement implanter un algorithme r€cursif qui calcule la suite de Fibonnaci. Voici
un exemple d’algorithme :
Fonction Fib (N : entier) entier
Debut
SI (N<=1) ALORS
RETOURNE 1
SINON
RETOURNE Fib(N-1) + Fib(N-2)
Fin
Il suffit en effet de d€crire en code r€cursif une d€finition qui est r€cursif. Implantons le donc
en C avec quelques impressions pour visualiser l’ex€cution :
#include <stdio.h>
int Fib (int N);
int MAAAAL = 0;
main (){
int Nombre;

printf ("Quel est votre nombre?");


scanf ("%i", &Nombre);

int Fibonnaci = Fib (Nombre);


printf ("La reponse est : %i\n", Fibonnaci);
printf ("Il a fallu %i iteration.\n",MAAAAL);
return 0;
}
int Fib (int N){
MAAAAL++;
printf ("Appel de Fib pour %i\n",N);
if (N <= 1)
return 1;
else
return Fib(N-1) + Fib(N-2);
}

R€sultat d’une ex€cution :


Quel est votre nombre?4
Appel de Fib pour 4
Appel de Fib pour 3
Appel de Fib pour 2
Appel de Fib pour 1
Appel de Fib pour 0
Appel de Fib pour 1
Appel de Fib pour 2
Appel de Fib pour 1
Appel de Fib pour 0
La reponse est : 5
Il a fallu 9 iteration.

On voit que dans ce cas, l’algorithme r€cursif n’est pas tr•s performant. Par contre
l’algorithme non r€cursif serait beaucoup moins €vident. En voici un qui fonctionne, implant€
en C :
#include <stdio.h>
int Fib (int N);
main (){
int Nombre;
printf ("Quel est votre nombre?");
scanf ("%i", &Nombre);
int Fibonnaci = Fib (Nombre);
printf ("La reponse est : %i\n", Fibonnaci);
}
int Fib (int N){
int DerniereValeur =1;
int Total = 1;
for (int i = 1; i < N; i++){
int Tamp = Total;
Total = Total + DerniereValeur;
DerniereValeur = Tamp;
}
return Total;
}
Dans ce cas, l’algorithme r€cursif est tr•s facile mais moins rapide. Certains probl•mes sont
cependant tr•s difficiles „ r€gler de fa†on non-r€cursive. La solution r€cusive est souvent
facile „ comprendre (quoique difficile „ trouver).

You might also like