Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


Recursie

c



+ Font mai mare | - Font mai mic



Recursie

O functie este recursiva daca se autoapeleaza, direct sau indirect. In C toate functiile se pot defini recursiv.

Exemplu:

#include
void numara(int n);

void main()


void numara(int n)

else
printf('Gata !n');
}

Dupa executia acestui program, pe ecran se va tipari
10 ! 9 ! 8 ! 7 ! 6 ! 5 ! 4 ! 3 ! 2 ! 1 !
Gata !
Acest program s-ar fi putut realiza si iterativ (folosind o instructiune de tip while).

Exemplu: Suma primelor n numere naturale.

int suma(int n)

De obicei, functiile recursive urmeaza un 'pattern' standard:
- exista un caz de baza (sau mai multe);
- caz recursiv general (in care, in general, un intreg este trimis ca argument al apelului recursiv);
Recursia este un procedeu foarte puternic de rezolvare a problemelor. Secretul este identificarea cazului general.
Pentru exemplul precedent, cand se trimite n catre functia 'suma()', recursia activeaza n copii ale functiei inaintea intoarcerii pas cu pas catre primul apel recursiv (se mai spune ca in momentul apelului recursiv, variabilele locale 'ingheata', ele 'dezghetandu-se' la intoarcerea din recursie). Multe functii recursive se pot scrie intr-o forma iterativa (folosind structuri de tip 'while', se mai spune 'derecursivare'). Recursia se recomanda cand problema se poate rezolva foarte usor folosind recursie si cand nu se cere o eficienta sporita in timpul executiei programului. Uneori, se recomanda recursia finala (adica dupa apelul recursiv nu mai sunt alte instructiuni si nu exista variabile locale).

Exemplu: Citeste o linie si o afiseaza in ordine inversa, apoi lasa
----------- doua randuri goale.

#include
void tipareste(void);

void main()


void tipareste(void)

Iata o rulare in executie:
Introduceti o linie: iepurasu usa rupei

iepur asu usarupei
Observati in exemplul precedent ca la fiecare apel recursiv, se memoreaza in stiva caracterul 'c' legat la o valoare, care se va afisa
la intoarcerea din recursie. Deci practic, sunt 'n' copii ale lui 'c', unde 'n' reprezinta lungimea liniei.

Exemplu:

Putem complica putin exemplul precedent, in sensul ca afisam aceleasi cuvinte, dar in ordine inversa.
#include
#include

#define MAXWORD 100

void tipareste_cuvinte(void);
void citeste_cuvant(char *);

void main()


void tipareste_cuvinte(void)


void citeste_cuvant(char *s)

Daca, la executie, utilizatorul scrie:
Introduceti o linie: noi invatam C
atunci pe ecran, va apare:
C invatam noi
Variabila 'c' avand clasa de memorare 'static', rezulta ca valoarea ei se pastreaza de la un apel la altul. De altfel, initializarea lui 'c' se face o singura data (cand se intra prima data in aceasta functie). Daca 'c' ar fi fost de tip 'auto', atunci chiar daca aveam la sfarsitul sirului 'n', la urmatorul apel, acesta nu ar fi fost cunoscut, deci practic nu mai aveam conditie de oprire.

Exemplu:

In acest exemplu, vom desena 'pattern-uri' pe ecran folosind functii recursive.
#include
#define SYMBOL '*'
#define OFFSET 0
#define LENGTH 19

void display(char, int, int);
void draw(char, int);

void main()


void display(char c, int m, int n)

}

void draw(char c, int k)

}
Functia 'main()' contine apelul functiei 'display()', care apeleaza 'draw()', care la randul ei apeleaza 'display()'. Deci functia
'display()' este recursiva. Functia 'draw()' tipareste k copii ale caracterului 'c'. Pe ecran se va afisa:
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * *
* * * * * * *
* * *

Manipularea sirurilor folosind recursia

Un sir consta dintr-un numar de caractere consecutive, terminate prin caracterul '0'. De fapt, putem gandi un sir ca fiind sirul nul (care consta doar din caracterul '0') sau un caracter urmat de un sir. Aceasta definitie a sirului este o structura de date recursiva.

Exemplu: O definitie recursiva a lungimii unui sir.

int r_strlen(char *s)

Eleganta acestei formulari recursive este 'platita' de o pierdere in timpul executiei. Daca sirul are lungimea k, calcularea lungimii sale necesita k + 1 apeluri recursive (un compilator optimizat poate evita aceasta pierdere).

Metodologia 'divide-et-impera'

Recursia se foloseste in foarte multe cazuri pentru codificarea algoritmilor 'divide-et-impera'. Un astfel de algoritm imparte problema in subprobleme, rezolvand fiecare subproblema prin recursie, apoi recombina solutiile partiale pentru a obtine intreaga solutie.
Vom considera un exemplu cunoscut, si anume, determinarea minimului si maximului elementelor unui sir de intregi (publicat pentru prima data de catre Ira Pohl, 'A Sorting Problem and Its Complexity', Communications of the ACM, 15, nr. 6, 1972) considerat cel mai bun algoritm pentru aceasta problema. Criteriul pentru 'cel mai bun' a fost numarul de comparatii necesare. Prezentam mai jos o functie C care rezolva aceasta problema (considerand dimensiunea sirului putere a lui 2).
void minmax(int a[], int n, int *min_ptr, int *max_ptr)

else

else

}

Exercitii propuse spre implementare

1. Scrieti o functie C recursiva echivalenta cu 'strncmp()'.
2. Scrieti o functie C recursiva care calculeaza media aritmetica a unui sir de numere reale.
3. Scrieti o functie C recursiva care calculeaza n!, unde n este un numar natural.
4. (Mutarea calului) Data o tabla de sah (8 x 8), sa se scrie o functie C recursiva care descrie mutarile calului astfel incat orice
pozitie sa fie parcursa o singura data.





Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 808
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved