In continuare se va prezenta conceptul de recursivitate si cateva clase de algoritmi recursivi, pentru intelegerea si rutinarea acestei tehnici puternice de programare, ce permite scrierea unor solutii clare, concise si rapide, care pot fi usor intelese si verificate. Ce este recursivitatea ?Un obiect sau un fenomen se defineste in mod recursiv daca in definitia sa exista o referire la el insusi.Recursivitatea
este folosita cu multa eficienta in matematica. Spre exemplu, definitii
matematice recursive sunt:
Utilitatea practica a recursivitatii rezulta din posibilitatea de a defini un set infinit de obiecte printr-o singura relatie sau printr-un set finit de relatii. Recursivitatea s-a impus in programare, odata cu aparitia unor limbaje de nivel inalt, ce permit scrierea de module ce se autoapeleaza (PASCAL, LISP, ADA, ALGOL, C sunt limbaje recursive, spre deosebire de FORTRAN,BASIC,COBOL, nerecursive). Recursivitatea
e strins legata de iteratie.Iteratia este executia repetata a unei
portiuni de program, pina la indeplinirea unei conditii (while, do-while
, for din C).
Un program recursiv poate fi exprimat: P=M(Si,P) , unde M este multimea ce contine instructiunile Si si pe P insusi. Structurile de program necesare si suficiente in exprimarea recursivitatii sunt functiile apelate prin nume. Recursivitatea poate fi directa - o functie P contine o referinta la ea insasi, sau indirecta - o functie P contine o referinta la o functie Q ce include o referinta la P. Apelul recursiv al unei functii trebuie sa fie conditionat de o decizie care sa impiedice apelul in cascada ( la infinit ); aceasta ar duce la o eroare de program - depasirea stivei. Exemplu generic: Se pune intrebarea: "Ce este mai indicat de utilizat: recursivitatea sau iteratia?" Algoritmii recursivi sunt potriviti pentru a descrie probleme care utilizeaza formule recursive sau pentru prelucrarea structurilor de date definite recursiv ( liste, arbori ), fiind mai eleganti si mai simplu de inteles si verificat. Iteratia este uneori preferata din cauza vitezei mai mari si a memoriei mai reduse. Spre exemplu varianta recursiva a functiei Fibonacci duce la 15 apeluri pentru n=5, deci varianta iterativa este mult mai performanta. Parametrii-valoare si parametrii-variabilaIn C, cu imbunatatirile aduse de C++, exista doua tipuri de parametri formali: valoare si referinta.Apelul recursiv al unei functii face ca pentru toti parametrii-valoare sa se creeze copii locale apelului curent (in stiva) , acestea fiind referite si asupra lor facindu-se modificarile in timpul executiei curente a functiei. Cind executia functiei se termina, copiile sunt extrase din stiva, astfel incit modificarile operate asupra parametrilor-valoare nu afecteaza parametrii efectivi de apel, corespunzatori. De asemenea pentru toate variabilele locale se rezerva spatiu la fiecare apel recursiv. In cazul parametrilor referinta, pe stiva se depune adresa parametrilor actuali, astfel incat operarea se face direct asupra spatiului de memorie afectat parametrilor efectivi, de apel. Pe parcursul unui apel, sunt accesibile doar variabilele locale si parametrii pentru apelul respectiv, nu si cele pentru apelurile anterioare, chiar daca acestea poarta acelasi nume. De
retinut:
Verificarea si simularea programelor recursiveSe face ca in cazul celor nerecursive, printr-o demonstratie formala, sau testind toate cazurile posibile.Se verifica intii daca toate cazurile particulare (ce se executa cind se indeplineste conditia de terminare a apelului recursiv) functioneaza corect. Se face apoi o verificare formala a functiei recursive, pentru restul cazurilor, presupunind ca toate componentele din codul functiei functioneaza corect. Verificarea e deci inductiva.Acesta e un avantaj al programelor recursive, ce permite demonstrarea corectitudinii lor simplu si clar. Exemplificare: Functia
recursiva de calcul a factorialului:
Demonstrarea
corectitudinii cuprinde doi pasi:
Tehnica eliminarii recursivitatiiOrice program recursiv poate fi transformat in unul iterativ, dar algoritmul sau poate deveni mai complicat si mai greu de inteles. De multe ori, solutia unei probleme poate fi elaborata mult mai usor, mai clar si mai simplu de verificat, printr-un algoritm recursiv.Dar
pentru implementare, poate fi necesara transformarea algoritmului recursiv
in unul nerecursiv, in situatiile:
Se va prezenta una din metodele de eliminare a recursivitatii ce foloseste o structura de date de tip stiva. In scrierea unei varianta nerecursive, trebuie parcursi toti pasii implicati in varianta recursiva, prin tehnici nerecursive. Recursivitatea implica folosirea a cel putin unei stive. La fiecare apel recursiv sunt depuse in stiva date, care sunt extrase la revenirea din acel apel. E simplu daca datele pentru un apel se organizeaza intr-o structura, un apel insemnind introducerea in stiva a unei structuri, revenirea, extragerea structurii. Se
prezinta eliminarea recursivitatii pentru un program simplu, care citeste
caracterele tastate pana la un blanc, tiparindu-le apoi in ordine inversa.
1.Algoritmi de traversare si inversare a unei structuri Traversarea
si inversarea unei structuri inseamna efectuarea unor operatii oarecare
asupra tuturor elementelor unei structuri in ordine directa, respectiv
in ordine inversa.
2.Algoritmi care implementeaza definitii recursive O definitie
recursiva e cea in care un obiect se defineste prin el insusi. Definitia
contine o conditie de terminare, indicind modul de parasire a definitiei
si o parte ce precizeaza definirea recursiva propriu-zisa.
Tehnica
divizarii ("divide and conquer"), fundamentala in elaborarea algoritmilor,
consta in descompunerea unei probleme complexe in mai multe subprobleme
a caror rezolvare e mai simpla si din solutiile carora se poate determina
solutia problemei initiale (exemple: gasirea minimului si maximului valorilor
elementelor unui tablou, cautarea binara, sortare Quicksort, turnurile
din Hanoi).
Metoda
se aplica problemelor in care solutia se poate reprezenta sub forma unui
vector x=(x1,x2,...xn) c S=S1 x S2 x...x Sn, unde multimile Si sunt finite,
S numindu-se spatiul solutiilor posibile. In particular, Si sunt identice
avind acelasi numar M de elemente. Pentru fiecare problema concreta sunt
date anumite relatii intre ucomponentele vectorului x, numite conditii
interne.
O varianta a acestei metode este cea in care, pentru un xi c vector solutie , xi+1 poate fi ales dintr-un numar M de posibilitati:
5.Algoritmi "inlantuie si limiteaza" (Branch and Bound) Sunt inruditi cu cei backtracking, mai numindu-se si backtracking cu constrangeri.
(1) Labirint 3D Pentru
problema de determinare a tuturor solutiilor de iesire dintr-un labirint
3D: sa se scrie un program pentru determinarea tuturor solutiilor si a
optimului de iesire dintr-un labirint tridimensional.
(2) Reconstructia punctelor Exista n puncte, p1, p2, ..., pn, toate localizate pe axa x, iar xi este coordonata lui pi. Se presupune ca x1=0 si punctele sunt numerotate de la stanga la dreapta. Aceste n puncte determina n*(n-1)/2 distante (de valori nu neaparat unice), d1, d2, ....,dm intre oricare 2 puncte distincte xi si xj. Problema reconstructie este urmatoarea: se dau m valori, (sortate in ordine crescatoare), care reprezinta setul de distante intre m=n*(n-1)/2 perechi de puncte. Se cere sa se reconstituie coordonatele celor n puncte. (3) Taieturi Sa
se scrie un program care sa gaseasca toate variantele, precum si cea optima
pentru taierea unui fir de lungime L in parti de lungimi L1,L2,...,Ln date,
in conditiile:
(4) Formatare de text Se considera urmatoarea problema de formatare a textului unui paragraf, care este o secventa de n cuvinte, c1, c2, ..., cn, de lungimi a1, a2, ..., an, care trebuie afisate pe linii de lungime L. Cuvintele trebuie separate prin spatii, a caror lungime ideala este b, dar spatiile pot fi extinse sau comprimate (dupa comprimare trebuie sa ramina totusi > 0), astfel incat o linie ce contine cuvintele ci ci+1 ... cj sa ocupe exact lungimea L. Pentru fiecare spatiu b' care este este mai mare sau mai mic decat lungimea ideala b, se defineste un "gradul de uratenie" ca fiind |b' - b|. Pentru intregul paragraf, este de dorit ca suma acestor grade de uratenie sa fie minim. Se cere sa se scrie programul care determina valorile lungimilor spatiilor separatoare astfel incat sa se obtina o formatare cat mai estetica a textului. (5) Recursivitate Sa
se scrie cite o functie recursiva pentru:
(6) Alcatuire chestionare Se considera un set de N intrebari, fiecare avand un punctaj Pi. Sa se genereze toate chestionarele continand un numar de intrebari intre A si B si avand un punctaj total intre C si D. (7) Triunghi magic Se considera un triunghi format din n linii, pe fiecare linie i sunt i numere intregi pozitive, ca in exemplul de mai jos: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5Sa se scrie un program care calculeaza cea mai mare suma a numerelor aflate pe un drum care leaga virful de sus al triunghiului cu baza. Drumul este astfel construit incat la fiecare pas se coboara pe diagonala, spre stinga sau spre dreapta. Exemplu: pentru triunghiul de mai sus, drumul cautat este: 7 - 3 - 8 - 7 - 5 (8) Labirint culori Se considera o suprafata caroiata de dimensiune n x n, in care fiecare patrat are una din culorile: galben, rosu, albastru sau verde. Configuratia suprafetei se citeste de la tastatura ( sau dintr-un fisier ). Sa se determine si sa se tipareasca daca exista drumuri ( minime ) intre colturile opuse - un drum trebuie sa cuprinda doar patrate de aceeasi culoare; deplasarea dintr-un patrat se poate face in oricare din cei opt vecini. (9) Cablaj Pe un circuit electric trebuie plasate n componente. Plasarea lor se face in n pozitii bine determinate, identificate cu numerele 1.. n. Se da o matrice c in care c[i,j] reprezinta numarul de conexiuni care trebuie facute intre componentele i si j, precum si o matrice d, cu d[p,q] reprezentind distanta intre punctele p si q. Cablarea consta in plasarea fiecarei componente intr-o anumita pozitie. Nu se pot aseza 2 componente in aceeasi pozitie. Costul cablarii este suma valorilor c[i,j]*d[p,q], unde componenta i a fost plasata in pozitia p iar componenta j in pozitia q. Se cere sa se determine o plasare a componentelor pe pozitii astfel incit costul total al cablarii sa fie minim. Fisierul
de intrare, cu numele citit de la tastatura, contine:
Iesirea va consta in afisarea permutarii care duce la costul minim, in forma: pozitia 1 - componenta x; pozitia 2 - componenta y ...... (10) Orarul cursurilor Sa se scrie un program care sa vina in sprijinul alcatuirii orarului cursurilor facultative. Exista un numar de N=20 cursuri si M=100 studenti. La inceputul anului, fiecare student isi exprima optiunea privind cursurile la care doreste sa participe. Un student poate alege un numar oarecare de cursuri (0 ..N), dar in medie numarul cursurilor alese este de 2-3. Problema responsabilului cu alcatuirea orarului este de a identifica care sunt cursurile care pot fi programate a se desfasura in paralel. Se pot desfasura in paralel 2 sau mai multe cursuri, cu conditia sa nu existe suprapuneri in orarul nici unui student. Programul va citi din fisierul s.dat numarul N de cursuri, numarul M de studenti, si apoi, pentru fiecare student, pe cite o linie, cursurile la care este insctis acesta. Programul determina grupele de cursuri care se pot desfasura in paralel(o varianta). Exemplu: N=5, M=6 studentul 1 alege cursurile 1,2 studentul 2 nu alege nimic studentul 3 alege cursurile 1,3 studentul 4 alege cursul 4 studentul 5 alege cursul 4 studentul 6 alege cursul 5Cursurile care se pot desfasura in paralel sunt: (1,4,5) (2,3) Observatie: se recomanda folosirea unui tip "multime de cursuri": Fiecare student are o multime de cursuri la care s-a inscris. Pe baza acestora, se poate determina, univoc, pentru fiecare curs, multimea cursurilor cu care este "in conflict", iar apoi evitind conflictele, se poate da o solutie de grupare a cursurilor. (11) Drum minim Intre n orase exista o retea de drumuri care permite ca dintr-un oras sa se ajunga in oricare din celelalte. Intre 2 orase exista cel mult un drum direct, de lungime cunoscuta, iar timpul necesar pentru parcurgerea unui drum este proportional cu lungimea sa. Se cere sa se realizeze programul pentru determinarea traseului pe care se poate merge intre doua orase date, intr-un timp minim. (12) Benzinariile Un sofer doreste sa conduca din orasul A in orasul B, intre care distanta este de n * 10 km (n numar intreg >=1). Incepand cu punctul de plecare A (inclusiv) exista benzinarii (numerotate incepand cu 0) la fiecare 10 km. Masina soferului consuma 1 litru de benzina la fiecare 10 km si are o capacitate a rezervorului de c litri (c numar intreg >=1). Soferul are la dispozitie o harta in care este trecut pretul la fiecare benzinarie. Sa se scrie un program care sa indice de unde si in ce cantitate trebuie sa cumpere soferul benzina pentru a parcurge drumul cu cost minim, si care este acest cost. Programul va afisa o singura solutie. Initial masina nu are benzina in rezervor, iar de la o benzinarie soferul poate cumpara orice cantitate de benzina, in limitele capacitatii rezervorului. Programul va citi datele din fisierul a.dat in care pe prima linie sunt trecute, separate de spatii, numerele intregi n si c, iar pe alta linie, tot separate de spatii cele n preturi pe litru la benzinarii (numere reale). Exemplu: Fisierul de intrare: 5 2 2.9 3.1 2.8 3.3 2.9 Iesirea programului: Cumpara 2 l de la benzinaria 0 Cumpara 2 l de la benzinaria 2 Cumpara 1 l de la benzinaria 4 Cost total: 14.3(13) Numere mari Sa se implementeze un TDA "numere mari". Un "numar mare" este un intreg care poate avea pina la 200 de cifre. Pentru reprezentarea interna a numerelor se vor folosi siruri de caractere. Asupra acestor numere se definesc operatiile aritmetice (adunare, scadere, inmultire). Sa se scrie un program care utilizeaza TDA numere, citeste 2 numere si realizeaza operatiile aritmetice asupra lor. (14) Gambling Un participant la un joc de noroc porneste avand la start o suma de bani A. La fiecare tura a jocului, jucatorul poate pierde sau castiga o suma in valoare fixa B. Sa se gaseasca toate posibilele variante de desfasurare a jocului(secvente pierdere - castig), astfel incat dupa N runde, jucatorul sa aiba aceeasi suma de bani, A, ca la start. (15) Mozaic Imaginea unui mozaic se afla intr-un fisier text, fiecare caracter desemnand culoarea unei placute din mozaic. Pentru simplitate, toate placutele sunt de forma patrata, de aceeasi dimensiune, si nu sunt decat doua culori, reprezentate in fisier prin caracterele 0 si 1. Toate liniile fisierului au aceeasi lungime si nu depasesc 250 caractere. Figurile din imaginea mozaicului sunt formate din grupe de 1 sau mai multe patretele adiacente, de culoare 1. Placutele adiacente au cel putin o latura comuna cu restul grupului. Scrieti un program care sa ceara, prin dialog de la consola, numele unui fisier(dimensiunea fisierului poate fi oricat de mare - peste 100 de linii), si sa afiseze numarul figurilor gasite in acel fisier. (16) Labirint 2D Pentru
problema clasica de determinare a tuturor solutiilor de iesire dintr-un
labirint 2D sa se scrie programul de aflare a optimului (drumul cel mai
scurt de iesire)
(17) Printre statui La orele serii, piata centrala in forma de hexagon regulat a orasului X abunda de vizitatori. Atractia o constituie statuile plasate la distante egale ( vezi Figura 1) si luminate fiecare de un reflector. La incheierea programului de vizitare, sarcina lui Gogu este de a stinge toate reflectoarele, astfel incat pierderea de energie sa fie minima. El porneste din cabina sa, notata 0, aflata linga coltul din stanga-sus al pietii, revenind in acelasi punct dupa stingerea tuturor reflectoarelor. Se poate deplasa numai pe aleile ce leaga cabina de prima statuie, respectiv statuile intre ele. Aleile sunt de lungimi egale, iar parcurgerea uneia se face intr-o unitate de timp. Poate sa treaca de mai multe ori pe linga aceeasi statuie, la prima trecere stingand reflectorul. Pregatiti traseul lui Gogu! Daca exista doua variante cu aceeasi energie minima consumata, se va considera solutia care se parcurge intr-un timp mai scurt. Ca
date de intrare, se citesc din fisierul IN.TXT intregii: pe prima linie
numarul N al statuilor de pe o latura a pietii, inclusiv colturile, iar
pe linia urmatoare consumurile de energie pe unitatea de timp ale reflectoarelor,
in ordinea parcurgerii lor pe linii, de la stanga la dreapta.
OUT.TXT
Copyright © 2001-2002. Carmen Holotescu All rights reserved. Published by Timsoft |