Sunteți pe pagina 1din 6

Algoritmi si structuri de date (6.12.

2012) Informatic, Matematic, anul 1

ASD_C08

ALGORITMI RECURSIVI Recursivitatea a aprut din necesiti practice, cum ar fi transcrierea direct a formulelor matematice recursive. Un exemplu de formul matematic recursiv este urmtoarea: (n+1)! = (n+1) n!, pentru n0 0! = 1 (prin convenie) Un subprogram este definit ca fiind recursiv dac, pornind de la anumite valori ale ei, se pot calcula alte valori prin autoapelarea subprogramului. Apelul poate fi fcut direct sau indirect (prin intermediul altei funcii). Valorile unei funcii recursive se calculeaz din aproape n aproape, pe baza valorilor cunoscute ale funciei pentru anumite argumente iniiale. Pentru a calcula noile valori ale funciei recursive, trebuie memorate valorile deja calculate care sunt strict necesare. Acest fapt face ca implementarea n program a calculului unor funcii recursive s necesite un volum mare de memorie. Recursivitatea poate fi transformat n iteraie (variant nerecursiv). n general, forma nerecursiv a unui algoritm este de preferat formei recursive, fiind mai eficient din punct de vedere al timpului de execuie i al memoriei ocupate. Forma recursiv este preferat datorit uurinei programrii sau acolo unde transformarea recursivitii n iteraie cere un efort de programare deosebit, algoritmul pierzndu-i claritatea exprimrii, testarea i ntreinerea devenind astfel foarte dificile. Exemplu de funcie recursiv: funcia n! pe care o notm cu factorial, factorial:NN si care se definete recursiv astfel 1, n = 0 factorial(n) = n factorial (n 1), n 1 Pentru a calcula factorial(4):
n=1

factorial(4) = 4 factorial(3) = 4 3 factorial(2) = 4 3 2 factorial(1)


n =0

n=4

n =3

n=2

= 4 3 2 1 factorial(0) = 4 3 2 1 1 = 4!

De fiecare dat cnd o funcie este apelat recursiv, pe stiva sistemului se rein parametrii (de exemplu valoarea lui n pentru determinarea factorialului) i eventualele variabile locale ale funciei. n cazul funciilor recursive se pune problema terminrii calculelor. Apelul unei funcii este terminat doar dac cauzeaz un numr finit de apeluri la aceea funcie sau la alte funcii. n funciile recursive trebuie s se garanteze terminarea apelurilor recursive prin inserarea condiiilor de terminare.

Exemple de programe ce folosesc subprograme recursive:

Algoritmi si structuri de date (6.12.2012) Informatic, Matematic, anul 1

ASD_C08

R1. Enunul problemei: S se descrie un algoritm pentru determinarea sumei factorialelor pn la n N* dat, folosind o funcie recursiv pentru calculul factorialului. Metoda de rezolvare: Problema se reduce la calcul unei sume: S = Descrierea algoritmului n pseudocod:
functie factorial(n) daca n=0 sau n=1 atunci returneaza 1 altfel returneaza nfactorial(n-1) sfarsit citete n S 0 pentru i = 1,n,1 repeta S S + factorial(i) scrie S

i!.
i =1

Descrierea algoritmului n C++: #include <iostream.h> int n,i; float S; float factorial(int n) { if (n==0) return 1; //else return n*factorial(n-1); } void main() { cout<<endl<<"Dati valoarea lui n (n>=1): "; cin>>n; //* presupunem ca n>=1 for (i=1;i<=n;i++) S += factorial(i); cout<<"Suma factorialelor pana la "<<n<<": "<<S; } R2. Enunul problemei: S se descrie un algoritm pentru determinarea celui mai mare divizor comun dintre n numere naturale nenule, folosind funcie recursiv pentru determinarea cmmdc-ului. Metoda de rezolvare: Determinarea cmmdc dintre mai multe numere se face iterativ prin determinarea cmmdc dintre primele dou, apoi ntre rezultat i urmtorul numr, .a.m.d. De exemplu, cmmdc(x1, x2, x3) = cmmdc(cmmdc(x1, x2), x3). Astfel, cmmdc(2, 4, 6, 8) = 2. Pe de alt parte, funcia cmmdc poate avea urmtoarele dou forme recursive: 1. folosind mpriri repetate: cmmdc(a,b) = cmmdc(b, a%b), dac b0; altfel este a. Pentru a = 20 i b = 12 se proceda nerecursiv astfel: 20 12 8 12 1 12 8 4 8 1 8 8 0 4 2 4 0

