Sunteți pe pagina 1din 8

Recursivitate

Un algoritm se numește recursiv dacă se autoapelează adică, dacă în corpul său există un modul care se autoapeleză.

Recursivitatea se realizează cu ajutorul subprogramelor. Un subprogram care se autoapelează se numește subprogram recursiv.

Prin urmare un algortim se numește recursiv sau un program se numește recursiv dacă conține cel puțin un subprogram care se autoapelează.

Recursivitatea este folosita cu multa eficienta in matematica. Spre exemplu, definitiile matematice recursive sunt:
Recursivitatea este folosita cu multa eficienta in matematica. Spre exemplu, definitiile matematice
recursive sunt:
Definitia functiei factorial
fact:N->N
fact(n) =
1, daca n=0
n*fact(n-1), daca n>0
Definitia functiei Ackermann
ac:NxN->N
ac(m,n)
=
n+1, daca m=0
ac(m-1,1), daca n=0
ac(m-1,ac(m,n-1)), daca m,n>0
Definitia functiei Fibonacci
fib:N->N
fib(n)=
0, daca n=0
1, daca n=1
fib(n-2)+fib(n-1), daca n>1
Recursivitatea se realizează în felul următor:
n>1 Recursivitatea se realizează în felul următor: - Din afara subprogramului facem un apel al subprogramului

- Din afara subprogramului facem un apel al subprogramului

- Dacă nu este îndeplinită o condiție (numită condiție de oprire), algoritmul se autoapelează de un anumit

număr de ori (până când e îndeplinită condiția). La fiecare nouă autoapelare a subprogramului se reexecută secvența de instrucțiuni din corpul său, eventual cu alte date, creându-se un lanț de autoapeluri recursive. Dacă condiția de oprire nu este îndeplinită niciodată sau nu există, algoritmul va avea un rezultat asemănător intrării într-un ciclu infinit.

Intuitiv, putem spune că un algoritm recursiv are același efect ca și o buclă (ciclu, instrucțiune repetitivă) – repetă execția unui set de instrucțiuni. În mod analog, deducem că repetarea nu trebuie să se realizeze de un număr infinit de ori. De aici provine necesitatea existenței condiției de oprire.

Prin urmare orice subprogram recursiv trebuie să îndeplinească următoarele condiții:

1. să se poată executa cel puțin o dată fără a se autoapela (când apare condiția de oprire);

2. toate autoapelurile să se producă astfel încât la un moment dat să se ajungă la îndeplinirea

condiției de oprire.

Cea mai mare parte a algoritmilor repetitivi se pot implementa într-o variantă nerecursivă (numită variantă iterativă) folosind instrucțiuni recursive, cât și într-o variantă recursivă atunci când conțin un modul definit recursiv.

Varianta de implementare rămâne la latitudinea programatorului.

Varianta recursivă este recomandată în cazul în care problemele sunt definite printr-o relație de recurență însă acest timp de algoritmi sunt mai greu de urmărit și de obicei necesită un timp de execuție mai mare.

1. succesiunea zilelor și nopților 2.
1.
succesiunea zilelor și nopților
2.

În viața de zi cu zi ne putem întâlni cu șiruri de elemente definite recurent ca de exemplu:

1.

se 1)

2.

