Sunteți pe pagina 1din 16

Recursivitate

Constantinescu Catalin Lazaroiu Alexandru Ivascu Ioana Chirila Paul

Recursivitatea este un mecanism general de elaborare a algoritmilor. O functie se numeste recursiva daca ea se autoapeleaza, fie direct (in definitia ei, se face apel la ea insasi), fie indirect (functia X apeleaza functia Y, care apeleaza functia X). Recursivitatea a aparut din necesitati practice date de transcrierea directa a formulelor matematice recursive. Apoi, acest mecanism a fost extins, fiind utilizat in elaborarea multor algoritmi. Pornim de la un exemplu : Sa se calculeze n ! Se observa ca n !=(n-1) !*n si se stie ca 0 !=1. Asadar : 5 !=4 !*5 4 !=3 !*4 3 !=2 !*1 1 !=0 !*1 0 !=1 (prin conventie matematica) Definitia recursiva a lui n ! este :

Functia recursiva se va scrie astfel:


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

void main() {cout<<factorial(5) ;} Se observa ca functia factorial se autoapeleaza. Autoapelul se realizeaza prin instructiunea return factorial(n-1)*n.

Sa vedem care este mecanismul prin care subprogramele se pot autoapela. Se stie ca la apelul fiecarui subprogram, se genereaza un nou nivel in segmentul de stiva, corespunzator acelui apel. Pe acel nivel se memoreaza : valorile parametrilor transmisi prin valoare adresele parametrilor transmisi prin referinta variabilele locale In capitolul anterior s-au discutat proprietatile structurii de date numita stiva. Exact aceleasi proprietati are si segmentul de stiva, numai ca acesta este gestionat automat de catre calculator, nu de catre programator. De fiecare data cand o functie se autoapeleaza, se creeaza un nou nivel in segmentul de stiva.

Fiecare apel de functie lucreaza cu datele aflate pe nivelul corespunzator acelui apel. La iesirea din apelul unei functii, nivelul respectiv se elibereaza si datele aflate acolo se pierd. Exista posibilitatea ca subprogramul sa lucreze direct cu variabilele globale, dar in acest caz, subprogramul isi pierde independenta.

Cum gandim un algoritm recursiv ?


Iata cateva exemple de rationament recursiv : O camera de luat vederi are in obiectiv un televizor care transmite imaginile primite de la camera. In televizor se vede un televizor in care se vede un televizor Anunt : Azi nu se fumeaza ! O gandire recursiva exprima concentrat o anumita stare, care se repeta la infinit. Aceasta gandire se aplica in elaborarea algoritmilor recursivi cu o modificare esentiala: adaugarea conditiei de terminare. In absenta acestei conditii nu se poate vorbi despre un algoritm deoarece acestia sunt finiti. Din acest punct de vedere, exemplele de mai sus nu sunt corecte.Atunci cand gandim un algoritm recursiv, privim problema la un anumit nivel. Ce se intampla la acel nivel se va intampla la toate celelalte.

Observatii : In cazul unui numar mare de autoapelari, exista posibilitatea ca segmentul de stiva sa se ocupe total, caz in care programul se va termina cu eroarea STACK OVERFLOW. Aceasta se intampla mai ales atunci cand conditia de terminare este pusa gresit si subprogramul se apeleaza la nesfarsit. Pentru orice algoritm recursiv exista unul iterativ care rezolva aceeasi problema. Mecanismul recursivitatii inlocuieste instructiunile repetitive. Datorita faptului ca la fiecare autoapel se ocupa o zona de memorie, recursivitatea este eficienta numai daca numarul de autoapelari nu este prea mare pentru a nu se ajunge la umplerea zonei de memorie alocata. Recursivitatea ofera avantajul unor solutii mai clare pentru probleme si a unei lungimi mai mici a programului. Ea prezinta insa dezavantajul unui timp mai mare de executie si a unui spatiu de memorie alocata mai mare. Este de preferat ca atunci cand programul recursiv poate fi transformat cu usurinta intr-unul iterativ sa se faca apel la cel din urma (vezi sirul lui Fibonacci)

Sirul lui Fibonacci


Sirul Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ..., in care primii doi termeni sunt 0 si 1, iar in rest, fiecare termen se obtine insumand cei doi termeni care il preced. Prin urmare, o definitie recursiva pentru sirul lui Fibonacci este: fib: N -> N fib(n) = n daca n<=1 si fib(n) = fib(n-1) + fib(n-2) daca n > 1. unsigned long fibo ( int x) { if (x <= 1) return x; return fibo (x-2) + fibo(x-1); } Observatie: Este absolut necesar sa se asigure iesirea din recursivitate. Pentru aceasta va exista o conditie de iesire.

Probleme
1. Sa se scrie o functie recursiva care primeste 3 parametri: n - numar natural, c1,c2 cifre si returneaza numarul obtinut din n prin inlocuirea tuturor aparitiilor cifrei c1 cu c2. Ex. din n=2324, c1=2 si c2=5 returneaza 5354 2. Sa se scrie o functie recursiva care sa afiseze descompunerea in factori primi a unui numar natural.

3) Se citeste un vector a cu n elemente numere naturale. Sa se calculeze elementul maxim din vector. Se va folosi o functie recursiva pentru citire si una recursiva pentru determinarea elementului maxim. 4) Sa se calculeze CMMDC al doua numele naturale folosind o functie recursiva.

5) Sa se determine cifra maxima a unui numar natural folosind o functie recursiva. 6) Sa se scrie o functie recursiva pentru calculul rasturnatului unui numar natural.

Rezolvari
1) #include<iostream.h> long schimba(long n, int c1, int c2) { if(n==0) return 0 else if(n%10==c1) return schimba(n/10)*10+c2; else return schimba(n/10)*10+n%10; } void main() { cout<<schimba(23362,2,4); } 1) #include<iostream.h> void desc(int n, int d) { if(n>1) if(n%d==0) { cout<<d<<" "; desc(n/d,d); } else desc(n,d+1); } void main() { desc(234,2); }

3) #include<iostream> using namespace std; int max(int a[100], int i, int j) { if(i==j) return a[i]; else { int m=(i+j)/2; int m1=max(a,i,m); int m2=max(a,m+1,j); if(m1<m2) return m2; else return m1; } } void citire(int a[100], int n) { if(n>0) { citire(a,n-1); cin>>a[n]; } } void afis(int a[100],int n) { if(n>0) { afis(a,n-1); cout<<a[n]<<" "; } } int main() { int n,a[100]; cin>>n; citire(a,n); afis(a,n); cout<<max(a,1,n); system("pause"); return 0; }

4) #include<iostream> using namespace std; int cmmdc(int x, int y) { if(x%y==0) return y; else return cmmdc(y,x%y); } int main() { cout<<cmmdc(15,55); system("pause"); return 0; }

5) #include<iostream> using namespace std; int max(int n) { if ( n <= 9 ) return n; else { int m = max(n/10); if ( m > n%10 ) return m; else return n%10; } } int main() { cout << max(23614); system("pause"); return 0; }

6) #include<iostream> using namespace std; int rast(int n, int r) { if ( n == 0 ) return r; else return rast(n/10,r*10+n%10); } int main() { cout <<rast(23456,0); system("pause"); return 0; }