Sunteți pe pagina 1din 9

Seminar 3 - Atp

Recursivitate
Aspecte teoretice

Limbajul C admite scrierea de funcii recursive.


Tehnica de programare n care un subprogram se autoapeleaz.
Mecanismul prin care este efectuat apelul unui subprogram se bazeaz pe utilizarea stivei
memoriei calculatorului.
Fiecare apel determin introducerea n stiv a:
o valorilor parametrilor reali,
o a adresei de revenire
o i a variabilelor locale.
La momentul execuiei, aceste informaii snt extrase cu eliminare din stiv, eliberndu-se
spaiul ocupat.
Exemplu: n!

De exemplu, n cazul apelului fact(3), secvena de apeluri recursive este:


fact(2),
fact(1),
fact(0).
n continuare execuia determin :
fact(0)=1,
fact(1)=1*fact(0)=1,
fact(2)=2*fact(1)=2,
fact(3)=3*fact(2)=6.

1. Sa se calculeze produsul scalar a doi vectori recursiv.


Exemplu:
n=3
v[0]=1
v[1]=2
v[2]=3
q[0]=1
q[1]=2
q[2]=3
ProdScal =14
2. Sa se calculeze n factorial (n!) in urmatoarele moduri:
a) prin modul clasic (o singura, functia main)
b) folosind o functie pentru calcul (cu parametru transmis prin valoare)
c) folosind o functie pentru calcul (cu parametru transmis prin referinta)
d) folosind o functie recursiva
Exemplu numeric:
n=5
5!=120
Indicatii

a) prin modul clasic (o singura, functia main)


1. biblioteci: stdio.h, conio.h
2. in main :
se declara intregi: n, rez;
- se citeste n ;
rez=1;
Executa {
rez=rez*n;
n--;
}
Atat timp cat (n!=0);
-

afiseaza rezultatul rez

b) folosind o functie pentru calcul (cu parametru transmis prin valoare)


1. biblioteci
2. functie pentru factorial:
intreg factorial (intreg n)
{ intreg rez=1;
Executa {
rez=rez*n;
n--;
}
Atat timp cat (n>0);
intoarce (rez);
2

}
3. in functia main:
- se declara si se citeste n-ul
- se afiseaza rezultatul prin apelarea functiei factorial (n)
c) folosind o functie pentru calcul (cu parametru transmis prin referinta)
1. biblioteci
2. functie factorial:
void factorial(intreg n, intreg *rezRef)
{ *rezRef=1;
Executa {
*rezRef = *rezRef * n;
n--;
}
Atat timp cat (n!=0);
}
3.in functia main:
- declarare n si rez de tip intreg
- se citeste n;
- se apeleaza functia factorial (), exp: factorial(n, &rez2);
- se afiseaza rezultatul rez2
d) folosind o functie recursiva
1. biblioteci
2. functie factorial (metoda 1):
Intreg fact1(intreg n)
{
daca (n == 0)
return 1;
intoarce (n * fact1(n - 1));
}
3. functie factorial (metoda 2) - recursivitate folosind un argument suplimentar; acc
(acumulator) e 1 initial, varianta recomandata pentru numar mare de apeluri; acc
=1*2*3*4*5...
intreg fact2(intreg n, intreg acc)
{ daca (n == 0)
intoarce acc;
intoarce fact2(n - 1, acc * n);
}
4. in main:
- declarare n intreg;
- citire n;
- apelare functii pentru factorial:
printf("\n%d! = %d\n", n, fact1(n));
printf("\n%d! = %d\n", n, fact2(n, 1));

3. Scrieti programul care identifica valoarea unei pozitii din cadrul sirului lui
Fibonacci (sirul lui Fibonacci: n= 1,1,2,3,5,8,13 ). Se va rezolva prin urmatoarele
variante:
a) clasic, in functia main (o singura functie)
b) cu parametru transmis prin valoare
c) cu parametru transmis prin referinta
d) folosind o functie recursiva
Exemplu numeric:
n=5
fibo(5)=5
Indicatii
a)
1.
2.
-

clasic, in functia main (o singura functie)