șirul numerelor naturale (primul număr este 0; celelalte se obțin din precedentul adăugându-

suma numerelor naturale (inițial suma este 0; fiecare element care trebuie adăugat se adaugă

la suma obținută din elementele aflate înaintea lui)

3. șirul lui Fibonacci

4. cmmdc dintre 2 numere

5. etc

De asemenea ne înâlnim și cu alte elemente și fenomene care pot permite o reprezentare recursivă:

o cameră de luat vederi care este îndreptată spre o oglindă. Vă propun să vă

gândiți ce se vede în cameră.

Etc.

După cum am mai spus execuția subprogramelor recursive seamănă cu execuția instrucțiunilor repetitive. Difereța constă în faptul că autoexecuția, în cazul programelor recursive, nu se poate realiza de un număr infinit de ori deoarece la fiecare autoapel se păstrează în stiva calculatorului variabilele locale și parametrii trimiși prin valoare iar stiva are o dimensiune limitată.

ș i prin valoare iar stiva are o dimensiune limitată. Reamintim că Stiv a reprezintă o

Reamintim că Stiva reprezintă o succesiune ordonată de elemente, delimitată de două capete, în care adăugarea și eliminarea elementelor se poate face pe la un singur capăt, numit vârful stivei. Extragerea elementelor se realizează în ordine inversă introducerii lor.

În cazul unui subprogram recursiv (care este în același timp modul apelat și apelant) acest mecanism al stivei este de o foarte mare importanță: atunci când se execută un lanț de autoapeluri recursive, la fiecare autoapel variabilele locale și parametrii subprogramului recursiv se salvează pe stivă, iar la revenirea aceste valori sunt preluate din stivă în ordinea inversă a introducerii lor.

Cum lucrează un subprogram recursiv? Presupunem că dorim să găsim valoarea celui de-al n-lea termen din șirul lui Fibonacci. șirul este definit în felul următor:

F(0)=0, dacă n=0

F(1)=1, dacă n=1 F(n)=F(n-1)+F(n-2), dacă n>=2.

Ne propunem să găsim cât este f(7), adică cel de-al șaptelea termen din șirul lui Fibonacci. Apelăm funcția cu parametru 7 dar observăm că nu putem calcula decât dacă știm valorile termenilor al șaselea și al cincelea. Termenul al șaselea nu-l putem calcula decât dacă știm valorile termenilor al cincelea și al patrulea șamd.

F(7)=F(6)+F(5)

F(6)=F(5)+F(4)

F(5)=F(4)+F(3)

F(4)=F(3)+F(2)

F(3)=F(2)+F(1) F(2)=F(1)+F(0) F(1)=1 F(0)=0 ** //apel recursiv //varianta nerecursiva int fact(int n) int fact(int
F(3)=F(2)+F(1)
F(2)=F(1)+F(0)
F(1)=1
F(0)=0
**
//apel recursiv
//varianta nerecursiva
int fact(int n)
int fact(int n)
{
{
if(n==1)
int i,f;
return 1;
return n*fact(n-1);
for(i=f=1;i<=n;i++)
f*=i;
}
return f;
}

Ne întoarcem preluând din stivă rezultatele salvate. Vom calcula mai întâi pe F(2) pentru că știm cât este F(1) și F(0). F(2)=1+0=1. Știind cât este F(2) putem calcula pe F(3). F(3)=F(2)+F(1)=1+1=2. Acum putem calcula și pe F(4)=F(3)+F(2)=2+1=3. Avem toate elementele pentru a calcula și F(5)=F(4)+F(3)=3+2=5. Ne întoarcem și la F(6)=F(5)+F(4)=5+3=8. Acum putem să aflăm cât este al șaptelea termen din șirul lui Fibonacci: F(7)=F(6)+F(5)=8+5=13. După câte se observă autoapeluri tind să se execute până se ajunge la condiția de oprire (adică condiția în cazul în care rezultatele sunt cunoscute, în cazul nostru pentru n=0 și pentru n=1) și apoi se preiau rezultatele intermediare din stiva calculatorului în calculând termenii intermediari.

stiva calculatorului în calculând termenii intermediari. // Observatie: tipul functiei trebuie sa devina long pentru

// Observatie: tipul functiei trebuie sa devina long pentru // n>=8 ( 8!>32767 )

Se citeste n.Sa se calculeze termenul de ordin n al sirului lui Fibonacci in varianta recursiva

#include<iostream>

int n;

int f(int n)

{

if(n==0) return 0; else if(n==1) return 1;

else return f(n-1)+f(n-2);

}

int main()

{

cout<<"n=";cin>>n; cout<<"termenul de ordin "<<n<<" este: "<<f(n);

 

}

 

Exercitii:

 

** Sa se scrie o functie recursiva care calculeaza si returneaza suma cifrelor unui numar natural primit ca parametru.

 
 

#include<iostream.h>

 

int sumacif(long n)

 

{

if(n==0) return 0; else return sumacif(n/10)+n%10;

}

void main()

{

 

cout<<sumacif(23562);

 

}

**Sa se scrie o functie recursiva care sa afiseze descompunerea in factori primi a unui

**Sa se scrie o functie recursiva care sa afiseze descompunerea in factori primi a unui numar natural . using namespace std; #include<iostream> void desc(int n, int d)

{

if(n>1)

 

if(n%d==0) { cout<<d<<" "; desc(n/d,d);

 

}

 

else desc(n,d+1);

 

}

1

int main()

{

int main() { desc(28,2); } ** Sa se scrie o functie recursiva care primeste un parametru

desc(28,2);

}

** Sa se scrie o functie recursiva care primeste un parametru n numar natural si afiseaza:

1

2

     
 

1

2 3

#include<iostream> using namespace std; void afis(int n) { if(n>0)

{

 

1

2 3 4

n

 

#include<iostream>

using namespace std;

for(int i=1;i<=n;i++) cout<<i<<" "; cout<<endl;

 

afis(n-1);

 

void afis(int n)

}

{

if(n>0)

}

 

{

int main()

afis(n-1);

{

for(int i=1;i<=n;i++) cout<<i<<" ";

afis(6);

 

return 0;

 

}

4

cout<<endl;

}

}