Algoritmi si structuri de date (6.12.2012) Informatic, Matematic, anul 1

ASD_C08

2. folosind scderi repetate: cmmdc(a,b) = cmmdc(a-b, b), dac a>b cmmdc(a, b-a), dac b>a a, a=b Pentru a = 20 i b = 12 se proceda nerecursiv astfel: a = 20 > b = 12 => a a-b => a = 20-12 = 8 a = 8 < b = 12 => b b-a => b = 12-8 = 4 a = 8 > b = 4 => a a-b => a = 8-4 = 6 a = 4 = b = 4. Stop. cmmdc(20,12) = 4. Descrierea algoritmului n pseudocod:
functie cmmdc(a,b) daca b=0 atunci returneaza a altfel returneaza cmmdc(b,a%b) sfarsit sau functie cmmdc(a,b) daca a=b atunci returneaza a altfel daca a>b atunci returneaza cmmdc(a-b,b) altfel returneaza cmmdc(a,b-a) sfarsit citete n, x1,,xn r = cmmdc(x1,x2) *se determina cmmdc-ul dintre primele 2 elem pentru i = 3,n,1 repeta *pentru celelalte r cmmdc(r,xi) scrie r

Descrierea algoritmului n pseudocod C++:


#include <iostream.h> int n,i,x[10],r; int cmmdc1(int a,int b) { /*cu impartiri repetate*/ if (b==0) return a; return cmmdc1(b,a%b); } int cmmdc2(int a,int b) { /*cu scaderi repetate*/ if (a==b) return a; if (a>b) return cmmdc2(a-b,b); return cmmdc2(a,b-a); } void main() { cout<<endl<<"Dati numarul de intregi pozitivi: "; cin>>n; cout<<"Dati cele n elemente intregi pozitivi: "; for (i=0;i<n;i++) cin>>x[i]; r = cmmdc1(x[0],x[1]); //se det cmmdc dintre primele 2 //sau r = cmmdc2(x[0],x[1]); for (i=2;i<n;i++) //se iau in calcul si celelalte r = cmmdc1(r,x[i]); cout<<"Cmmdc="<<r; }

Algoritmi si structuri de date (6.12.2012) Informatic, Matematic, anul 1

ASD_C08

R3. Enunul problemei: Descriei un algortim rezursiv pentru afiarea cifrelor unui numr ntreg nenul. Metoda de rezolvare: Ideea afirii cifrelor numrului n, de la cea a unitilor pn la prima este de a afia ultima cifr a lui n, apoi de a repeta procedeul pentru numrul n din care se omite ultima cifr, .a.m.d. Descrierea algoritmului n pseudocod:
procedura cifre(n) daca n0 atunci scrie n%10 cifre(n/10) sfarsit citete n cifre(n) *de la dreapta la stanga

Descrierea algoritmului n C++: #include <iomanip.h> #include <iostream.h> unsigned long n; void cifre(unsigned long n) { if (n) { //sau n!=0 cout<<setw(3)<<n%10; //se afiseaza ultima cifra cifre(n/10); //apoi repeta pt numarul fara ultima cifra } } void main() { cout<<endl<<"n="; cin>>n; cout<<"Cifrele numarului (de la ultima la prima): "; cifre(n); } Pentru a afia cifrele de la stnga la dreapta se schimb funcia C astfel (nti se apeleaz procedeul similar pentru numrul n fr ultima cifr, apoi se afieaz ultima cifr: void cifre2(int n) { if (n) { //n!=0 cifre2(n/10); //consideram numarul fara ultima cifra cout<<setw(3)<<n%10; //apoi se afieaza ultima cifra } } cifre2(123) cifre2 (12) cifre2(1) cifre2(0) afi.3 afi.2 afi.1

