Sunteți pe pagina 1din 17

Subprograme- recursivitatea în cascadă

Să repetăm: ce înseamnă n!
3!=6
5!=120
dar 0!=1 ? (prin def.)
Dar în C++ cum vom calcula factorialul?
P:=1;
For I:=1 to n do
P:=p*i;
Scrie p;

RECURSIVITATEA ÎN CASCADA
Sa analizam Algoritmul pentru calculul sirului lui Fibonacci în varianta iterativa si în varianta recursiva.
Enunt : Sa se determine primele n numere ale sirului lui Fibonacci, unde n este este un numar natural citit de a
tastatura. (exp: n=8, => {1, 1, 2, 3, 5, 8, 13, 21})

Fişa B Recursivitatea în cascadă

Sa analizăm algoritmul pentru calculul şirului Fibonacci în varianta iterativa şi în varianta


recursivă.
Enunt : Sa se determine primele n numere ale sirului lui Fibonacci, unde n este este un numar natural
citit de a tastatura. (exp: n=8, => {1, 1, 2, 3, 5, 8, 13, 21})

Varianta iterativă

fibo1, fibo2 = elementele initiale


Date de intrare : n = câte elemente ale sirului lui Fibonacci vor fi calculate
Date intermediare : i = contor care numara elementele generate
Date de ieşire : fibo3 = elementul generat
Algoritmul constă în generarea celui de-al treilea element (fibo3) cunoscându-
le pe precedentele două ( fibo1 si fibo2), după care fibo1 fibo2 si fibo2 fibo3
fibo(0) =0

fibo(1) =1

Recursiv
Iterativ

fibo(2)= fibo(0)+fibo(1)=0+1=1

fibo(3) =fibo(1)+fibo(2)=1+1=2

fibo(4)= fibo(2)+fibo(3)=1+2=3

………….

fibo(n) = fibo(n-2)+fibo(n-1)
PROGRAM C++ (varianta iterativa)

#include<iostream>
// n – numarul de elemente;
using namespace std;
// i – contor i€[3,n], deoarece primele doua elemente
int main(){ sunt a1 1 si a2 1;
int n, fibo1=1, f ibo2=1, fibo3, i; // fibo1, fibo2, fibo3 – elementele şirului lui Fibonacci
cout<<"n="; cin>>n;

cout<<fibo1<<" "<<fibo2<<" ";

for (i=3; i<=n; i++) /*se repeta de n-3 ori generarea unui numar al sirului lui
Fibonacci fibo3=fibo1+fibo2; se genereaza un nou element*/

cout<<fibo3<<" ";

fibo1=fibo2;

fibo2=fibo3;

} return 0; }

VARIANTA RECURSIVĂ

Se defineşte şirul lui Fibonacci, prin funcţia fibo:N N:


0 pentru n=0;
fibo(n)= 1 pentru n=1
fibo(n-1)+fibo(n-2) pentru i>1
PROGRAM C++ (varianta recursiva)

