Vous êtes sur la page 1sur 27

Rcursivit (1/3)

Une construction est rcursive si elle se dfinit partir d'elle-mme.

Exemple: le dessin de la Vache qui rit

Autre exemple: le triangle de Sierpinski

Licence Informatique - Semestre 2 - Algorithmique et Programmation

Rcursivit (2/3)
En informatique, un programme est dit rcursif s'il s'appelle lui mme. Il s'agit
donc forcment d'une fonction.

Exemple : la factorielle, n! = 1 x 2 x ... x n donc n! = n x (n-1)!


// cette fonction renvoie n! (n est suppos suprieur ou gal 1)
fonction avec retour entier factorielle(entier n)
dbut
retourne n*factorielle(n-1);
fin

L'appel rcursif est trait comme n'importe quel appel de fonction.

Licence Informatique - Semestre 2 - Algorithmique et Programmation

Rcursivit (3/3)
factorielle(3)
dbut
retourne 3*factorielle(2);
fin

factorielle(2)
dbut
retourne 2*factorielle(1);
fin

factorielle(1)
dbut
retourne 1*factorielle(0);
fin

factorielle(0)
dbut
retourne 0*factorielle(-1);
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

Condition d'arrt (1/2)


Puisqu'une fonction rcursive s'appelle elle-mme, il est impratif qu'on prvoit
une condition d'arrt la rcursion, sinon le programme ne s'arrte jamais!

On doit toujours tester en premier la condition d'arrt, et ensuite, si la condition


n'est pas vrifie, lancer un appel rcursif.

Exemple de la factorielle : si n 1, n! = n x (n-1)!, sinon n! = 1.


// cette fonction renvoie n! (n est suppos suprieur ou gal 1)
fonction avec retour entier factorielle(entier n)
dbut
si (n = 1) alors
retourne 1;
sinon
retourne n*factorielle(n-1);
finsi
fin

Licence Informatique - Semestre 2 - Algorithmique et Programmation

Condition d'arrt (2/2)


6
factorielle(3)
dbut
si (3 = 1) alors retourne 1;
sinon retourne 3*factorielle(2);
finsi
fin

2
factorielle(2)
dbut
si (2 = 1) alors retourne 1;
sinon retourne 2*factorielle(1);
finsi
fin

1
factorielle(1)
dbut
si (1 = 1) alors retourne 1;
sinon retourne 1*factorielle(0);
finsi
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

Pile d'excution (1/4)


La rcursivit fonctionne car chaque appel de fonction est diffrent.
L'appel d'une fonction se fait dans un contexte d'excution propre, qui
contient:
- l'adresse mmoire de l'instruction qui a appel la fonction
- les valeurs des paramtres et des variables dfinies par la fonction
Exemple: excution du programme Toto
programme Toto
entier i;
dbut
i <- 2;
crire factorielle(2);
crire "bonjour";
i <- factorielle(i);
fin

Licence Informatique - Semestre 2 - Algorithmique et Programmation

Pile d'excution (2/4)


programme Toto
444
entier i;
445
dbut
446
i <- 2;
447
crire 2;
factorielle(2);
448
crire "bonjour";
449
i <- 2;
factorielle(i);
450
fin

factorielle(2): n = 2, retour #447


#449
467
463
si (n = 1) alors
468
464
retourne 1;
469
465
sinon
470
466
retourne n*factorielle(n-1);
n*1;
471
467
finsi

factorielle(1): n = 1, retour #466


#470
527
765
si (n = 1) alors
528
766
retourne 1;
529
767
sinon
530
768
retourne n*factorielle(n-1);
531
769
finsi
Licence Informatique - Semestre 2 - Algorithmique et Programmation

Pile d'excution (3/4)


Prvoir l'avance le nombre d'appels d'une fonction rcursive pouvant tre
en cours simultanment en mmoire est impossible. La rcursivit suppose
donc une allocation dynamique de la mmoire ( l'excution).

Quand il n'y a pas de rcursivit, on peut rserver la compilation les zones


mmoire ncessaires chaque appel de fonction.

Les langages de programmation permettent pour la plupart la programmation


rcursive, mais ce n'est pas le cas de certains langages anciens (COBOL,
FORTRAN, BASIC, ...).

