Sunteți pe pagina 1din 6

10.

Recursivitatea
n programare, recursivitatea se refer la proprietatea unei funcii de a se putea apela pe ea nsi.
Cu alte cuvinte, spunem c o funcie este recursiv dac ea se autoapeleaz. Ea se poate autoapela fie
direct, fie indirect prin apelul altor funcii.
La apelurile recursive ale unei funcii aceasta este apelat nainte de a reveni din ea. La fiecare
reapel al funciei, parametrii i variabilele ei se aloc pe stiv ntr-o zon independent. De aceea, aceste
date au valori distincte la fiecare reapelare. Nu acelai lucru se ntmpl cu variabilele statice. Ele ocup
tot timpul aceeai zon de memorie i deci ele pstreaz valoarea la reapel.
Orice apel al unei funcii conduce la o revenire din funcia respectiv la punctul urmtor celui din
care s-a realizat apelul. Atunci cnd se revine dintr-o funcie se procedeaz la curirea stivei, adic stiva
se reface la starea ei dinaintea apelului. De aceea, orice apel al unui apel recursiv va conduce i la
curirea stivei, la o revenire din funcie, i deci parametrii i variabilele locale vor reveni la valorile lor
dinaintea reapelului respectiv. Numai variabilele statice rmn neafectate la o astfel de revenire.
Procesele recursive sunt strns legate de procesele iterative. Secvena iterativ presupune
execuia repetat a unei secvene de instruciuni, pn la ndeplinirea unei condiii (while, do-while, sau
for din C). Recursivitatea se refer la executarea repetat a unei secvene de instruciuni, ns pe parcursul
execuiei (nu la sfrit, ca n cazul iteraiei), se va verifica o condiie a crei valoare de neadevr implic
reluarea execuiei secvenei de instruciuni de la nceput, fr ca execuia curent s se fi terminat. n
momentul ndeplinirii condiiei, se va reveni n ordine invers din secvena de apeluri, relundu-se i
finalizndu-se apelurile suspendate.
Funciile recursive se utilizeaz la definirea proceselor recursive de calcul. Un proces de calcul
se spune c este recursiv, dac el are o parte care se definete prin el nsui. Un exemplu simplu de astfel
de funcie este funcia de calcul al factorialului, care se poate defini astfel:
factorial(n)=1, dac n=0, altfel
factorial(n)=n* factorial(n-1)

Alternativa:
factorial(n)=n* factorial(n-1)

definete funcia factorial(n) prin ea nsi.

Un proces recursiv trebuie mereu s conin o parte care nu se definete prin el nsui. n exemplul
de mai sus, alternativa:
factorial(n)=1, dac n=0

este partea care este definit direct.


Definiia de mai sus se transmite imediat n limbajul C:
double factorial(int n)

{
if (n==0)
return 1.0;
else
return n*factorial(n-1);
}

S urmrim execuia acestei funcii pentru n=3. La apelul din funcia principal se construiete o
zon pe stiv n care se pstreaz adresa de revenire n funcia principal, dup apel, precum i valoarea
lui n, aa cum este prezentat n figura de mai jos:

rev

adr1

adresa de revenire n funcia care a fcut apelul.

figura 1

Deoarece n>0, se execut alternativa else. Aceasta conine expresia:


n*factorial(n-1);

care autoapeleaz (direct) funcia factorial. Reapelarea funciei se realizeaz cu valoarea n-1=3-1=2.
prin aceasta se construiete o zon nou pe stiv, care conine revenirea la evaluarea expresiei de mai
sus, precum i valoarea nou a parametrului n, adic valoarea 2. Se obine starea din figura de mai jos:
rev

adr2

rev

adr1

adresa de revenire la evaluarea expresiei n*factorial(n-1);

figura 2

La o nou reapelare a funciei factorial, n=2>0, deci din nou se execut alternativa else. Evaluarea
expresiei conduce la o reapelare cu valoarea n-1=2-1=1. Se obine urmtoarea configuraie a stivei:

rev

adr3