Algoritmi si structuri de date (6.12.2012) Informatic, Matematic, anul 1

ASD_C08

R4. Enunul problemei: Descriei un algortim pentru determinarea combinrilor de n luate cte k, folosind o funcie recursiv.
k k k 1 0 Metoda de rezolvare: C n = Cn 1 + C n1 , pentru n>k i k>0; altfel (pentru n=k sau k=0) C n =1,

n 2 1 2 2 1 0 1 0 1 0 Cn =1. De exemplu: C 4 = C3 + C3 = ( C2 + C1 2 ) + ( C 2 + C 2 ) = (1 + C1 + C1 ) + ( C1 + C1 +1) = =(1+1+1) + (1+1+1) = 6.

Descrierea algoritmului n pseudocod:


functie combinari(n,k) daca n=k sau k=0 atunci returneaza 1 altfel returneaza combinari(n-1,k)+combinari(n-1,k-1) sfarsit citete n,k scrie combinari(n,k)

Descrierea algoritmului n C++:


#include <iostream.h> int n,k; int combinari(int n,int k) { if (n==k || k==0) return 1; return combinari(n-1,k)+combinari(n-1,k-1); } void main() { cout<<endl<<"Dati valoarea lui n (n>=0): "; cin>>n; cout<<"Dati valoarea lui k (k>=0, k<=n): "; cin>>k; cout<<"Combinari de "<<n<<" luate cate "<<k<<": "<< combinari(n,k); }

R5. Enunul problemei: Descriei un algoritm pentru determinarea valoarii maxime dintre elementele unui vector, folosind o funcie recursiv. Metoda de rezolvare: maxim{x1,, xn} = maxim{ maxim{x1,, xn-1}, xn}. Descrierea algoritmului n pseudocod:
functie maxim2(a,b) //maxim dintre a si b daca a>b atunci returneaza a altfel returneaza b sfarsit functie maxim(x1 xn) //maxim din vectorul x de dim n daca n=2 atunci returneaza maxim2(x1,x2) altfel returneaza maxim2(maxim(x1,xn-1),xn) sfarsit citete n, x1 xn scrie maxim(x1 xn)

Algoritmi si structuri de date (6.12.2012) Informatic, Matematic, anul 1

ASD_C08

Descrierea algoritmului n C++: #include <iostream.h> #define maxim2(a,b) a>b ? a : b //maximul dintre 2 valori int n,i,x[10]; int maxim(int x[10],int n) { /*dintre x[0]...x[n-1]*/ if (n==2) return maxim2(x[0],x[1]); return maxim2(maxim(x,n-1),x[n-1]); } void main() { cout<<"n = : "; cin>>n; cout<<"Dati valorile: "; for (i=0;i<n;i++) cin>>x[i]; cout<<"Elementul maxim este: "<<maxim(x,n); } Tema 08 (suplimentar): 1) Descriei un algoritm recursiv pentru determinarea numrului lui Fibonacci de ordin n (irul lui Fibonacci este definit astfel: Fn = Fn-1 + Fn-2, pentru n2, iar F0 = F1 = 1; de exemplu F2 = 1+1 = 2, F3 = F2 + F1 = 2+1=3, F4 = F3 + F2 = 3+2=5). 2) Descriei un algoritm recursiv pentru afiarea invers a elementelor unui vector folosind o funcie recursiv (afiez ultimul elem, apoi apelez funcia void pentru restul vectorului). 3) Folosind funcii recursive, descriei algoritmul pentru afiarea elementelor unui vector folosind o funcie recursiv (apelez funcia pentru restul vectorului, apoi afiez ultimul element). 4) Determinai o funcie recursiv pentru calculul sumei Sn = 1 + 3 + 5 + + (2n-1), n1 i descriei un algoritm pentru calculul acestei sume. 5) Folosind recursivitatea, decriei un algoritm pentru a verifica dac un vector conine cel puin un numr negativ n primele n poziii. 6) Descriei un algortim recursiv pentru conversia unui numr din baza 10 n baza 2.