En programmation fonctionnelle (LISP, CAML, ) ou en programmation


logique (PROLOG), les programmes sont toujours rcursifs.

Licence Informatique - Semestre 2 - Algorithmique et Programmation

Pile d'excution (4/4)


Attention : excuter trop d'appels de fonction fera dborder la pile d'excution!

public static void testPile(int nbAppels){


System.out.println("appel numro " + nbAppels);
testPile(nbAppels + 1);
}
...
testPile(1);

appel numro 1
appel numro 2
...
appel numro 5613
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.SingleByte.withResult(SingleByte.java:44)
at sun.nio.cs.SingleByte.access$000(SingleByte.java:38)
at sun.nio.cs.SingleByte$Encoder.encodeArrayLoop(SingleByte.java:187)
Licence Informatique - Semestre 2 - Algorithmique et Programmation

Rcursif versus itratif (1/4)


Il est souvent possible d'crire un mme algorithme en itratif et en rcursif.
Exemple :

fonction avec retour entier factorielleBis(entier i)


entier rsultat;
dbut
rsultat <- i;
tantque (i > 1) faire
i <- i 1;
rsultat <- rsultat * i;
fintantque
retourne rsultat;
fin

L'excution d'une version rcursive d'un algorithme est gnralement un peu moins
rapide que celle de la version itrative, mme si le nombre d'instructions est le
mme ( cause de la gestion des appels de fonction).

Licence Informatique - Semestre 2 - Algorithmique et Programmation

10

Rcursif versus itratif (2/4)


Comparaison exprimentale du calcul de la factorielle en itratif et en rcursif.

Licence Informatique - Semestre 2 - Algorithmique et Programmation

11

Rcursif versus itratif (3/4)


Un algorithme rcursif mal crit peut conduire excuter bien plus d'instructions
que la version itrative.
Exemple : la suite de Fibonacci
fonction avec retour entier fibo(entier n)
dbut
si ((n=1) ou (n=0)) alors
retourne 1;
sinon
retourne fibo(n-1)+fibo(n-2);
finsi
fin

fibo(1)
fibo(4)

fibo(1)
fibo(2)

fibo(0)

fibo(1)

+
fibo(0)

fibo(1)
+

Licence Informatique - Semestre 2 - Algorithmique et Programmation

fibo(0)

12

Rcursif versus itratif (4/4)


Sur des structures de donnes naturellement rcursives, il est bien plus facile
d'crire des algorithmes rcursifs qu'itratifs.

Certains algorithmes sont extrmement difficiles crire en itratif.

Licence Informatique - Semestre 2 - Algorithmique et Programmation

13

Rcursivit imbrique
La rcursivit imbrique consiste faire un appel rcursif l'intrieur d'un autre
appel rcursif.

Exemple : la suite d'Ackerman


A(m,n) = n+1 si m = 0,
A(m,n) = A(m-1,1) si n=0 et m > 0
A(m,n) = A(m-1, A(m,n-1)) sinon
fonction avec retour entier ackerman(entier m, entier n)
dbut
si (m = 0) alors
retourne n+1;
sinon
si ((m>0) et (n=0)) alors
retourne ackerman(m-1,1);
sinon
retourne ackerman(m-1,ackerman(m,n-1));
finsi
finsi
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

14

Rcursivit croise
La rcursivit croise consiste crire des fonctions qui s'appellent l'une l'autre.
Exemple :
// cette fonction renvoie vrai si l'entier est pair, faux sinon
// on suppose que l'entier est positif ou nul
fonction avec retour boolen estPair(entier n)
dbut
si (m = 0) alors
retourne VRAI;
sinon
retourne estImpair(n-1);
finsi
fin
// cette fonction renvoie vrai si l'entier est impair, faux sinon
// on suppose que l'entier est positif ou nul
fonction avec retour boolen estImpair(entier n)
dbut
si (m = 0) alors
retourne FAUX;
sinon
retourne estPair(n-1);
finsi
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