biblioteci
in main:
declarare variabile intregi: i,n, rez1=1, rez2=1, rezFinal;
se citeste n ( n reprezinta pozitia din sir pentru care se doreste aflarea valorii
calcul sir:
daca ((n==1) || (n==2)) atunci rezFinal=1; // || sau
altfel
pentru (i=3;i<=n;i++)
{
rezFinal = rez1+rez2;
rez1=rez2;
rez2=rezFinal;
}
se afiseaza rezFinal (ex: printf("termenul de pe pozitia %d este %d ", n, rezFinal); )

b) cu parametru transmis prin valoare


1. biblioteci
2. functie sirFibo:
intreg sirFibo (intreg m)
{
intreg i, rez1=1, rez2=1, rezFinal;
daca ((m==1) || (m==2)) rezFinal=1;
altfel
pentru (i=3;i<=m;i++)
{
rezFinal = rez1+rez2;
rez1=rez2;
rez2=rezFinal;
}
return rezFinal;
}
3.
-

in main:
se declara intregi: n, rez1=1, rez2=1;
se citeste pozitia din sir (n);
se afiseaza valoarea din sir pentru pozitia solicitata ( printf("termenul de pe pozitia %d
este %d ", n ,sirFibo(n)) );

c) cu parametru transmis prin referinta


4

1. biblioteci
2. functia sirFibo:
void sirFibo (intreg m, intreg *rezFinal)
{
intreg i, rez1=1, rez2=1;
daca ((m==1) || (m==2)) *rezFinal=1;
altfel
pentru (i=3;i<=m;i++)
{
*rezFinal = rez1+rez2;
rez1=rez2;
rez2= *rezFinal;
}
}
3.in main:
- se declara intregi : n, rez1=1, rez2=1, rezFinal2;
- se citeste pozitia din sir (n)
- se apeleaza functia sirFibo si se afiseaza rezultatul:
sirFibo (n, &rezFinal2);
printf("termenul de pe pozitia %d este %d ", n , rezFinal2);

d) folosind o functie recursiva


1. biblioteci
2. functie recursiva pentru calcul sir (metoda 1):
intreg fibo1(intreg n)
{
Daca ((n == 1) || (n == 2))
intoarce 1;
intoarce fibo1(n - 2) + fibo1(n - 1);
}
3. functie recursiva pentru calcul sir (metoda 2 - folosind argumente suplimentare, varianta
recomandata pentru numar mare de apeluri )
intreg fibo2(intreg n, intreg acc1, intreg acc2)
{
daca (n == 1)
intoarce acc1;
intoarce fibo2(n - 1, acc2, acc1 + acc2);
}
4.in main:
- se declara n intreg;
- se citeste n (pozitia dorita);
- se apeleaza si afiseaza cele doua functii pentru sir:
printf("\nfibo(%d) = %d\n", n, fibo1(n));
printf("\nfibo(%d) = %d\n", n, fibo2(n, 1, 1));

4.Scrieti programul care calculeaza intr-un subprogram recursiv suma elementelor


unui vector.
1. Biblioteci
2. Se declara intregi: a[10], n; //declarate in afara functiei si in afara lui main (var. globale)
3. Functia recursiva pentru calcul suma:
intreg Suma (intreg n, intreg a[10])
{
Daca (n==0) intoarce 0;
altfel intoarce (a[n]+Suma(n-1,a));
}
4. In main
- Se declara intreg : i;
- Se citesc dimensiunea n si elementele vectorului a[] ;
- Se afiseaza rezultatul (prin apelarea functiei Suma() );
printf("Suma = %d", Suma(n,a));
5.Scrieti programul care contine subprogramul recursiv pentru calculul celui mai mare
divizor comun dintre doua numere naturale.
Exemplu numeric:
Introduceti x: 10
Introduceti y: 8
cmmdc(10,8) = 2
a) iterativ
b) recursiv
Indicatii
a) iterativ
1. biblioteci:
2. functie pentru cmmdc:
intreg cmmdc(intreg a, intreg b)
{
Atat timp cat (a!=b)
{
Daca (a>b)
a=a-b;
altfel
b=b-a;
}
intoarce a;
}

3. in main:
- se declara integi x si y;
- se citesc x si y de la tastatura;
- afisare rezultat:
daca (!x || !y)
//daca x=0 sau y=0
6