int main()

{

afis(6);

return 0;

}

**Sa se determine cifra maxima a unui numar natural folosind o functie recursiva. #include<iostream>

folosind o functie recursiva. #include<iostream> using namespace std; int max(int n) { if ( n <=

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() {int n; cout<<"te gandesti la un numar:"; cin>>n; cout <<"cifra maxima este: "<< max(n);

return 0;

}

**Sa se scrie o functie recursiva care primeste ca parametru litera 'A' si afiseaza in ordine toate literele mari din

'A' si afiseaza in ordine toate literele mari din alfabet. using namespace std; #include<iostream>

alfabet.

using namespace std; #include<iostream>

void litere(char c) { if(c<='Z') { cout<<c<<" ";

litere(c+1);

}

}

int main() {char c; for(c='a'; c<='z';c++)

cout<<c<<" "; cout<<endl; litere('A');

}

**Sa se scrie o functie recursiva care primeste ca parametru un sir de caractere format din cel mult 100 de caractere litere mici si elimina toate vocalele din sir. #include <iostream> #include<string.h> using namespace std;

void elimin(char a[100])

{

if(strlen(a)>0)

if(strchr("aeiou",a[0]))

{ strcpy(a,a+1); elimin(a); } else elimin(a+1); } int main() { char a[100]="abracadabra"; elimin(a);
{ strcpy(a,a+1);
elimin(a);
}
else elimin(a+1);
}
int main()
{
char a[100]="abracadabra";
elimin(a);
cout<<a;
return 0;
}
**Sa se calculeze CMMDC al doua numele naturale folosind o functie recursiva.
#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(55,45);
return 0;
}
#include<iostream.h>

void litere(char c)

{ if(c<='Z') { cout<<c<<" ";

litere(c+1);

}

}

void main()

{

litere('A');

}

** Sa se scrie o functie recursiva care primeste un parametru n numar natural si returneaza numarul obtinut din

n prin scaderea cu 1 a cifrelor impare si marirea cu 1 a celor pare. Ex. din n=2324 returneaza 3235

using namespace std; #include<iostream>

long schimba(long n) { if(n==0) return 0; else if(n%2==1) return schimba(n/10)*10+n%10-1; else return schimba(n/10)*10+n%10+1;

}

int main()

{

else return schimba(n/10)*10+n%10+1; } int main() { cout<<schimba(23362); } ** Sa se scrie o functie

cout<<schimba(23362);

}

** Sa se scrie o functie recursiva care primeste un parametru n numar natural si returneaza numarul obtinut din

prin eliminarea cifrelor pare. Ex. din n=23524 returneaza 35

n

using namespace std; #include<iostream> long sterge(long n) { if(n==0) return 0; else if(n%2==1) return sterge(n/10)*10+n%10; else return sterge(n/10);

}

int main()

{

cout<<sterge(23562);

}

** Formulati un enunt:

#include<iostream>

} ** Formulati un enunt: #include<iostream> using namespace std; int n, a[100]; void citire(int a[100],

using namespace std; int n, a[100]; void citire(int a[100], int n)

{

if(n>0)

{ citire(a,n-1);

cin>>a[n];

}

}

int sumacif(int n)

{

if(n==0) return 0; else return n%10+sumacif(n/10);

}

int suma(int a[100], int n)

{ if(n==0) return 0; else return suma(a,n-1)+sumacif(a[n]); } int main() { cin>>n; citire(a,n);
{
if(n==0) return 0;
else return
suma(a,n-1)+sumacif(a[n]);
}
int main()
{
cin>>n;
citire(a,n);
cout<<suma(a,n);
return 0;
}