#include<iostream>
using namespace std;
int n; //n- variabilă globală
int fibo(int n)
{ // n- este declarat variabila n ca variabilă locală
if (n==0) return 0;
else if (n==1)
return 1;
else return fibo(n-1)+fibo(n-2);
}
int main()
{ // n – numarul de elemente (variabila globala);
cout<<"n="; cin>>n;
cout<< "Termenul "<< n<< " al sirului lui Fibonacci este"<<f ibo(n);
return 0;

O astfel de recursivitate se numeşte recursivitate în cascadă deoarece se reapelează.


Observaţii:

Pentru calculul lui fibo(n) este necesar sa se cunoasca fibo(n-1) si fibo(n-2), deci se execută
autoapelul de două ori în cazul general.
Parametrii acestor functii sunt depusi în stivă. Procedeul continuă pâna când este calculat
fibo(n-1), apoi se reia calculul pentru fibo(n-2).
Acest lucru este extrem de ineficient pentru valori mari ale lui n.
Acest tip de recursivitate este un exemplu în care programul iterativ este mult mai eficient
decât programul recursiv.
fibo(4)  fibo(3)  fibo(2)  fibo(1)=1

3 2
+

fibo(0)=0

+ fibo(1)=1

fibo(2)  fibo(1)=1

1 +
Adâncimea recursivităţii pentru apelulfibo(0)=0
fibo(4) este 9:

Dacă notăm cu ar(n) adâncimea recursivităţii pentru apelul fibo(n) observăm că:

ar(1)= ar(0)=1

ar(2)=1+ ar(1)+ ar(0)=1+1+1=3


ar(3)=1+ ar(2)+ ar(1)=1+3+1=5

ar(4)=1+ ar(3)+ ar(2)=1+5+3=9

…….

ar(5)=1+ ar(4)+ ar(3)=1+9+5=15

ar(6)=1+ ar(5)+ ar(4)=1+15+9=25

ar(7)=1+ ar(6)+ ar(5)=1+25+15=41

……………

ar(n)=1+ ar(n-1)+ ar(n-2)

Temă :

1. Să se afişeze toţi termenii şirului lui Fibonacci mai mici decât un numar natural n introdus de la
tastatură. (inclusiv matricea de valori)

2. Să se scrie un algoritm pentru afişarea termenului n din urmatoarele şiruri :

an=an-1+bn-1;

bn=(bn-1)2-(an-1)2
Fişa C Fixare de cunoştinţe:
o Încercaţi parcurgerea următoarelor programe în C++ şi matricea de variaţie:

Analizaţi şi explicaţi rolul fiecărei linii


# include <iostream> #include <iostream>
using namespace std; using namespace std;
void f1 () void f1 (int k)
{ {
cout << "123 abc"; for (int i=1; i<=k ; i++)
} cout << "abc"<< " ";
void main () }
{ int main ()
f1(); {
} f1(5);
}
Se va afisa: Se va afişa:
123 abc abc abc abc abc abc

Funcţia nu returnează o valoare Funcţia nu returnează o valoare


Funcţia nu are parametri Funcţia are un parametru formal de tip int
Apelul funcţiei este o instrucţiune de Apelul funcţiei este o instrucţiune de apel simplă şi se face cu ajutorul
apel simplă unui parametru actual care este de acelaşi tip cu tipul parametrului
formal corespunzător
Să se testeze dacă un număr este prim sau nu

#include <iostream> # include <iostream>


#include <math.h> # include <math.h>
using namespace std; using namespace std;
int prim (int x) int prim (int x)
{ {
int nr_div=0; for (int i=2; i<=sqrt(x); i++)
for (int i=2; i<=sqrt(x); i++) if (x%i==0)
if (x%i==0) return 0;
nr_div++; return 1;
if (nr_div==0) }
return 1;
else int main ()
return 0; {
} int N;
cout << "N="; cin >> N;
int main () if (prim(N))
{ cout << "PRIM";
int N; else
cout << "N="; cin >> N; cout << "NU E PRIM";
if (prim(N)) }
cout << "PRIM";
else
cout << "NU E PRIM";
}

Funcţia returnează o valoare de tip În cazul în care se întâlneşte un divizor a lui x se execută
int instrucţiunea return 0. Astfel apelul funcţiei se încheie.
Funcţia are un parametru formal de
tip int Dacă x este număr prim, instrucţiunea return 0 nu se execută
Rezultatul funcţiei este utilizat în niciodată şi în acest caz, după terminarea execuţiei instrucţiunii for, se
cadrul unei expresii de testare (IF) execută instrucţiunea return 1 (care determină încheierea execuţiei
funcţiei).

o Se citeşte un număr natural n. Să se calculeze utilizând varianta iterativă şi varianta


recursivă suma primelor n numere naturale.

(exp: n=4 => s=1+2+3+4=10)

În varianta iterativa definitia În varianta recursiva definitia functiei se face printr-


functiei se face printr -o o expresie care contine însas i functia:
expresie care contine numai
valori cunoscute.
0 pentru n=0; 0 pentru n=0;
Suma(n)= Suma(n)=
1+2+3+…+n pentru n+Suma(n-1) pentru n!=0
n!=0

PROGRAM C++ (varianta iterativa) PROGRAM C++ (varianta recursiva)

#include<iostream.h> #include<iostream.h>
using namespace std; using namespace std;
int suma(int n){ int suma(int n){
int i, s=0 ; if (n==0)
if (n==0) return 0;
return 0; else
else{ return n+suma(n-1);
for (i=1 ; i<=n ; i++) }
s+=i ; // s=s+i int main(){
return s ; int n;
} cout<<"n="; cin>>n;
} cout<<"Suma="<<suma(n)<<endl;
int main(){ return 0;
int n; }
cout<<"n="; cin>>n;
cout<<"Suma="<<suma(n);
return 0;
}

Observaţii varianta recursivă:

1. Recurenţa este realizată prin autoapelul functiei suma.

2. Pentru calcularea sumei sunt necesare doua elemente :

- Formula de recurenta : suma(n)=n+suma(n-1);

- O valoare iniţiala cunoscută : suma(0)=0;

3. Numele functiei poate sa apara si în membrul stâng al unei instructiuni de


atribuire.

4. Ideea de baza a recursivitatii este aceea ca fiecare nou apel al functiei


(autogenerarea unui nou proces de acelasii fel) ne apropie de solutia finala care
corespunde valorii initiale cunoscute.
o Se citeşte un numar natural n. Să se calculeze utilizând varianta iterativă
şi varianta recursivă factorialul numarului n. (exp: n=4 => n!=1*2*3*4=24)
o

PROGRAM C++ (varianta iterativa) PROGRAM C++ (varianta recursiva)