rev

adr2

rev

adr1

adresa de revenire la evaluarea expresiei n*factorial(n-1);

figura 3

Iari n=1>0 i deci se face o nou reapelare i se obine configuraia:


rev

adr2

rev

adr2

rev

adr2

rev

adr1

adresa de revenire la evaluarea expresiei n*factorial(n-1);

figura 4

n acest moment n=0, deci se revine din funcie cu valoarea 1. Se cur stiva i se revine la
configuraia din figura 3. Adresa de revenire permite continuarea evalurii expresiei n*factorial(n-1). n
acest moment n are valoarea 1 i cum s-a revenit tot cu valoarea 1, se realizeaz produsul:
1*1=1

Dup evaluarea expresiei n*factorial(n-1) se realizeaz o nou revenire tot cu valoarea 1. Dup
curirea stivei se ajunge la configuraia din figura 2. n acest moment n are valoarea 2. Evalund expresia
n*factorial(n-1) se realizeaz produsul:
2*1=2

Apoi se revine din nou la funcia cu valoarea 2. Dup curirea stivei se ajunge la configuraia
din prima figur. n acest moment n are valoare 3. Se evalueaz expresia n*factorial(n-1) i se obine:
3*2=6

Se revine din funcie cu valoarea 6 (3!) i conform adresei de revenire, se revine n funcia
principal din care s-a apelat funcia factorial.
Programul care calculeaz factorialul unui ntreg preluat de la tastatur este prezentat n
continuare.
Ex. S se realizeze un program care calculeaz factorialul unui ntreg preluat de la tastatur.
#include <stdio.h>
main()
{
int n;
printf("Introduceti intregul pentru care se va calcula factorialul:");
scanf ("%d",&n);
printf("fact(%d)=%d",n,factorial(n));
}
factorial(int n)
{
if(n==0)
return 1;
else
return n*factorial(n-1);
}

Referitor la funciile recursive, trebuie specificat faptul c recursivitatea constituie un nou tip de
mecanism de control al programului. Din acest motiv, fiecare funcie recursiv va avea o instruciune if
care controleaz dac funcia se va apela pe ea nsi din nou sau dac va reveni n programul apelant.
Fr o astfel de instruciune, o funcie recursiv va rula necontrolat, folosind toat memoria alocat
stivei, conducnd n final la o blocare a calculatorului.
Recursivitatea poate fi util n simplificarea anumitor algoritmi. Spre exemplu, algoritmul de
sortare Quicksort este foarte dificil de implementat dac nu se folosete recursivitatea.

Ex. S se realizeze un program care afieaz descresctor (sau cresctor) numerele de la n la 0 (sau
0 la n) folosind o funcie recursiv, unde n este un ntreg introdus de utilizator.
#include <stdio.h>
main()
{
int n;
printf("Introduceti n>");
scanf("%d",&n);
afisare(n);
}
afisare(int n)
{
if (n>=0)
{
printf("%d ",n);
afisare(n-1);
}
}

Pentru afiarea numerelor n ordine cresctoare, n corpul instruciunii if se va inversa ordinea


celor dou instruciuni.
Ex: Calculul cmmdc (a,b), unde a i b sunt dou numere ntregi introduse de utilizator.
a=28, b=12
1. Metoda restului:
a=b
b=a%b
dac b=0 cmmdc=a
a=
b=

28
12

12
4

dac b=0
afieaz cmmdc=a
altfel
calculeaz cmmdc (b, a%b)
2. Metoda scderilor succesive:
dac a=b cmmdc = a
dac a>b se calculeaz cmmdc (a-b,b)
dac b>a se calculeaz cmmdc (a,b-a)

4
0

a=
b=

28
12

16 (28 - 12)
12

4 (16 - 12)
12

dac a=b
afieaz cmmdc=a
altfel
dac a>b
calculeaz cmmdc (a-b, b)
altfel
calculeaz cmmdc (a, b-a)

4
8 (12 - 4)

4
4 (8 - 4)

S-ar putea să vă placă și