Sunteți pe pagina 1din 33

Recursivitatea

Recursivitatea este proprietatea unei entiti (algoritm, program, structur de date, figur etc.) de a putea fi descris prin entiti de acelasi tip cu ea nsi. Recursivitatea

este larg folosit n matematic i este, tot o dat, o tehnic important de elaborare a algoritmilor. Vom arata, de asemenea, c i unele structuri de date au caracter recursiv, ceeace faciliteaz

prelucrarea lor prin algoritmi recursivi.


Exist o strnsa legtur ntre recursivitate i raionamentul inductiv. Amintim c, n acest raionament, se stabilete c o

anumit proprietate P este valabil pentru toate elementele unui ir de entiti E1, E2, E3, ... Ek, Ek+1, .... Raionamentul conine doua etape: se stabilete c proprietatea P are
1.

loc pentru elementul E1 (eventual pentru un numr finit de elemente E1, E2, ..., Em); 2. se demonstreaz c, dac proprietatea P are loc pentru un element oarecare Ek, ea are loc i pentru elementul

urmtor Ek+1, deci este valabil pentru toate elementele irului.


Funcii, proceduri i metode recursive

Funcia recursiv este o funcie n corpul creia exist apeluri la ea nsi. n mod similar, o procedur n

corpul creia exist apeluri la ea nsi este recursiv. n programarea orientat pe obiecte, funciile i procedurile se realizeaz sub form de metode. n consecin, funciile i

procedurile recursive sunt metode recursive.


Exemple de funcii recursive: 1. Funcia factorial: fact(0)=1; fact(k)=k*fact(k-1)

pentru k>0 2. Funcia lui Fibonacci: fib(0)=fib(1)=1 fib(k)=fib(k1)+fib(k-2) pentru k>1 3. Funcia lui Ackerman Este un exemplu de funcie care

creste mai rapid decat cea exponenial i se definete astfel: Fie m i n numere naturale; ack(0, n) = n+1; ack(m, 0) = ack(m-1, 1) pentru m>0; ack(m, n) =

ack(m-1, ack(m, n1)) pentru m>0 si n>0. Remarcm c, n ultima linie a acestei definiii, are loc o dubl invocare recursiva a funciei: o dat pentru calcularea celui de al doilea argument i nc o

dat pentru calcularea valorii funciei.

Din exemplele de mai sus, constatm urmatoarele: n definiia unei funcii recursive trebuie sa fie obligatoriu

prevzute i condiii de terminare n care valoarea ntoars este calculat direct, fr a mai recurge la invocarea recursiv a aceleeai funcii;

algoritmul trebuie sa fie astfel conceput, nct dup efectuarea unui numar finit de apeluri recursive s fie satisfcute condiiile de terminare.

Exist i posibilitatea ca

recursia sa fie indirect: n corpul funciei f este invocat funcia g, iar n corpul funciei g este invocat funcia f. Cercul acestor invocri succesive poate sa conin mai mult de dou

funcii.
Procedurile nu au valoare ntoars, ci numai efect lateral. n consecin, folosirea procedurilor recursive se bazeaz pe cumularea efectelor laterale,

care const n modificarea valorilor unor variabile globale sau valorilor parametrilor procedurii. n limbajul Java nu exist variabile globale, dar pot fi modificate valorile unor cmpuri ale

clasei creia i aparine metoda recursiv sau ale unor componente ale obiectelor primite ca parametri.
Comparaie ntre iteraie i recursie

Aceeai funcie poate fi, de regul, calculat att printr-un algoritm

iterativ, ct i prin unul recursiv. Uneori ns, iteraia este mult mai rapid dect recursia i consum mai puin memorie. n schimb, utilizarea funciilor sau procedurilor recursive este mai

elegant i face algoritmul mai uor de neles i de verificat. n plus, folosirea recursivitii este o tehnic foarte eficient de concepere a algoritmilor. Din aceasta cauz, muli algoritmi

sunt concepui mai nti n varianta lor recursiv i apoi, numai dac aceasta variant necesit timp de calcul sau memorie prea mare, se caut i o variant iterativ.
De foarte multe ori,

trecerea de la varianta recursiv la cea iterativ a algoritmului se face nlocuind funcia recursiv printr-un ciclu. De exemplu, pentru calcularea factorialului, se poate folosi fie funcia recursiv
static long factorial(long n) throws Exception {

if(n<0) throw new Exception("Factorial arg<0: "+n);

if(n==0) return 1; // conditia de incheiere a recursiei

return n*factorial(n-1); // invocarea recursiv }

fie varianta iterativ


static long fact(long n) throws Exception { if(n<0) throw new Exception("Factorial arg<0: "+n);

long f=1; // initializarea ciclului

for(long i=2; i<=n; i++) f*=i; // ciclul de iterare

return f; }

Complexitatea

ambelor funcii este liniar O(n). Vom arta totui, c exist i situaii n care nlocuirea recursiei prin iteraie necesit folosirea unei structuri de stiv. Exemplu n fisierul Fibonacci.jav

a se d un exemplu de aplicaie n care se testeaz doua variante de calcul al funciei Fibonacci: varianta recursiv, care respect definiia dat mai sus, i varianta iterativ. Argumentul funciei se d ca argument

n linia de comand. Pentru fiecare din aceste variante se determin i timpul de calcul (n milisecunde). n acest scop, nainte i dup invocarea metodei respective se invoc metoda , care intoarce timpul
System.currentTimeMillis()

indicat de ceasul sistemului, i se face diferena, obinnd timpul de calcul n milisecunde. Este posibil ca, pentru valori mici ale argumentului funciei, durata de calcul n ambele variante s fie 0 (adic mai mic de o

milisecund). Se constat ns c la valori mai mari ale argumentului (peste 25) diferena dintre cele doua variante devine din ce n ce mai mare, n defavoarea celei recursive. Memoria ocupat este, de asemenea, mult mai

mare la varianta recursiv, unde se pun pe stiva sistemului toate datele de la invocrile intermediare ale funciei, n timp ce n varianta iterativ este necesar s se memoreze de la o iteraie la alta numai

doua valori: i . Explicaia este c cei doi algoritmi folosii pentru calculul funciei Fibonacci au complexiti diferite. n varianta iterativ exist un singur ciclu, care se parcurge de n-2 ori,
f1=fib(i1) f2=fib(i-2)

deci algoritmul are complexitate liniar O(n). n varianta recursiv, numarul de apeluri recursive ale funciei fibonacci(k) se obine ca suma unei progresii geometrice cu raia 2 i deci este de n ordinul 2 . ntr-

adevar, pentru calcularea lui fibonacci(n) este necesar sa se calculeze fibonacci( n-1) si fibonacci(n2). Pentru calcularea fiecreia din aceste valori sunt necesare alte dou apeluri ale funciei fibonacci i aa mai departe,

pn se ajunge la fibonacci(1). Complexitatea algoritmului recursiv este deci, n acest caz, n exponential O(2 ).

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