Documente Academic
Documente Profesional
Documente Cultură
1. Conceptul de recursivitate 2. Recursivitatea direct 3. nregistrarea de activare 4. Relaia dintre recursivitate i iteraie 5. Exemple de programe recursive
Conceptul de recursivitate
Definiii
Un obiect sau un fenomen este definit n mod recursiv dac n definiia sa se face referire la el nsui. Conceptul de recursivitate ofer posibilitatea definirii unei infiniti de obiecte printr-un numr finit de relaii. Recursivitatea a fost introdus n programare n 1960, n limbajul Algol. O funcie este recursiv atunci cnd executarea ei implic cel puin nc un apel ctre ea nsi. Recursivitate direct apelul recursiv se face chiar din funcia invocat. Recursivitate indirect (mutual) apelul recursiv se realizeaz prin intermediul mai multor funcii care se apeleaz circular.
Conceptul de recursivitate
Exemple de funcii recursive
1 fact(n) = n * fact(n-1) fib: N N (Fibonacci) 1 fib(n) = fib(n-2)+fib(n-1) ac: N x N N ac(m, n) = (Ackermann) n+1 ac(m-1, 1) ac(m-1, ac(m, n-1)) dac m = 0, dac n = 0, dac m 0 i n 0. dac n > 0 dac n = 0 sau n = 1 dac n > 1 dac n = 0
Recursivitatea direct
Principii
n limbajul C funciile se pot apela pe ele nsele, adic sunt direct recursive. Pentru o funcionare corect (din punct de vedere logic), apelul recursiv trebuie s fie condiionat de o decizie care, la un moment dat n cursul execuiei, s mpiedice continuarea apelurilor recursive i s permit astfel revenirea din irul de apeluri. Lipsa acestei condiii sau programarea ei greit va conduce la executarea unui ir de apeluri a crui terminare nu mai este controlat prin program i care, la epuizarea resurselor sistemului, va provoca o eroare de execuie : Depirea stivei de date.
Recursivitatea direct
Exemplu schematic
void p (list de parametri){ ... a, b; ... if (cond) p(...) ... sau: p(...); while (cond) { ...p(...) } sau: do ... p(...)... while (cond) } Condiia care trebuie testat este specific problemei de rezolvat. Programatorul trebuie s o identifice n fiecare situaie concret i, pe baza ei, s redacteze corect apelul recursiv. Revenirea din apeluri se face n ordine invers.
nregistrarea de activare
nregistrare de activare. Aceasta conine, printre altele, locaiile rezervate pentru valorile parametrilor (argumentelor), pentru variabilele automatice i pentru rezultatul returnat de funcie. La fiecare apel se creaz o nou nregistrare de activare, incluznd un nou set de parametri i de variabile automatice. Zona de memorie n care se face aceast rezervare se numete stiva de date. n cazul apelurilor recursive vor exista n memorie, simultan, mai multe nregistrri de activare pentru aceeai funcie recursiv, fiecare coninnd cte un set de parametri i de variabile automatice (locale). Dei locaiile poart acelai nume n fiecare set, ele reprezint entiti diferite i au valori distincte. Pe parcursul unui apel nu sunt accesibile dect locaiile din nregistrarea de activare creat la apelul curent.
Unei funcii i se "acord", la apel, o zon de memorie numit
apel 3 p
apel 2 p
apel 1 p
(din fct. principal)
ABC ABC
CBA
#include <stdio.h> double putere(double a, unsigned n) { return n = = 0 ? 1 : a*putere(a, n-1); } int main(void) { printf(1.5 la puterea 5 = %f \n, putere(1.5, 5)); return 0; }
Exemplu
Rdcina patrat
x: a0=1, an+1 = (an+x / an) / 2 Cnd s-a atins precizia dorit ( |an+1-an|< ), x este an. #include <stdio.h> #include <math.h> double rad(double x, double an) { return x < 0 ? 0 : fabs((x/ an-an)/2)<0.0001 ? an : rad(x, (an+x/ an)/2); } int main(void) { printf(radical din 7 este %f \n, rad(7.0, 1.0)); return 0; }
Algoritmul lui Euclid de aflare a celui mai mare divizor comun a dou nr. ntregi
Formularea recursiv, n cuvinte, a algoritmului: Dac unul dintre numere este zero, c.m.m.d.c. al lor este cellalt numr. Dac nici unul dintre numere nu este zero, atunci c.m.m.d.c. nu se modific dac se nlocuiete unul dintre numere cu restul mpririi sale cu cellalt. Algoritmul poate fi implementat sub forma urmtoarei funcii recursive: unsigned cmmdc (unsigned m, unsigned n){ if (n==0) return m; else return cmmdc(n, m % n); }
m 18 27 18 9
n 27 18 9 0
cmmdc cmmdc (27, 18 % 27) cmmdc (18, 27 % 18) cmmdc (9, 18 % 9) cmmdc=9
#include <stdio.h> unsigned cmmdc(unsigned m, unsigned n) { return m==n ? m:m>n ? cmmdc(m-n,n) : cmmdc(m, n-m); } int main(void) { printf(cmmdc(18, 27) este %u\n, cmmdc(18, 27)); return 0; }
Generarea permutrilor
Enunul problemei
Se consider o secven de n numere naturale distincte. Se cere s se genereze toate secvenele reprezentnd permutrile celor n numere. Se pornete de la primele n numere naturale ordonate cresctor ntr-un tablou ai, i=1,n. Prin apelul recursiv al funciei Permut se reduc n cascad permutri (k) la permutri (k-1), efectundu-se operaiile descrise n algoritmul urmtor (n pseudocod):
Generarea permutrilor
Algoritmul de rezolvare al problemei
** procedura Permut (K ; ) este intreg K, I dac K = 1 atunci * Tiprete soluia altfel Permut(K-1); pentru I := 1 la K-1 execut * schimb ntre ele A[I] cu A[K] * Permut (K-1); * schimb ntre ele A[I] cu A[K] sfrit
Generarea permutrilor
Programul
#include <stdio.h> #define N 4 int a[N+1]; void Tipareste(){ int i; for (i=1; i<=N; i++) printf("%d ", a[i]); printf("\n"); }
Generarea permutrilor
Programul
void Permutare(int k) { int i,x; if (k == 1) Tipareste(); else { Permutare(k-1); for (i=1; i<=k-1; i++) { x = a[i]; a[i] = a[k]; a[k] = x; Permutare(k-1); x = a[i]; a[i] = a[k]; a[k] = x; } }}
Generarea permutrilor
Programul
int main(int argc, char *argv[ ]) { int i; for (i=1; i<=N; i++) a[i] = i; Permutare(N); return 0; }
Generarea permutrilor
Concluzii
Pentru a parcurge n mod corect i complet toate permutrile prin nlocuirea fiecrui element ak cu toate elementele ai , la revenirea din cel de-al doilea apel recursiv trebuie refcut starea iniial a tabloului a. Aceast situaie sau situaii similare apar frecvent n programele recursive, atunci cnd procedura recursiv efectueaz modificri asupra unor variabile globale (externe funciilor). Se observ c programul conine chiar operaiile descrise anterior n pseudocod, la care se adaug condiia de oprire a apelrii recursive (k = 1, caz n care s-a obinut o secven final i se tiprete). n concluzie, descrierea trecerii de la un pas la pasul urmtor, calitativ identic, mpreun cu condiia de oprire, sunt suficiente pentru implementarea n program a unui algoritm recursiv( similitudine cu metoda induciei matematice ).