Sunteți pe pagina 1din 26

Recursivitate.

Divide-et-impera

Conf. dr. Smaranda Belciug


sbelciug@inf.ucv.ro
Recursivitate
—  Modalitatea de gasi solutia unei probleme
de dimensiune mare impartind-o in
probleme de dimensiuni mai mici, dar de
aceeasi forma ca problema initiala
—  Subproblemele dintr-o solutie recursiva
au aceeasi structura ca problema initiala
—  Recursivitatea permite rezolvarea unor
probleme complexe, scriind programe
simple si elegante

2
Un exemplu simplu de recursivitate

void CollectContributions(int n) {
if (n <= 100)
colecteaza banii de la un singur
donator
else{
gaseste 10 voluntari
fiecare voluntar strange n/10 dolari
//CollectContributions(n/10)
combina banii stransi de voluntari
}
}
3
Structura unei functii recursive.
Paradigma recursivitatii.
—  if (testeaza cazul simplu) {

—  Calculeaza o solutie simpla fara recursivitate

—  } else {

—  Imparte problema in subprobleme de aceeasi forma

—  Rezolva fiecare problema apeland recursiv functia aceasta

—  Combina solutiile subproblemelor astfel incat sa obtii solutia


problemei initiale

—  }

4
Aplicarea recursivitatii
—  Trebuie identificat cazul de baza pentru care raspunsul se

poate determina usor

—  Trebuie gasita o decompozitie recursiva, care permite

spargerea unei probleme complexe in mai mult probleme de


aceeasi forma, dar mai simple
—  Solutiile recursive mai sunt numite si strategii divide et

impera

5
Exemple - factorial
Iterativ Recursiv
—  int Fact(int n) { —  int Fact(int n) {
—  int product; —  if (n == 0) {
—  product = 1; —  return 1;

—  for (int i = 1; i <= n; i++) { —  } else {


—  product *= i; —  return n * Fact(n - 1);

—  } —  }
—  return product;
—  }
—  }

6
Explicatii
—  f = fact(4)

7
8
Leap of faith
—  Strategia psihologica: presupunerea ca orice apel recursiv

simplu va merge corect.

—  Intelegerea acestei strategii este esentiala pentru aplicatiile

practice

—  fact(4) = 4 * fact(3)

—  fact(3) este mai simplu decat fact(4), deci, presupunem ca

merge corect – leap of faith

9
Fibonacci
—  Problema reproducerii iepurilor (1202 – Leonardo
Fibonacci)
—  Fiecare pereche de iepuri produce o noua pereche in fiecare
luna
—  Iepurii devin mai fertili in a doua luna a vietii lor

—  Iepurii batrani nu mor niciodata

—  Daca o pereche de iepuri nou nascuti apare in Ianuarie, cate


perechi de iepuri vor fi pana la finele anului?

10
Calcularea numerelor Fibonacci

11
12
13
Eficienta implementarii recursive

14
Alternativa mai eficienta

Functie
wrapper

Termenul n este termenul n-1 din secventa care incepe cu un pas mai
tarziu

15
Detectarea palindroamelor
—  Se verifica daca prima si ultima litera este aceeasi

—  Se verifica daca substringul obtinut prin inlaturarea primei si ultimei


litere este tot un palindrom

16
Implementare mai eficienta

17
Cautarea binara
—  Cautarea intr-un array sau vector a unui element particular

—  De exemplu, daca lucram cu un array de string-uri ne-ar fi

foarte folositoare o functie de urmatoarea forma:


—  int FindStringInArray(string key, string array[], int n);

—  Returneaza indexul elementului egal cu key (daca sunt mai multe

elemente, orice index este ok)


—  Returneaza -1 daca nu a gasit niciun element egal cu key

18
—  Algoritmul de cautare liniara – nu avem informatii cu privire

la ordinea elementelor in array, astfel verificam element cu


element. Strategia consuma foarte mult timp, in cazul array-
urilor foarte mari.

—  Daca string-urile sunt asezate in ordine alfabetica, folosim

strategia cautarii binare. Impartim array-ul in doua,


comparam key cu elementul din mijloc, dupa care verificam
sirul din stanga sau dreapta, in functie de caz.

19
20
Recursivitate mutuala
—  Daca o functie f apeleaza o functie g, care la randul ei

apeleaza functia f, apelurile functiilor sunt considerate


recursive.

—  Deoarece functiile f si g se apeleaza una pe alta, acest tip de

recursivitate se numeste recursivitate mutuala.


—  Sa testam daca un numar este par sau impar.

21
—  Daca limitam cautarea la multimea numerelor naturale,

atunci numerele pare si impare pot fi caracterizate astfel:


—  Predecesorul unui numar par este un numar impar.

—  Un numar este par, daca nu este impar.

—  Numarul 0 este par prin definitie.

22
23
Sa gandim recursiv!
—  Reductionism - un obiect poate fi inteles

prin intelegerea partilor sale componente


—  Holism – un obiect intreg este mai mare decat suma partilor sale
componente (recursivitate)
—  Cand scrii un program recursiv trebuie sa ignori detaliile

apelurilor recursive.
—  Cand programul recursiv nu merge, cauta in eroarea in
implementare recursiva, nu in mecanismul recursiv!

24
Checklist pentru gasirea erorii
—  Incepe programul recursiv cu cazul simplu? (programul trebuie sa inceapa cu
if)
—  Ai rezolvat cazul simplu corect? (daca ai scris fact(0) = 0 si nu fact(0) = 1,
tot programul va merge prost)
—  Descompunerea recursiva simplifica problema? (ai grija sa nu scrii o bucla
infinita)
—  Apelurile recursive sunt subprobleme de aceeasi forma cu cea initiala?

—  Cand unim solutiile subproblemelor formam raspunsul intreg al problemei


initiale?

25
Pe saptamana viitoare!

26

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