15

Ecrire un algorithme rcursif


Problme: crire un algorithme rcursif ralisant un certain traitement T sur
des donnes D.
1- dcomposer le traitement T ensous traitements de mme nature mais sur
des donnes plus petites
2- trouver la condition d'arrt
3- tester ventuellement sur un exemple
4- crire l'algorithme

Licence Informatique - Semestre 2 - Algorithmique et Programmation

16

Dichotomie rcursive (1/2)


Exemple: crire une fonction rcursive qui recherche par dichotomie un
lment dans un tableau d'entiers. La fonction renvoie l'indice de l'lment s'il
existe et -1 sinon.
1- Dcomposition du traitement: rechercher un lment dans le tableau va
conduire, si on ne trouve pas l'lment au milieu, relancer la recherche sur
une moiti du tableau, puis sur un quart, etc.
A chaque appel rcursif, il faut donc savoir entre quels indices i et j on
cherche l'lment.
fonction avec retour entier dicho(entier[] t, entier n, entier i, entier j)
...

2- Condition d'arrt: la recherche s'arrte quand on trouve l'lment ou


quand il n'y a plus de case o chercher (i>j).

Licence Informatique - Semestre 2 - Algorithmique et Programmation

17

Dichotomie rcursive (2/2)


4- Ecriture de l'algorithme:
// on suppose t tri par ordre croissant
// on cherche l'lment n dans t entre i et j inclus
fonction avec retour entier dicho(entier[] t, entier n, entier i, entier j)
dbut
si (i>j ou t[(i+j)/2]=n) alors
si (i>j) alors
retourne -1;
sinon
retourne (i+j)/2;
finsi
sinon
si (t(i+j)/2] > n) alors
retourne dicho(t,n,i,(i+j)/2 1);
sinon
retourne dicho(t,n,(i+j)/2 + 1,j);
finsi
finsi
fin

Remarque: pour chercher n dans tout le tableau t, il faut appeler


dicho(t,n,0,t.longueur-1)
Licence Informatique - Semestre 2 - Algorithmique et Programmation

18

Inversion rcursive (1/2)


Exemple: crire une fonction rcursive qui inverse l'ordre des lments dans
un tableau d'entiers.
1- Dcomposition du traitement: on change les lments situs aux
extrmits du tableau, et on inverse l'ordre des lments situs entre ces
deux extrmits.

3
0

0
3

A chaque appel rcursif, il faut donc savoir entre quels indices i et t.longueur1-i on travaille.
fonction sans retour inverse(entier[] t, entier i)
...

2- Condition d'arrt: l'inversion doit s'arrter quand l'indice i est suprieur ou


gal t.longueur/2.
Licence Informatique - Semestre 2 - Algorithmique et Programmation

19

Inversion rcursive (2/2)


4- Ecriture de l'algorithme:
// on inverse les lments d'indices compris entre i et t.longueur-1-i
fonction sans retour inverse(entier[] t, entier i)
entier temp;
dbut
si (i<t.longueur/2) alors
temp < t[i];
t[i] < t[t.longueur-1-i];
t[t.longueur-1-i] < temp;
inverse(t,i+1);
finsi
fin

Remarque: pour inverser tout le tableau t, il faut appeler inverse(t,0)

Licence Informatique - Semestre 2 - Algorithmique et Programmation

20

Rcursivit terminale et non terminale (1/4)


Une fonction rcursive est dite terminale si aucun traitement n'est effectu la
remonte d'un appel rcursif (sauf le retour d'une valeur).