#include<iostream.h> #include<iostream.h>
using namespace std; using namespace std;
int fact(int n){ int fact(int n){
int i, p=1; if (n==0)
if (n==0) return 1;
return 1; else
else{ return n*fact(n-1);
for (i=1 ; i<=n ; i++) }
p=p * i; int main(){
return p; int n;
} cout<<"n="; cin>>n;
} cout<<n<<"!="<<fact(n);
int main(){ return 0;
int n; }
cout<<"n="; cin>>n;
cout<<n<<"!="<<fact(n);
return 0;
}
În varianta iterativa definitia functiei se face În varianta recursiva definitia functiei se face printr-o
printr -o expresie care contine numai valori expresie care contine însăşi functia:
cunoscute. 1 pentru n=0;
1 pentru n=0; Fact(n)=
Fact(n)= n*Fact(n-1) altfel
1*2*3*…*n altfel

o Se citeste un numar natural n. Să se calculeze utilizând varianta iterativă şi


varianta recursiva suma cifrelor numarului n.

(exp: n=1325 => s=1+3+2+5=11)

În varianta iterativa definitia functiei se face În varianta recursiva definitia functiei se face printr-o
printr -o expresie care contine numai valori expresie care contine însăşi functia:
cunoscute. 0 pentru n=0;
0 pentru n=0; S (n)=
S(n)= n%10+S(n/10) altfel
s+(n%10); n=n/10; altfel
PROGRAM C++ (varianta iterativă) PROGRAM C++ (varianta recursivă)

#include<iostream.h> #include<iostream.h>
using namespace std; using namespace std;
int suma_cifre(int n){ int suma_cifre(int n)
int s=0 ; {
while (n!=0){ if (n==0)
s+=n%10; // s=s+n%10 return 0;
n/=10; // n=n/10 else
} return n%10+suma_cifre(n/10);
return s ; }
} int main(){
int main(){ int n;
int n; cout<<"n="; cin>>n;
cout<<"n="; cin>>n; cout<<"Suma="<<suma_cifre(n);
cout<<"Suma="<<suma_cifre(n); return 0;
return 0; }
}
Test – Subprograme

1. Explicaţi noţiunile de parametrii locali, parametrii globali. (1p)


2. Stabiliti valoarea de adevar a fiecaruia dintre urmatoarele enunturi (1p)
a) Subprogramele reprezinta acele parti ale unui program ce corespund subproblemelor in care
este descompusa o problema complexa. (0,25p)
b) Parametri definiţi în antetul unui subprogram se numesc formali, iar cei care apar la apelul
subprogramului se numesc actuali (0,25p)
c) Corpul unui subprogram trebuie cuprins între {…} numai daca este alcatuit din cel puţin
două instrucţiuni distincte (0,25p)
d) La transmiterea prin valoare, parametri actuali pot fi: constante, variabile, valori ale unor
expresii, valori returnate de alte functii. (0,25p)
3. Folosind doua functii recursive, sa se calculeze valoarea functiilor matematice f(x) si g(x),
pentru o valoare a argumentului x introdusa de la tastatura. (1p)

f(x)= 1+ g(x), pentru x <= 3 g(x)= 5 ,pentru x<0


x*x , pentru x > 3, 2*x + f(x+1), pentru x >=0
4. Completează următoarele enunţuri cu cuvinte potrivite astfel încât să obţii afirmaţii adevărate:
a) Unitatea de bază a oricărui program C++ este ______________ . Acesta este încapsulat într-o instrucţiune
_____________ delimitată de caracterele ________ . (0,25p)
b) Blocul este format din ____ părţi: partea ____________ şi partea _______________. (0,25p)
c) Subprogramul este _______________________________________________________ ___ __
_________________________________________________________________ (0,25p)
d) Definiţia subprogramului este formată din ___________ funcţiei şi _________ funcţiei. (0,25p)

5. Fie următoarea funcţie recursivă:

float F(float x, int n)


{
if (n<=2) return 2.0;
else return 2*x + F(x-1,n-1);
}
Dacă se execută următoarea secvenţă de instrucţiuni:
cout<<F(3.0, 2)<<” ”; cout<<F(3.0, 2)<<” ”; cout<<F(3.0, 2)<<” ”;

ce se va afişa :
a) 6 2 2
b) 2 8 8
c) 2 5 5
d) 1 7 7
6. Se consideră funcţia recursivă :

int F(int x)
{
if (x==0) return 0;
else if (x%3 == 0) return F(x/10)+1;
else return F(x/10);
}

Pentru ce valoare a lui x funcţia F va returna valoarea 4 :


a) 13369 b) 21369 c) 4 d) 123

Tema pentru acasa:


1. “Se întroduc 5 numere întregi. Să se adune numerele pare”.
2. “Se întroduc 5 numere întregi. Să se calculeze suma factorialelor şi puterilor”.

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