Documente Academic
Documente Profesional
Documente Cultură
RECURSIVITATE
if ( cond ) {
instrucțiune ;
while ( cond )
instrucțiune ;
}
Mecanismul apelului de funcţie. Apelul recursiv
Evaluarea unui apel de funcţie e declanşată atunci când valoarea funcţiei e necesară ı̂n
evaluarea unei expresii (inclusiv ı̂n execuţia unei instrucţiuni de forma expresie ; ). Ea se
efectuează ı̂n următorii paşi:
− se evaluează toate expresiile care constituie argumentele funcţiei. Deci orice apeluri
de funcţii care apar ı̂n argumente se efectuează ı̂nainte de apelul funcţiei considerate.
− valorile argumentelor se atribuie parametrilor formali din antetul funcţiei, cu
conversiile necesare de tip (de exemplu ı̂ntreg–real). Compatibilitatea de tip a
expresiilor argument e verificată deja la compilare, dacă se cunosc tipurile
parametrilor formali – un motiv ı̂n plus pentru care se cere ca o funcţie să fie
declarată ı̂nainte de a fi folosită.
− se execută corpul funcţiei, cu parametrii formali având valori iniţiale ca mai sus.
La ı̂ntâlnirea instrucţiunii return, execuţia funcţiei se ı̂ncheie cu valoarea obţinută prin
evaluarea expresiei date.
− execuţia programului revine la locul de apel, unde valoarea returnată de funcţie e
folosită.
La ı̂ntâlnirea instrucţiunii return, execuţia funcţiei se ı̂ncheie; orice alte instrucţiuni care
urmează ı̂n corpul funcţiei nu se mai execută. Dacă execuţia unei funcţii se termină prin
atingerea ultimei acolade } fără a executa o instrucţiune return, iar programul utilizează
valoarea funcţiei, efectul e nedefinit (programul se comportă imprevizibil). O funcţie care
nu prevede ı̂n orice situaţie o valoare returnată e scrisă eronat sub aspect logic.
Apelul recursiv
La un moment dat pot fi ı̂n execuţie mai multe apeluri diferite la aceeaşi funcţie. Fiecare
apel reprezintă o instanţă (copie) distinctă a funcţiei, cu propriile valori de parametri,
cele primite ı̂n momentul apelului. La fel se ı̂ntâmplă şi ı̂n calculul pe hârtie, prin
“desfăşurarea” formulei de recurenţă.
În funcție de procesele care se autoapelează, există două tipuri de recursivitate:
1. recursivitatea directă: fiecare apel recursiv generează un singur nou apel, până la
oprirea pentru cazul de bază. În acel moment, sunt active toate apelurile. Revenirea se face
ı̂n ordine inversă faţă de cea de apel: din fiecare apel se revine ı̂n instanţa care a efectuat
apelul. Aici, execuţia se reia ı̂n contextul dinainte de apel: adică din locul ı̂n care a fost
făcut apelul (unde e folosită valoarea returnată), şi cu acele valori ale parametrilor
corespunzând instanţei respective. Ca la orice apel de funcţie, informaţia se transmite spre
funcţia apelată prin parametri, şi ı̂napoi spre locul de apel (funcţia apelantă ) prin rezultat.
Rezultatul final e astfel efectul unui calcul ı̂n care câte un pas e efectuat de fiecare din
instanţele apelate. Aceasta e esenta recursivităţii şi ı̂n acelaşi timp puterea ei ı̂n rezolvarea
de probleme: ea permite exprimarea indirectă a soluţiei prin paşi simpli, din aproape ı̂n
aproape, fără a necesita formularea directă a unei soluţii complexe.
2. recursivitatea indirectă: există două procese care își generează reciproc apariția; în acest
caz trebuie să fie folosită obligatoriu declararea prin prototip a subprogramelor.
Recursivitatea ı̂n sintaxa limbajelor
Recursivitatea apare natural ı̂n definirea precisă a sintaxei limbajelor de programare. Multe
elemente de limbaj au ı̂n componenţă repetiţia, care poate fi exprimată recursiv. Astfel, antetul
unei funcţii poate fi definit (ı̂n limita celor prezentate până acum) ca:
antet-funcţie ::= tip identificator ( parametri )
parametri ::= void | lista-param
lista-param ::= tip identificator | tip identificator , lista-param
#include <iostream>
using namespace std;
int max(int a, int b)
{
if(a>b)
return a;
else
return max(b,a);
}
int min(int a, int b)
{
if(a<b)
return a;
else
return min(b,a);
}
int main()
{
int a,b;
cin>>a>>b;
cout<<"maximul="<<max(a,b)<<endl<<"minumul="<<min(a,b);
return 0;
}
Varianta 1 Varianta 2
#include <iostream>
using namespace std;
long generare_nr(long n)
{
int c;
cout<<"c=";
cin>>c;
if(c<0||c>9)
return n;
else
{
return generare_nr(n*10+c);
cout<<"c=";
cin>>c;
}
}
int main()
{
cout << generare_nr(0);
return 0;
}
#include <iostream>
using namespace std;
int suma(long n)
{
if(n==0)
return 0;
else
return suma(n/10)+n%10;
}
int main()
{
long n;
cin>>n;
cout << suma(n) << endl;
return 0;
}
c. Generarea inversului
#include <iostream>
using namespace std;
int inv(int n, int nr)
{
if(n==0)
return nr;
else
return inv(n/10,nr*10+n%10);
}
int main()
{
int n;
cin>>n;
cout << inv(n,0) << endl;
return 0;
}
#include <iostream>
using namespace std;
int prim(int n,int i)
{
if(i==1)
return 1;
else
if(n%i==0)
return 0;
else
return prim(n,i-1);
}
int main()
{
int n,ok;
cin>>n;
ok=prim(n,n/2);
if(ok==1)
cout<<"numarul este prim";
else
cout<<"numarul nu este prim";
return 0;
}
#include <iostream>
using namespace std;
void divizori(int n, int d)
{
if(d<=n/2)
{
if(n%d==0)
cout<<d<<" ";
divizori(n,d+1);
}
}
int main()
{
int n;
cin>>n;
divizori(n,2);
return 0;
}
#include <iostream>
using namespace std;
void conversie(int n, int q)
{
int c;
c=n%q;
if(n>=q)
conversie(n/q,q);
cout<<c;
}
int main()
{
int n,q;
cout << "n=" ;
cin>>n;
cout<<"baza=";
cin>>q;
conversie(n,q);
return 0;
}
#include <iostream>
using namespace std;
int n, v[20];
int gasit (int x, int i)
{
if(i==n)
return (x==v[i]);
else
return (x==v[i]) || gasit(x, i+1);
}
int main()
{
int i, x;
cin>> n;
for(i=1;i<=n;i++)
cin>>v[i];
cin>>x;
if(gasit(x,1))
cout<<"DA";
else
cout <<"NU";
return 0;
}
#include <iostream>
using namespace std;
int maxim(int v[20],int n)
{
if(n==1)
return v[n];
else
if(v[n]>maxim(v,n-1))
return v[n];
else
return maxim(v,n-1);
}
int main()
{
int n, v[20], i;
cin>>n;
for(i=1;i<=n;i++)
cin>>v[i];
cout<<maxim(v,n);
return 0;
}
#include <iostream>
using namespace std;
int suma(int n, int v[20])
{
if(n==0)
return 0;
else
return v[n]*(v[n]%2==0)+suma(n-1,v);
}
int main()
{
int n, v[20],i;
cout<<"n=";
cin>>n;
for(i=1;i<=n;i++)
cin>>v[i];
cout<<suma(n,v);
return 0;
}
Recursivitatea în cascadă:
Reprezintă un exemplu în care programul iterativ este mult mai eficient decât cel recursiv.
Pentru calculul termenului de ordin n al șirului lui Fibonacci se implementează funcția
descrisă mai jos:
0, 𝑝𝑒𝑛𝑡𝑟𝑢 𝑛 = 0
𝑓𝑖𝑏𝑜 𝑛 = 1, 𝑝𝑒𝑛𝑡𝑟𝑢 𝑛 = 1
𝑓𝑖𝑏𝑜 𝑛 − 1 + 𝑓𝑖𝑏𝑜 𝑛 − 2 , 𝑝𝑒𝑛𝑡𝑟𝑢 𝑛 > 1