Une fonction rcursive est dite non terminale si le rsultat de l'appel rcursif est
utilis pour raliser un traitement (en plus du retour d'une valeur).

Exemple de non terminalit : forme rcursive non terminale de la factorielle, les


calculs se font la remonte.
fonction avec retour entier factorielleNT(entier n)
dbut
si (n = 1) alors
retourne 1;
sinon
retourne n*factorielleNT(n-1);
finsi
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

21

Rcursivit terminale et non terminale (2/4)


6
factorielleNT(3)
dbut
si (3 = 1) alors retourne 1;
sinon retourne 3*factorielleNT(2);
finsi
fin
2
factorielleNT(2)
dbut
si (2 = 1) alors retourne 1;
sinon retourne 2*factorielleNT(1);
finsi
fin
1
factorielleNT(1)
dbut
si (1 = 1) alors retourne 1;
sinon retourne 1*factorielleNT(0);
finsi
fin
Licence Informatique - Semestre 2 - Algorithmique et Programmation

22

Rcursivit terminale et non terminale (3/4)


Exemple de terminalit : forme rcursive terminale de la factorielle, les
calculs se font la descente.
// la fonction doit tre appele en mettant resultat 1
fonction avec retour entier factorielleT(entier n, entier resultat)
dbut
si (n = 1) alors
retourne resultat;
sinon
retourne factorielleT(n-1, n * resultat);
finsi
fin

factorielleT(3,1)

factorielleT(2,3)

factorielleT(1,6)
Licence Informatique - Semestre 2 - Algorithmique et Programmation

23

Intrt de la rcursivit terminale


Une fonction rcursive terminale est en thorie plus efficace (mais souvent moins
facile crire) que son quivalent non terminale : il n'y a qu'une phase de descente
et pas de phase de remonte.

En rcursivit terminale, les appels rcursifs n'ont pas besoin d'tres empils dans
la pile d'excution car l'appel suivant remplace simplement l'appel prcdent dans
le contexte d'excution.

Certains langages utilisent cette proprit pour excuter les rcursions terminales
aussi efficacement que les itrations (ce n'est pas le cas de Java).

Il est possible de transformer de faon simple une fonction rcursive terminale en


une fonction itrative : c'est la drcursivation.

Licence Informatique - Semestre 2 - Algorithmique et Programmation

24

Drcursivation (1/3)
Une fonction rcursive terminale a pour forme gnrale :
fonction avec retour T recursive(P)
dbut
I0
si (C) alors
I1
sinon
I2
recursive(f(P));
finsi
fin

La fonction itrative correspondante est :

T est le type de retour


P est la liste des paramtres
C est la condition d'arrt
I0 le bloc d'instructions excut dans tous les cas
I1 le bloc d'instructions excut si C est vraie
I2 et le bloc d'instructions excut si C est fausse
f la fonction de tranformation des paramtres

fonction avec retour T iterative(P)


dbut
I0
tantque (non C) faire
I2
P <- f(P);
I0;
fintantque
I1
fin

Licence Informatique - Semestre 2 - Algorithmique et Programmation

25

Drcursivation (2/3)
Exemple: drcursivation de la factorielle terminale
// cette fonction doit tre appele avec a=1
fonction avec retour entier factorielleRecurTerm(entier n, entier a)
dbut
si (n <= 1) alors
retourne a;
sinon
retourne factorielle(n-1,n*a);
finsi
fin

fonction avec retour entier factorielleIter(entier n, entier a)


dbut
tantque (n > 1) faire
a < n*a;
n < n-1;
fintantque
retourne a;
fin

Licence Informatique - Semestre 2 - Algorithmique et Programmation

26

Drcursivation (3/3)
Une fonction rcursive non terminale a pour forme gnrale :
fonction avec retour T recursive(P)
dbut
I0
si (C) alors
I1
sinon
I2
recursive(f(P));
I3
finsi
fin

T est le type de retour


P est la liste des paramtres
C est la condition d'arrt
I0 le bloc d'instructions excut dans tous les cas
I1 le bloc d'instructions excut si C est vraie
I2 et I3 les blocs d'instructions excuts si C est fausse
f la fonction de tranformation des paramtres

La fonction itrative correspondante doit grer la sauvegarde des contextes


d'excution (valeurs des paramtres de la fonction.

La fonction itrative correspondante est donc moins efficace qu'une fonction


crite directement en itratif.
Licence Informatique - Semestre 2 - Algorithmique et Programmation

27