afisez ("cmmdc(%u,%u) = 1\n",x,y);


altfel
afisez ("cmmdc(%u,%u) = %u\n",x,y,cmmdc(x,y));
b) recursiv
1. Biblioteci
2. Functie recursiva pentru cmmdc:
intreg cmmdc(intreg a, intreg b)
{
Daca (a==b) intoarce a;
altfel
daca (a>b) intoarce cmmdc(a-b,b);
altfel intoarce cmmdc(a,b-a);
}
3. In
-

main:
Declarare intregi: x,y;
Se citesc x si y
Afisare rezultat:
if(!x || !y) //daca x=0 sau y=0
printf("cmmdc(%u,%u) = 1\n",x,y);
else
printf("cmmdc(%u,%u) = %u\n",x,y,cmmdc(x,y));

6.Scrieti un subprogram recursiv care calculeaza suma elementelor pare dintr-un


vector. Pentru citirea vectorului se va realiza un subprogram. Dimensiunea n va fi
citita in programul principal.
Exemplu:
n=5
v[0]=2
v[1]=4
v[2]=5
v[3]=6
v[4]=2
Rezultat suma: 14
Indicatie:
real suma(real *v, intreg n)
{ daca (n==0) intoarece 0;
altfel intoarce suma (n-1) + (v[n-1]%2 = = 0) * v[n-1];
}

Tema:
1. Scrieti un subprogram recursiv care calculeaza aranjamente de n luate cate k
(A(n,k)=n*A(n-1,k-1).
2. Scrieti un subprogram recursiv care calculeaza combinari de n luate cate k
3. Scrieti un subprogram recursiv care calculeaza numarul de elemente negative dintr-un
vector.
4. Scrieti un subprogram recursiv care calculeaza suma elementelor pare dintr-un vector.
5. Scrieti un program recursiv care rezolva problema turnurilor din Hanoi
6. Sa se scrie o functie recursiva pentru determinarea sumei cifrelor unui numar natural.
7

7. Sa se scrie subprogramul recursiv pentru a transforma un numar natural n, din baza 10 n


baza k (1<k<=10). Indicatie: Numarul se mparte la k, se retine restul, ctul se mparte la
k, se retine restul... pna cnd ctul este mai mic dect mpartitorul. Rezultatul se obtine
prin scrierea n ordine inversa a resturilor obtinute. Tiparirea restului se face dupa
autoapel.
8. Sa se scrie un program care primeste un numar variabil (maxim 100) de parametri de tip
int. Nu se stie numarul valorilor primite. Pentru a marca sfarsitul listei se foloseste
valoarea conventionala 0. Subprogramul trebuie sa creeze un vector cu valorile primite.

Indicatii
1. Biblioteci ce trebuie incluse: stdio.h, conio.h, stdarg.h, malloc.h
2.
int *lista_var2 (int *nr, ...)
{int i, *v, t;
va_list p; //va_list este tip declarat in stdarg.h.
/* va_list este un pointer catre lista de parametrii. In functia utilizator corespunzatoare
(lista_var2) trebuie declarata o variabila (numita p) de acest tip, care va permite adresarea
parametrilor*/
v=(int*)malloc(100*sizeof(int));
va_start(p, nr); //initializeaza variabila p cu adresa primului parametru din sublista variabila.
// Prototip: void va_start (va_list p, ultim), aici ultim = nr (numele ultimului
parametru din sub lista variabila).
*nr=0;
t=va_arg(p,int);// va_arg intoarce valoarea parametrului din sublista variabila.
//Prototip: tip_element va_arg(va_list p, tip_element), unde tip_element este tipul
elementului transferat din lista.
//Dupa fiecare apel al functiei va_arg, variabila p este modificata astfel incat sa
indice urmatorul parametru
while(t)
{ v[*nr]=t;
(*nr)++;
t=va_arg(p,int);
}
va_end(p); // va_end incheie operatia de extragere a valorilor parametrilor si trebuie apelata
inainte de revenirea din functie
// prototip: void va_end(va_list p)
free(v);
return v;
}
8

3. In main:
se declara: int *x, i,n;
x=lista_var2(&n, 1, 3, 3, 5, 20, 0); //apelare functie
apoi se afiseaza vectorul x.