Sunteți pe pagina 1din 71

Universitatea tefan cel Mare Suceava Facultatea de Inginerie Electric i tiina Calculatoarelor

NDRUMAR DE LABORATOR
Programarea calculatoarelor i limbaje de programare 2

prof. dr. ing. tefan-Gheorghe PENTIUC asistent. drd. ing. Ovidiu-Andrei SCHIPOR asistent. drd. ing. Felicia-Florentina GZ-BELCIUG .l. dr. ing. Marius CERLINC

Suceava, 2010

Cuprins
1. FIIERE TEXT 2. FIIERE BINARE 3. POINTERI LA FUNCII 4. STRUCTURI 5. CMPURI DE BII 6. LISTE LINIARE 7. LISTE SIMPLU NLNUITE 8. STIVA 9. COADA 10. MULIMI 11. ARBORI 12. METODA GREEDY 13. BACKTRACKING RECURSIV 14. BACKTRACKING ITERATIV BIBLIOGRAFIE 5 9 13 15 19 31 37 43 47 51 57 61 65 69 71

1. Fiiere text
1.Obiective
Utilizarea principalelor funcii specifice fiierelor text; Implementarea unei aplicaii de salvare/citire a datelor matriceale n/din fiierele text; Generarea fiierelor html i a fiierelor istoric n cadrul aplicaiei.

2.Aspecte teoretice
Memoria intern este limitat att din punctul de vedere al persistenei datelor ct i din punctul de vedere al capacitii. Posibilitatea de a stoca i accesa cantiti mari de date este oferit de dispozitivele de stocare externe (hard-disk, DVD, flash). Din punct de vedere logic, aceste dispozitive organizeaz datele sub forma fiierelor. Transferul datelor din memoria intern ntr-un fiier poart denumirea de salvarea datelor. Transferul invers presupune citirea din fiier.

Funcii noi deschidere nchidere caracter scriere citire


fputc fgetc

fopen fclose

ir de caractere
fgets fputs

date formatate
fscanf fprintf

3.Exemple
Exemplul 1 salvarea/citirea unui vector n/din fiier text Un program minimal ce opereaz cu iruri de numere ntregi trebuie s implementeze funciile de citire de la tastatur i afiare pe ecran. Utiliznd fiiere se pot implementa nc dou funcii, una care s realizeze salvarea unui vector ntr-un fiier iar alta citirea unui vector din fiier. Trebuie respectat un anumit format al fiierului. Convenim ca s scriem pe prima linie a fiierului numrul de elemente ale irului iar pe linia urmtoare elementele, separate prin spaiu. De exemplu, dup salvarea vectorului {2, -3, 0, 8}, fiierul trebuie s conin: 4 2 -3 0 8

Funcia de salvare a vectorului are ca argumente numrul de elemente - n, vectorul - v i numele fiierului n care se dorete salvarea vectorului - numeFisier. Aceast funcie returneaz valoarea 1 (unu) dac nu au aprut erori la deschiderea fiierului i 0 (zero) n caz contrar.
int salvareVector(int n, int v[NMAX], char* numeFisier){ FILE *pf; //pf este o variabila de tip pointer catre un fisier int i; //se deschide fisierul in mod scriere (write) pf = fopen (numeFisier, "wt"); //daca fisierul nu poate fi deschis, se returneaza fals logic if (pf == NULL) return 0; //daca pf este un pointer valid atunci se pot scrie datele fprintf (pf, "%d\n",n); //se scrie numarul de elemente for (i=0;i<n;i++) //se scriu succesiv elementele fprintf (pf, "%d ",v[i]); fclose (pf); //inchidere fisier return 1; //salvarea datelor s-a incheiat cu succes }

Funcia de citire din fiier a vectorului are ca argumente un pointer la numrul de elemente - n, vectorul - v i numele fiierului din care se dorete citirea vectorului - numeFisier. Returneaz valoarea 1 (unu) dac nu au aprut erori la deschiderea fiierului i 0 (zero) n caz contrar.
int citireVectorFisier(int* pn, int v[NMAX], char* numeFisier){ FILE *pf; int i; //se deschide fisierul in mod citire (read) pf = fopen (numeFisier, "rt"); if (pf == NULL) return 0; fscanf (pf, "%d",pn); //se citeste numarul de elemente for (i=0;i<*pn;i++) //se citesc succesiv elementele fscanf (pf, "%d",&v[i]); fclose (pf); //inchidere fisier return 1; //citirea datelor din fisier s-a incheiat cu succes }

Exemplul 2 copierea coninutului unui fiier text n altul n cadrul acestui exemplu se va prezenta o funcie care copie coninutul unui fiier n altul. Funcia primete ca argument numele fiierelor surs i destinaie (n aceast ordine). Returneaz valoarea 0 (zero) dac a aprut eroare la deschiderea fiierelor i 1 (unu) n caz contrar.
int copiereFisier1 (char* numeSursa, char* numeDest){ FILE *pfSursa, *pfDest; // pointeri la cele doua fisiere char c; // variabila de "manevra" if ((pfSursa=fopen(numeSursa, "rt"))==NULL) //deschidere sursa return 0; if ((pfDest=fopen(numeDest, "wt"))==NULL) //deschidere destinatie return 0; /*se citesc caractere din fisierul sursa si se scriu in fisierul destinatie pana cand functia fgetc() returneaza EOF*/ while ((c=fgetc(pfSursa))!=EOF) fputc(c,pfDest); fclose (pfSursa); fclose (pfDest); return 1; 6 }

Varianta prezentat realizeaz copierea caracter cu caracter. n cazul fiierelor text poate fi mai performant o copiere linie cu linie. n continuare este prezentat secvena de copiere pentru acest mod de implementare. Pentru dimensiunea tabloului n care se memoreaz o linie s-a utilizat constanta MAX_LINIE. Cu alte cuvinte, presupunem c numrul maxim de caractere de pe o linie din fiierul surs este MAX_LINIE 1 (la sfritul irului trebuie adugat i caracterul \0).
int copiereFisier2 (char* numeSursa, char* numeDest){ FILE *pfSursa, *pfDest; char buf[MAX_LINIE]; // variabila de manevra if ((pfSursa=fopen(numeSursa, "rt"))==NULL) return 0; if ((pfDest=fopen(numeDest, "wt"))==NULL) return 0; //cand ajunge la sfarsitul fisierului fgets() returneaza NULL while (fgets(buf,MAX_LINIE-1,pfSursa)!=NULL) fputs(buf,pfDest); fcloseall(); // se inchid toate fisierele deschise return 1; }

Exemplul 3 testarea existenei unui fiier Funcia care testeaz existena unui fiier are ca argument numele acestuia. Se bazeaz pe faptul c fopen() returneaz NULL dac se ncearc deschiderea n citire a unui fiier inexistent.
int existaFisier (char* numeFisier){ FILE *pf; //daca fisierul poate fi deschis pentru scriere atunci el exista return (pf=fopen (numeFisier, "r"))==NULL ? 0 : (fclose(pf),1); }

4. Tem de realizat n timpul laboratorului


Exerciiul 1 matrice i fiiere text S se realizeze o aplicaie care s afieze un meniu cu urmtoarele opiuni:
C A S R citire matrice de la tastatura afisare matrice pe ecran salvare matrice in fisier citire matrice din fisier

Referitor la formatul datelor n fiier, pe prima linie se vor scrie numrul de linii i numrul de coloane separate prin spaiu. Apoi se vor scrie pe linii succesive liniile matricei (elementele separate prin spaiu). Coninutul fiierului dup salvarea matricei {{4,9,2},{0,6,1}} va fi:
2 3 4 9 2 0 6 1

Exerciiul 2 generare fiier backup S se adauge o opiune care s permit copierea unui fiier n altul (B creare fisier backup pentru un fisier creat la optiunea S).
7

Exerciiul 3 generare fiiere HTML Din ce n ce mai multe aplicaii i prezint datele n format html. Fiierele html sunt n acest caz generate pe baza unor date necunoscute iniial. Ele se mai numesc fiiere generate on the fly (din zbor). Aplicaia anterioar poate fi extins n acest sens prin adugarea unei opiuni (H generare html). Accesarea ei trebuie s determine generarea unui fiier html care, deschis cu ajutorul unui browser, s afieze matricea sub forma unui tabel ca n exemplul urmtor: Matrice: 2 linii, 3 coloane 492 061
<html> <head><title>Matrice</title></head> <body>Matrice: 2 linii, 3 coloane.<br> <table border='1'> <tr><td>4</td><td>9</td><td>2</td></tr> <tr><td>0</td><td>6</td><td>1</td></tr> </table></body></html>

2. Fiiere binare
1. Obiective
Identificarea diferenelor ntre formatele text i binar ale datelor; nsuirea lucrului cu principalele funcii specifice fiierelor binare; Extinderea unei aplicaii de salvare/citire a datelor n/din fiiere binare.

2. Aspecte teoretice
n cadrul laboratorului anterior, datele au fost salvate n format text, rezultnd fiiere uor de citit/modificat cu ajutorul programelor editoare de text (Notepad). n memoria intern, datele au o alt reprezentare formatul binar. Aa de exemplu, n limbajul C, o variabil de tip ntreg va ocupa n memorie ntotdeauna 2 octei, indiferent de valoarea ei. Acest lucru nu este valabil dup conversia variabilei n formatul text cnd, un numr ntreg poate ocupa de la 1 octet (de exemplu numrul 7) i pn la 6 octei (de exemplu numrul 12539). Pentru a evita conversia consumatoare de timp ntre cele dou formate este necesar scrierea datelor din memorie n fiiere direct n formatul binar. Funcii noi scriere
fwrite

citire
fread

poziionare
fseek

aflare poziie
ftell

Tabelul urmtor ilustreaz legtura dintre formatul text (linia valoare) i formatul binar (liniile baza 2 i baza 10) pentru variabile de diferite tipuri, adugate succesiv ntr-un fiier binar. Linia ASCII se refer la conversia valorii numerice din fiecare octet la tipul caracter pe baza tabelei ASCII (aceste caractere se afieaz dac fiierul binar este deschis cu un editor de text obinuit).
variabila valoare nr octet baza 2 baza 10 ASCII variabila valoare nr octet baza 2 baza 10 ASCII variabila valoare nr octet baza 2 baza 10 ASCII char c1 'A' 1
01000001

char c2 '0' 2
00110000

int i1 49 3
00110001

int i2 320 4 5
01000000

int i3 -49 6 7
11001111

8
11111111

00000000

00000001

65 A

48 0

49 1

64 @

207

255

9
01100001

long l 6513249 10 11
01100010 01100011

12
00000000

13
01100001

char s[4] "ana" 14 15


01101110 01100001

16
00000000

97 a

98 b

99 c

97 a

110 n

97 a

17
01000001

18
00000000

19
01000010

int v[4] {65,66,51,52} 20 21


00000000 00110011

22
00000000

23
00110100

24
00000000

65 A

66 B

51 3

52 4

3. Exemple
Exemplul 1 program de test fiiere binare Programul urmtor ofer posibilitatea citirii succesive de la tastatura a unor variabile i adaugarii acestora ntr-un fiier binar. La fiecare iteraie utilizatorul are posibilitatea s precizeze tipul i valoarea variabilei. Dup fiecare adaugare n fiier, programul afieaz coninutul acestuia la nivel de octet, indicnd numrul octetului si valoarea sa in formatele decimal i ASCII.
CONV.C #include <stdio.h> #include <conio.h> #include <string.h> // numele fisierului in care se vor scrie datele #define NUME_FISIER "fisier.dat" // tipurile de date se considera: // 1-char, 2-int // 0-rezervat pentru terminarea programului // vector de intregi cu numarul de octeti ale tipurilor de date int lung[] ={0,sizeof(char),sizeof(int)}; // vector de siruri de caractere cu specificatori de format char *format[] = {"","%c","%d"}; int void int int char* citesteTipVariabila(); citesteVariabila(int tip, char* var); adaugaVariabilaInFisier(char* numeFisier, int tip, char* zona); afiseazaFisierBinar(char* numeFisier); convertesteInBaza2(char c);

//------------------------------------------// functia principala a programului //------------------------------------------void main (){ // pentru memorarea unei variabile se aloca 2 octeti char var[sizeof(int)]; // tipul variabilei (1-char, 2-int) int tip; // ciclul se repeta cat timp tip este diferit de 0 while(tip = citesteTipVariabila()){ // se citeste o variabila de la tastatura citesteVariabila (tip,var); // se adauga variabila in fisierul binar adaugaVariabilaInFisier (NUME_FISIER,tip,var); // se afiseaza fisierul binar afiseazaFisierBinar (NUME_FISIER); } } //------------------------------------------// citeste si returneaza tipul unei variabile //------------------------------------------int citesteTipVariabila(){ int tip; // citeste un tip pana cand se incadreaza in intervalul [0,2] do{

10

clrscr(); printf ("\nDa tipul (1-char, 2-int, 0-termina):"); scanf("%d",&tip); }while (tip<0 || tip>2); return tip; } //----------------------------------------------------------------// citeste o variabila de un anumit tip in zona primita ca argument //----------------------------------------------------------------void citesteVariabila (int tip, char* var){ printf ("\nDa valoarea variabilei:"); flushall(); // se utilizeaza un format dependent de valoarea lui tip // var este adresa unei zone in care se memoreaza variabila scanf (format[tip],var); } //---------------------------------------------------------------// adauga in fisier valoarea de tipul tip din zona de memorie var //---------------------------------------------------------------int adaugaVariabilaInFisier (char* numeFisier, int tip, char* var){ // fisierul este deschis in modul append binar FILE* pf = fopen(numeFisier,"ab"); if (!pf) return 0; // se scriu 1 x lung[tip] octeti // de la adresa var in fisierul pf fwrite (var,lung[tip],1,pf); fclose (pf); return 1; } //-----------------------------------------------------------------// afiseaza continutul fisierului in binar, decimal si ASCII //-----------------------------------------------------------------int afiseazaFisierBinar (char* numeFisier){ char octet; int i=0; FILE *pf = fopen(numeFisier,"rb"); if (!pf) return 0; // se afiseaza header-ul tabelului printf ("nr. octet | decimal | ASCII "); printf ("\n---------------------------"); // se citeste cate un octet din fisier // pana cand se ajunge la sfarsitul fisierului while (fread (&octet,1,1,pf)==1){ // se afiseaza aliniat pe coloane informatiile printf ("\n%9d | %7d | %5c " ,i++,octet,octet); } fclose (pf); printf ("\nApasa orice tasta pentru a continua..."); getch(); return 1; }

11

Exemplul 2 salvarea/citirea unui vector n/din fiier binar Scrierea n fiier se realizeaz dup urmtorul format: nti este scris numrul de elemente n (de tip int, va ocupa sizeof(int) bytes); n continuare este scris fiecare element din vectorul v.
int salveazaVectorBinar(int n, int v[NMAX], char* numeFisier){ FILE* fp = fopen(numeFisier, "wb"); if (fp == NULL) return 0; // eroare deschidere // scrie in fisierul fp numarul de elemente ale vectorului // adica 1 x sizeof(int) octeti de la adresa &n if (fwrite(&n, sizeof(int), 1, fp) == 1) // scrie in fisierul fp elementele vectorului // adica n x sizeof(int) octeti de la adresa v if (fwrite(v, sizeof(int), n, fp) != n){ // daca datele au fost scrise cu succes fclose(fp); return 1; } fclose(fp); // au aparut probleme la scrierea datelor return 1; }

Funcia de citire a vectorului din fiier va prelua mai nti numrul de elemente i apoi va citi elementele vectorului.
int citesteVectorFisierBinar(int* pn, int v[NMAX], char* numeFisier){ FILE* fp = fopen(numeFisier, "rb"); if (fp == NULL) return 0; // eroare deschidere // se citeste numarul de elemente if (fread(pn, sizeof(int), 1, fp) == 1) // se citesc elementele if (fread(v, sizeof(int), *pn, fp) == *pn){ // daca datele au fost citite cu succes fclose(fp); return 1; } fclose(fp); // au aparut probleme la citirea datelor return 0; }

4. Tem de realizat n timpul laboratorului


Exerciiul 1 S se modifice aplicaia prezentat n exemplul 1 pentru a permite adugarea n fiier i a variabilelor de tipul long int. De asemenea s se afieze pe ecran i valorile n bazele 8 respectiv 16 ale octeilor din fiier. Indicati cea mai simpl modalitate de a goli fiierul n care se salvez datele de fiecare dat cnd scriei n el cte o variabil. Exerciiul 2 S se extind aplicaia realizat n laboratorul cu fiiere text prin adugarea opiunilor:
M salvare matrice in fisier binar N citire matrice din fisier binar

12

3. Pointeri la funcii
1. Obiective
familiarizarea cu tablouri de pointeri la funcii utilizarea modului grafic

2. Aspecte teoretice
Declararea unui parametru de tip pointer la funcie se face astfel :
int (*p_functie)( int , float ) ;

Acest pointer nu poate conine dect adresa unei funcii ce are un prototip identic cu cel al pointerului:
int { functie( int a, float b )

//corpul functiei } void main( void ) { p_functie = functie; }

cu observaia c numele funciei reprezint adresa funciei. Apelul unei funcii prin intermediul unui pointer la funcie se face conform secvenei de mai jos:
p_functie( 23, 45.6 ) ;

3. Exemplu
Se consider o aplicaie care afieaz 10 valori ale funciilor cosinus, sinus i x+x/2 pe intervalele [-1,1] i pentru funcia radical pe intervalul [0.1,3.2].

#include <math.h> #include <stdio.h> #include <conio.h> typedef double (*pFunctie)( double v ); void tabel( char*, pFunctie, double, double, int); double functie( double ); void main( void )

13

void main( void ) { clrscr(); tabel( "cos", cos, -1, 1, 10 ); tabel( "sin", sin, -1, 1, 10 ); tabel( "radical", sqrt, 0.1, 3.2, 10 ); tabel( "functie", functie, -1, 1, 10 ); } void tabel( char *nume, pFunctie functie, double a, double b, int N) { printf("\n\n%s - [%.1lf, %.1lf] in %d pasi", nume, a, b, N ); for( double i=a, suma=0; i <= b; i += (b-a)/N ) printf("\n%5.1lf\t|%5.1lf", i, functie( i )); } double functie( double x ) { return x + x/2; }

4. Tem de realizat n timpul laboratorului


Q - Citirea intervalului de reprezentare a funciei N - Citirea numrului de pai S - Afieaz grafic funcia sinus C - Afieaz grafic funcia cosinus R - Afieaz grafic funcia radical P - Afieaz grafic o funcie polinomiala a crui grad si coeficieni sunt citii de la tastatura X - Ieire

Observaie. Odat cu afiarea graficului, ntr-un fiier text al crui nume este dat in linia de comanda s se salveze valorile funciei alese in diferite puncte sub forma:
x sin(x) -1 -0.0174 -0.9 -0.0157 -0.8 -0.0139 . . . . . x cos(x) . . . . .

Ordinea funciilor trebuie sa fie cea aleas corespunztor meniului.

14

4. Structuri
1.Obiective
Insuirea lucrului cu tipurile de date structurate; Consolidarea cunotinelor privind fiierele binare; Implementarea unei aplicaii minimale de gestiune a stocurilor;

2.Aspecte teoretice

n aplicaiile de pn acum s-au utilizat doar tipuri de date simple (char, int, float, etc). Cel mult aceste tipuri au fost extinse prin utilizarea operatorilor [] obinndu-se astfel tablouri de date de acelai tip (omogene). De cele mai multe ori, realitile modelate prin datele programului sunt complexe nereducndu-se la un ir omogen de date. Pentru asemenea date trebuie create tipuri noi (compuse) specifice aplicaiei. n continuare este prezentat o definiie de tip de dat care s modeleze conceptul de calculator:
struct calculator{ char numeProcesor[20]; float frecventa; //exprimata in GHz int capacitateRAM; //exprimata in MB int capacitateHDD; //exprimata in GB char numeProducator[64]; float pret; };

Pentru a defini n program o variabil n care s se poat memora datele de identificare ale unui calculator trebuie s se utilizeze noul tip de dat creat i anume struct calculator.
struct calculator unCalculator;

n acest moment se aloc memorie suficient pentru a memora toate cmpurile specificate n definiia de structur. Pentru a putea utiliza variabila unCalculator este necesar o modalitate de acces la membrii din care este format. Accesul la membrii se realizeaz cu ajutorul operatorului . (punct). n acest context, unCalculator.numeProcesor se comport ca un ir de caractere obinuit i similar, unCalculator.frecventa se comport ca un numr ntreg. Avantajele tipurilor de date structurate sunt: crearea i manipularea cu uurin a tipurilor complexe de date specifice aplicaiei; copierea simplificat, printr-o singur atribuire a tuturor cmpurilor; transmiterea ca parametrii la funcii; scrierea/citirea n bloc n/din fiiere binare.

15

3.Exemple
Considerm structura:
struct student{ long nrMatricol; char nume[100]; float media; }; typedef struct student STUDENT;

// typedef creaza sinonimul STUDENT // pentru denumirea struct student

Exemplul 1 dou variante de funcii pentru citirea unui student Pentru citirea unui student se poate utiliza fie o funcie care returneaz o variabil de tip STUDENT fie o funcie care primete adresa unei variabile de tip STUDENT.
STUDENT citireStudent (){ STUDENT s; printf (\nIntroduceti pe rand nr. matricol, numele si media); scanf (%ld,&s.nrMatricol); gets (s.nume); scanf (%f,&s.media); return s; }

void citireStudent (STUDENT *p){ printf (\nIntroduceti pe rand nr. matricol, numele si media); scanf (%ld,&p->nrMatricol); gets (p->nume); scanf (%f,&p->media); }

Dac n prima variant se transfer prin stiv un numr de sizeof(STUDENT) octei (n acest caz 108), n a doua variant se transfer doar octeii necesari memorrii unei adrese. Dei prima variant este mai intuitiv a doua variant este mai eficient. Exemplul 2 funcie pentru adugarea ntr-un fiier binar Se dorete realizarea unei funcii care s adauge o nregistrare (un student) ntr-un fiier. Numele fiierului se va primi ca argument. Funcia va returna valoarea 0 (zero) dac au aprut erori I/O i 1 (unu) n caz contrar. Transmiterea studentului n funcie poate fi realizat fie prin valoare (argumentul este de tip STUDENT) fie prin referin (argumentul este de tip STUDENT*). Se prefer a doua variant deoarece numrul de octei transferai prin stiv este considerabil mai mic.
int adaugareStudent (char *numeFisier, STUDENT *p){ if ((f=fopen(numeFisier, a))==NULL) return 0; fwrite (p,sizeof(STUDENT),1,f) return 1;

16

4. Tem de realizat n timpul laboratorului


Exerciiul 1 Se va realiza o aplicaie tip meniu care s permit gestionarea unei baze de date cu produsele dintr-o magazie. Un produs va fi reprezentat prin 3 informaii: cod, nume, unitate (ex: 315,mere,kg). Opiunile necesare pentru a fi implementate sunt:
A V U I X adaugare un produs in fisierul de lucru vizualizarea produselor din fisierul de lucru cautarea unui produs dupa nume informatii despre autor iesire din program

Observaii: fiierul de lucru (al crui nume este preluat din linia de comand) va fi accesat n mod binar; dac utilizatorul ncearc s adauge un produs cu un cod care se mai gsete deja n fiierul de lucru, va fi interogat dac dorete suprascrierea sau nu a nregistrrii respective; n continuare este prezentat listing-ul fiierului header al aplicaiei:
#ifndef _PRODUSE_H_ #define _PRODUSE_H_ typedef char LOGIC; #define ADEVARAT 1 #define FALS 0 typedef struct produs{. . .}PRODUS; // utilizare rapida a lui typedef void citireProdus (PRODUS *p); /* ncarc produsul indicat de pointerul p cu informatiile specifice (cod, nume, unitate) */ LOGIC adaugareProdus (char *numeFisier, PRODUS *p);/*adauga in fisierul cu numele numeFisier produsul indicat de pointerul p; daca a aparut o eroare I/O returneaza FALS altfel returneaza ADEVARAT*/ LOGIC vizualizareProduse (char *numeFisier);/*afiseaza pe rand toate inregistrarile din fisierul cu numele numeFisier; daca a aparut o eroare I/O returneaza FALS altfel returneaza ADEVARAT*/ LOGIC gasitProdus (char *numeFisier, int codProdus,LOGIC *errFisier); /*cauta produsul cu codul codProdus in fisierul cu numele numeFisier; daca produsul este gasit returneaza ADEVARAT altfel returneaza FALS; variabila pointata de errFisier va avea valoarea FALS daca a aparut o eroare IO sau ADEVARAT in caz contrar */ #endif // protectie mpotriva includerii multiple // a acestui fiier header

17

Exerciiul 2 Aplicaia anterioar poate fi extins prin urmrirea fluxului produselor. n acest scop se vor utiliza nc dou fiiere: - intrari - memoreaz codul produsului intrat n magazie i numrul de buci (ex: 315 40 -> au intrat 40 kg mere) - ieiri - memoreaz codul produsului ieit din magazie i numarul de buci (ex: 315 10 -> s-au vnd 10 kg mere) Pentru modelare nregistrrile din aceste fiiere trebuie definit nc o structur:
typedef struct produsIO{ int cod; int cantitate; }PRODUS_IO,*pPRODUS_IO;

Opiuni adugate la meniu:


B C D E S efectueaz o intrare afieaz intrrile efectueaz o ieire afieaz ieirile afieaza stocurile din magazie

5. Teme pentru studiu individual


Exerciiul 1 tergerea nregistrrilor O aplicaie real trebuie s permit i tergerea anumitor nregistrri. Acest aspect va fi luat n considerare pentru dezvoltarea unei versiuni mbuntite a aplicaiei. Exerciiul 2 datarea intrrilor i ieirilor Aplicaia de la laborator se va extinde astfel nct s permit pstrarea coordonatelor temporale asociate nregistrrilor cu privire la intrri i ieiri.

18

5. Cmpuri de bii
1. Obiective
nsuirea lucrului cu cmpuri de bii si uniuni programarea cu tipuri de date complexe definite de utilizator dezvoltarea aptitudinilor de programare modulara si structurata (utilizarea de segmente de date si cod, clase de memorare, fiier header, proiect);

2. Aspecte teoretice
Sa se elaboreze un program pentru evidenta tuturor studenilor si doctoranzilor Facultatii de Inginerie Electrica, nscrii la toate formele de invatamant aprobate de Minister: ingineri, masterat, studii aprofundate si doctorat. Persoanele care urmeaz studiile la aceste categorii vor fi denumite in continuare prin termenul 'inscrisi'. Programul va afia urmtorul meniu: F - precizare forma de invatamant R - citire date din fisier C - citire date de la tastatura despre inscrisi S - salvare date in fisier A - afisare inscrisi M - modifica datele despre un inscris T - terminare program

Precizarea formei de invatamant va fi ceruta initial de program, apoi va fi afisata in meniu pentru a permite utilizatorului sa lucreze si cu alta forma de invatamant. Toate celelalte optiuni se refera la inscrisii de la forma de invatamant precizata. Prin optiunea R, datele citite din fisier se vor adauga eventualelor date prezente in memorie. Optiunea C preia de la tastatura date despre inscrisii de la forma de invatamant precizata si le adauga in memorie. Optiunea S salveaza datele din memorie in fisierul indicat de utilizator. La optiunea M se afiseaza numele tuturor inscrisilor si un numar de ordine. Apoi se cere numarul de ordine al persoanei pentru care se vor modifica datele.

3.Fiiere puse la dispoziie


inscrisi.h evidenta.c citdate.c afisare.c inscrisi.c denspec.c denspec.h citiri.c citiri.h definire tipuri de date programul principal evidenta citire date despre inscrisi afisare date despre inscrisi segment de date cu inscrisi denumire specializari declaratii denumire specializari functii de citire prototipurile functiilor de citire

/* ======================================================== I N S C R I S I . H Contine declararea tipurilor de date pentru diferitele categorii de 'inscrisi', inclusiv tabloul buf[] de inscis is dimensiunea sa maxima (NMAX). (c)PSG2002 ======================================================== */ #ifndef INSCRISI_H #define INSCRISI_H

19

#define #define #define #define #define

NMAX _ING _MASTER _DSA _DOCTORAT

500 0 1 2 3

#define ADEVARAT 1 #define FALS (!ADEVARAT) typedef unsigned char LOGIC,COD; typedef struct { COD spec; float medii[5]; float licenta; } STUD_ING; typedef struct { COD spec; char fac[30]; float medii[2]; float disertatie; } MASTER; typedef struct { COD spec; char fac[30]; float medie_an; float disertatie; } DSA; typedef struct { COD domeniu; char fac[30]; unsigned ex1:2,ex2:2,ex3:2; // 0="A", 1="S" 2="B", 3="FB" unsigned rf1:2,rf2:2,rf3:2; // 0="A", 1="S" 2="B", 3="FB" char teza[15]; // 'foarte bine", "magna cumlaude" } DOCTORAND; typedef union { STUD_ING stud; MASTER sm; DSA sdsa; DOCTORAND drd; } INSCRIERE; typedef struct stcd { char nume[20]; unsigned an_admis:11; //...2047 unsigned sex:1; // 0=F, 1=M unsigned cat:3; //0 =ing, 1=cursant postuniv. 4 luni //1= DSA 2 = master, 3=doctorand unsigned an:3; INSCRIERE info; } INSCRISI; extern INSCRISI buf[]; #endif

20

/*

======================================================== I N S C R I S I . C Segment de date cu tabloul buf[] de 'inscrisi' (c)PSG2002 ======================================================== */ #include "inscrisi.h" INSCRISI buf[NMAX];

/* ======================================================== C I T I R I . C Fisierul contine functii gnerale de citire a valorilor unor variabile de tip int, double si sir de caractere. (c)PSG2002 ======================================================== */ #include <stdio.h> #include <conio.h> #include <string.h> #include "citiri.h" /* -------------------------------------------------------------c i t _ t e x t Functia realizeaza: - afisarea mesajului de atentionare - citirea unui sir de caractere de maxim n_car_max caractere - memoreaza caracterele citite la adresa dest -------------------------------------------------------------- */ char * cit_text(char *atentionare, char *dest, int n_car_max) { char *dest_0=dest; printf("%s:", atentionare); flushall(); for(n_car_max --;n_car_max > 0; n_car_max --, dest ++) if((*dest = getche())== ENTER)break; *dest = EOS; return dest_0; } /* -------------------------------------------------------------c i t _ d o u b l e Citeste un real, dupa avertizarea utilizatorului prin citirea unui mesaj de atentionare pe ecran. Rezultatul returnat de functie este valoarea citita. Citirea este programata pentru ca functia sa fie operationala si pe versiunile de compilatoare C unde nu s-a implementat si formatul real de citire a datelor -------------------------------------------------------------- */ double cit_double(char *atentionare) { double val; char cifre[25]; cit_text(atentionare, cifre,25); sscanf(cifre, "%lf", &val); return val; }

21

/* -------------------------------------------------------------c i t _ i n t Citeste un intreg dupa afisarea prealabila a mesajului de la adresa atentionare. Verifica daca valoarea citita este cuprinsa in intervalul [a,b] -------------------------------------------------------------- */ int cit_int(char *atentionare, int a, int b) {int n; flushall(); do{ printf("%s (%d, %d)= ", atentionare, a, b); scanf("%d", &n); } while(n<a||n>b); return n; } /* -------------------------------------------------------------c i t _ f l o a t Citeste un float dupa afisarea prealabila a mesajului de la adresa atentionare. Verifica daca valoarea citita este cuprinsa in intervalul [a,b] -------------------------------------------------------------- */ float cit_float(char *atentionare, float a, float b) {float x; do{ printf("%s (%f, %f)= ", atentionare, a, b); scanf("%f", &x); } while(x<a||x>b); return x; } /* -------------------------------------------------------------f g e t _ s i r ( s, n, f) Citeste un sir din fisierul f. Are functionarea asemanatoare cu a lui fgets Suplimentar elimina new-line de la sfirsitul sirului. Vezi si functia fput_sir din acest fisier sursa. -------------------------------------------------------------- */ char *fget_sir( char *s , int n , FILE *f) { char *ret_fgets; if( (ret_fgets= fgets(s , n , f)) != 0) { *(s + strlen(s) - 1) = '\0'; /* eliminare new-line */ } return ret_fgets; }

22

/*

-------------------------------------------------------------f p u t s i r Scrie in fisierul f sirul de caractere s urmat de un '\n'. -------------------------------------------------------------- */ int fputsir(char *s,FILE *f) { fputs(s, f); return fputc('\n', f); } // Actualizata dupa functia din bc_Help long unsigned LungimeFisier(FILE *fis) { long unsigned poz_crt, lung; poz_crt = ftell(fis); fseek(fis, 0L, SEEK_END); lung = ftell(fis); fseek(fis, poz_crt, SEEK_SET); return lung; } /* ======================================================== D E N S P E C . C Fisierul contine denumirile specializarilor formelor de invatamant si a domeniilor de doctorat, precum si durata acestora (nr_ani[]). (c)PSG2002 ======================================================== */ #include <stdio.h> char *spec_ing[] ={ "Calculatoare", "Automatica si informatica industriala", "Electronica", "Electrotehnica", "Energetica", "Inginerie economica"}; char *spec_post[] = {"Informatica", "Sisteme inteligente in controlul proceselor"}; char *domenii[] = { "Electronica si telecomunicatii", "Inginerie electrica", "Stiinta calculatoarelor" }; int nr_ani[]={5,2,1,6}; #define NR_pCHAR(x) sizeof(x)/sizeof(char *) int nr_specializari[]= {NR_pCHAR(spec_ing), NR_pCHAR(spec_post), NR_pCHAR(spec_post), NR_pCHAR(domenii) }; char **adresa[] = { spec_ing, spec_post, spec_post, domenii}; void AfiseazaDenumiri(int forma_inv) { int i; char **den = adresa[forma_inv]; for(i=1; i<=nr_specializari[forma_inv]; i++) printf("\n%d-%s",i, den[i-1]); }

23

/* ======================================================== E V I D E N T A . C Programul realizeaza evidenta tuturor studentilor si doctoranzilor Facultatii de Inginerie Electrica, inscrisi la toate formele de invatamant aprobate: ingineri, masterat, studii aprofundate si doctorat. Persoanele care urmeaza studiile la aceste categorii vor fi denumite prin termenul 'inscrisi'. Fisierul contine functia main() si meniu(). (c)PSG2002 ======================================================== */ #include <stdio.h> #include <string.h> #include <conio.h> #include <ctype.h> #include <stdlib.h> #include "inscrisi.h" #include "citiri.h" #define INFINIT 1 char meniu(); extern int CitireDateTastatura(int forma_inv, int nr_inscrisi); extern void AfisareInscrisi(int nr_inscrisi); void main() { char *txt_forma_inv="\nForma de invatamant: 0=ing,1=master,2=DSA,3=doctorat"; int forma_inv, nr_inscrisi=0; forma_inv=cit_int(txt_forma_inv, 0,3); while(INFINIT) switch(meniu()) { case 'F': forma_inv=cit_int(txt_forma_inv, 0,3); break; case 'C': nr_inscrisi=CitireDateTastatura(forma_inv,nr_inscrisi); break; case 'A': AfisareInscrisi(nr_inscrisi); break; case 'T': return; default: printf("\n*** Optiune neimplementata"); break; } } char meniu() { printf("\n\n" "\nF - precizare forma de invatamant" "\nR - citire date din fisier" "\nC - citire date de la tastatura despre inscrisi" "\nS - salvare date in fisier" "\nA - afisare inscrisi" "\nM - modifica datele despre un inscris" "\nT - terminare program" "\nOptiunea dv.:" ); return toupper(getche()); }

24

/* ======================================================== C I T D A T E . C Contine functiile de citire a datelor pentru diferitele categorii de 'inscrisi'. (c)PSG2002 ======================================================== */ #include <stdio.h> #include <string.h> #include <conio.h> #include <ctype.h> #include <stdlib.h> #include "inscrisi.h" #include "citiri.h" #include "denspec.h" LOGIC CitireDateComune (INSCRISI *p); void CitesteDateStudIng(int nr); void CitesteDateMaster(int nr); void CitesteDateDSA(int nr); void CitesteDateDoctorand(int nr); int CitireDateTastatura(int forma_inv, int nr_inscrisi) { printf("\n\n*** Dati ENTER la 'Nume :' cand ati terminat!"); for (;nr_inscrisi<=NMAX; nr_inscrisi++) { // // Date comune tuturor categoriilor // if(!CitireDateComune(&buf[nr_inscrisi])) break; buf[nr_inscrisi].cat = forma_inv; buf[nr_inscrisi].an = cit_int("Anul de studii",1,nr_ani[forma_inv]); // // Partea de informatii specifica fiecarei categorii // switch (forma_inv) { case _ING: CitesteDateStudIng(nr_inscrisi); break; case _MASTER: CitesteDateMaster(nr_inscrisi); break; case _DSA: CitesteDateDSA(nr_inscrisi); break; case _DOCTORAT: CitesteDateDoctorand(nr_inscrisi); break; } } return nr_inscrisi; }

25

static LOGIC CitireDateComune (INSCRISI *p) { if(*cit_text("\nNume ",p->nume,sizeof(p->nume))==EOS) return FALS; p->an_admis = cit_int ("\nAn admis",2000,2047); p->sex = cit_int ("Sex <0=F, 1=M>",0,1); return ADEVARAT; }

COD CitesteSpecializare(int forma_inv); void CitesteMedii(float *med, int n); static void CitesteDateStudIng(int nr) { buf[nr].info.stud.spec=CitesteSpecializare(_ING); CitesteMedii(buf[nr].info.stud.medii, buf[nr].an); if(buf[nr].an==5) buf[nr].info.stud.licenta = cit_float("Media licenta",1.,10.); } static COD CitesteSpecializare(int forma_inv) { printf("\nAlegeti codul specializarii:"); AfiseazaDenumiri(forma_inv); return (COD)cit_int("\nCod specializare", 1, nr_specializari[forma_inv]); } static void CitesteMedii(float *med, int an) { int j; char msg[20]; for(j=1;j<=an;j++) { sprintf(msg,"Media anului %d",j); med[j-1]=cit_float(msg, j<an?5.:1., 10.); } } static void CitesteDateMaster(int nr) { buf[nr].info.sm.spec=CitesteSpecializare(_MASTER); cit_text("Faculatea absolvita",buf[nr].info.sm.fac, sizeof(buf[nr].info.sm.fac)); printf("\n"); CitesteMedii(buf[nr].info.sm.medii,buf[nr].an); if(buf[nr].an==2) buf[nr].info.sm.disertatie = cit_float("Media lucrare de disertatie",1.,10.); } static void CitesteDateDSA(int nr) { } static void CitesteDateDoctorand(int nr) { }

26

/* ======================================================== A F I S A R E . C Contine functiile de afisare ale diferitelor categorii de 'inscrisi'.

(c)PSG2002 ======================================================== */ #include #include #include #include #include #include #include void void void void void <stdio.h> <string.h> <conio.h> <ctype.h> <stdlib.h> "inscrisi.h" "denspec.h"

AfisareDateComune (INSCRISI pers); AfisareDateStudIng(int nr); AfisareDateMaster(int nr); AfisareDateDSA(int nr); AfisareDateDoctorand(int nr);

void AfisareInscrisi(int nr_inscrisi) { int nr; for (nr=0;nr<nr_inscrisi; nr++) { // // Date comune tuturor categoriilor // AfisareDateComune(buf[nr]); // // Afisare informatii specifice fiecarei categorii // switch (buf[nr].cat) { case _ING: AfisareDateStudIng(nr); break; case _MASTER: AfisareDateMaster(nr); break; case _DSA: AfisareDateDSA(nr); break; case _DOCTORAT: AfisareDateDoctorand(nr); break; } } }

27

static void AfisareDateComune (INSCRISI p) { printf("\n\nNume: %s\nSex : %c",p.nume,p.sex?'M':'F'); printf("\nAn admis : %d",p.an_admis); printf("\nAn de studiu : %d",p.an); } static void AfisareMedii(float *med, int n); static void AfisareDateStudIng(int nr) { printf("\nSpecializare : %s", spec_ing[buf[nr].info.stud.spec-1]); AfisareMedii(buf[nr].info.stud.medii, buf[nr].an); if(buf[nr].an==5) printf("\nMedia licenta : %.2f",buf[nr].info.stud.licenta); } static void AfisareMedii(float *med, int an) { int j; for(j=1;j<=an;j++) printf("\nMedia anului %d: %.2f",j,med[j-1]); } static void AfisareDateMaster(int nr) { printf("\nSpecializare : %s", spec_post[buf[nr].info.sm.spec-1]); printf("\nFaculatea absolvita : %s",buf[nr].info.sm.fac); AfisareMedii(buf[nr].info.sm.medii, buf[nr].an); if(buf[nr].an==2) printf("\nMedia disertatie %.2f",buf[nr].info.sm.disertatie);

} static void AfisareDateDSA(int nr) { } static void AfisareDateDoctorand(int nr) { }

28

/* ======================================================== C I T I R I . H Fisierul contine prototipurile functiilor gnerale de citire a valorilor unor variabile de tip int, double si sir de caractere (definitiile sunt lor in citiri.c) (c)PSG2002 ======================================================== */ #ifndef CITIRI_H #define CITIRI_H #define #define ENTER '\r' EOS '\0'

char * cit_text(char *, char *, int ); int cit_int(char *, int , int ); float cit_float(char *atentionare, float a, float b); double cit_double(char *); char *fget_sir( char * , int , FILE *); int fputsir(char * , FILE *); long unsigned LungimeFisier(FILE *fis); #endif

/* ========================================================

D E N S P E C . H

Contine declaratiile corespunzatoarea datelor din fisierul denspec.c (denumiri specializari si durata acestora (nr_ani)

(c)PSG2002 ======================================================== */ #ifndef DENSPEC_H #define DENSPEC_H extern int nr_ani[]; extern int nr_specializari[]; extern char *spec_ing[], *spec_post[], *domenii[]; void AfiseazaDenumiri(int forma_inv); #endif

29

4. Tem de realizat n timpul laboratorului


De rezolvat (in cadrul lucrrii de laborator si sub forma de tema de casa). Se vor programa toate opiunile acestui program si se vor rezolva urmtoarele prin completarea si eventual modificarea surselor puse la dispoziie. 1. La terminarea programului se pot pierde date nesalvate in fiier. De aceea, in cazul cnd in memorie se afla date nou introduse, utilizatorul va fi ntrebat automat daca dorete sa le salveze. 2. Configurai programul pentru cazul real al nscriilor din Facultatea de Inginerie Electrica: ingineri (maxim 1500), master (maxim 250), DSA(maxim 150), doctoranzi (maxim 100). 3. Numele celor nscrii este memorat pe lungimea maxima data in structura. Reprogramai lund in considerare stocarea numelui pe n+1 caractere, unde n este numrul de caractere al numelui persoanei nscrise. 4. Luai in considerare memorarea denumirilor specializrilor intr-un fiier. Folosii o tehnica similara cu cea utilizata in laboratorul trecut in cazul denumirilor de discipline. 5. Programai o validare a datelor introduse lund in consideraie corespondena (an_admis, an de studii) pentru valoarea maxima a anului de studii cat si data curenta din calculator pentru valoarea maxima an_admis. La afiarea datelor in versiunea actuala afiarea nscriilor are loc in ordinea in care sunt prezeni acetia in tabloul buf[]. Realizai afiarea lor grupat, pe forme de nvmnt. 6. Programai funciile de cutare nscris dup nume si 'exmatriculare' (tergere din buf[]). 7. *Programai toate funciile acestui program, inclusiv cutare si tergere lucrnd direct in fiier.

30

6. Liste liniare
1.Obiective
Dezvoltarea de tipuri de date abstracte n limbajul C; nsuirea lucrului cu tipul de dat abstract lista; Implementarea listelor liniare prin vector de dimensiune variabil alocat dinamic; Implementarea operaiilor de salvare/citire a listelor n/din fiierele text;

2.Aspecte teoretice
O list liniar este o secven de elemente ce pot fi regsite prin numrul de ordine (al locului pe care l ocup) n acea secven. l=<e1,e2,,en> Trebuie subliniat faptul c numrul de ordine al fiecrui element, esenial n definiia listei, nu este neaprat legat de valoarea elementelor listei. De altfel acestea pot nici s nu fie date scalare, deci comparaiile nu pot avea loc. Operaii principale asupra listelor liniare: init() iniializeaz o list; insert_inc(l,e) insereaz n faa primului element din lista l, elementul e; insert_sfirsit(l,e) - insereaz dup ultimul element din lista l, elementul e; insert_stinga(l,e,f) insereaz n faa elementului e din lista l, elementul f; insert_sfirsit(l,e,f) insereaz dup elementul e din lista l, elementul f; sterge_prim(l) terge primul element din lista l; sterge_ultim(l) terge ultimul element din lista l; sterge(l,e) - terge elemental e din lista l; distrugere(l) ncheie toate operaiile cu lista l, elibereaz eventual spaiul ocupat de list; Alte operaii: cauta(l,e) caut n lista l, elementul e; este_vida(l,e) testeaz dac lista l este vid(nu conine elemente); este_plina(l,e) testeaz dac lista l este plin(nu mai pot fi adugate elemente noi); O implementare prin vector alocat dinamic a listelor liniare n limbajul C poate utiliza urmtoarea structur:
struct dlist { int liber; int nmax; DATA *pv; //poziia n care va fi inserat un nou element //numrul maxim de elemente //pointer la tipul DATA pentru alocarea dinamic a //vectorului ce conine elementele listei

};

31

Un avantaj major al listelor liniare implementate prin vector de dimensiune variabil alocat dinamic este dat de faptul c listele i mresc capacitatea n mod dinamic. Se ajunge astfel, la o mai buna gestiune a memoriei, evitndu-se pe de o parte alocarea un numr prea mare de elemente i pe de alt parte a unui numr prea mic de elemente. Membrul nmax al structurii dlist va conine numrul maxim de elemente ce pot fi introduse n list i ii va schimba valoarea n mod dinamic (va crete cu o constant N_INIT), de fiecare dat cnd se ajunge la capacitatea maxim. Unul din cele mai importante aspecte legate de aceast implementare se refer la creterea n mod dinamic a capacitii vectorului. Acest aspect este prezentat n funcia de adugare a unui nou element la sfritul listei.
LISTA ins_la_urma(LISTA l, DATA x) { DATA *w; int i; if(este_plina(l)) { //Alocarea unei noi zone de memorie pentru vectorul ce conine elementele //listei. Noul vector va avea un numr de elemente egal cu numrul maxim //de elemente (nmax) la care se adaug valoarea N_INIT. if((w=malloc( (l->nmax+N_INIT)*sizeof(DATA) ) )==NULL) return l; //Copierea datelor din zona de memorie a crei adres de nceput este dat //de pv n noua zon de memorie (copierea elementelor listei) for(i=0;i<l->nmax;i++) w[i]=l->pv[i]; //Creterea numrului maxim de elemente l->nmax = l->nmax+N_INIT; //Eliberarea zonei de memorie spre care pointeaz pv free(l->pv); //Setarea pointerului pv la adresa de nceput a noii zone de memorie ce //conine elementele listei l->pv = w; } //Adugarea noului element l->pv[l->liber++]=x; return l; }

n figurile urmtoare este prezentat modalitatea de cretere n mod dinamic a capacitii vectorului ce conine elementele listei i de adugare a unui nou element la sfritul listei.

32

3. Tem de realizat n timpul laboratorului


S se scrie un program C care implementeaz tipul de dat abstract lista. Se vor putea efectua operaii cu liste liniare implementate prin vectori alocai dinamic, ale cror elemente conin chei ntregi. Programul va afia meniul urmtor i va efectua operaiile corespunztoare: C - citete un numr ntreg i-l introduce n faa listei L R - citete un fiier text ce conine numere ntregi separate prin spaii i le introduce n lista A - afieaza lista L S - caut un element n lista L E - elimin primul element din lista L W - salveaz lista L ntr-un fiier text D - din lista L se formeaz dou noi liste, una ce conine elementele negative i una coninnd elementele pozitive P - afieaza lista coninnd elementele pozitive N - afieaz lista coninnd elementele negative I - informaii despre autor T - terminare program

33

n cazul opiunilor R i W se va afia coninutul fiierului citit/scris, iar numele fiierului va fi introdus de la tastatur. Vei implementa tipul de dat abstract lista n 3 fiiere: data.h, listdinv.h i listdinv.c. Programul demonstrativ va fi realizat sub forma unui fiier separat (demolist.c). Vei introduce opiuni suplimentare pentru testarea celorlalte metode ale TDA lista care au prototipuri n listdinv.h (sterge_primul, ins_la_urma, sterge_ultim,terge un element de cheie dat indiferent de poziie).

4. Fiiere puse la dispoziie


Fiierul data.h conine definiia tipului informaiei din elementele TDA lista Fiierul listdinv.h conine prototipurile funciilor de lucru cu TDA lista Fiierul listdinv.c conine definiiile funciilor de lucru cu TDA lista

Fiierul data.h
#ifndef _DATA_H_ #define _DATA_H_ #define ADEVARAT 1 #define FALS 0 typedef unsigned char LOGIC; // //----------------------------------------// Rezervat modificarilor utilizatorului // care va preciza tipul informatiei din // elementele TDA //----------------------------------------// typedef int DATA; #define FORMAT "%d" #define ABSENT 0 // //----------------------------------------#endif

Fisierul ListDinv.h
#ifndef _LISTDINV_H_ #define _LISTDINV_H_ #include "data.h" //----------------------------------// Proprietatile TDA lista in reprez. // cu vector alocat dinamic de dimensiune extensibila dinamic // #define N_INIT 10 struct dlist { int liber; int nmax; DATA *pv; }; typedef struct dlist Lista, *LISTA;

34

// //---------------------------------// Metodele (operatiile) TDA // LISTA newl(); LISTA ins_la_urma(LISTA l, DATA x); LISTA sterge_ultim(LISTA l); DATA primul(LISTA l); LOGIC este_vida(LISTA l); LOGIC este_plina(LISTA l); char *conv_lista_sir(LISTA l,char *s); // ... void destroyl(LISTA l); #endif

Fisierul ListDinv.c
#include #include #include #include <stdio.h> <string.h> "listdinv.h" <stdlib.h>

//--------------------------------------------------// Metodele TDA lista in implementarea // cu vector de dimensiune extensibila alocat dinamic // // Elaborat: PSG, 08.04.03 //--------------------------------------------------// // Initializare lista // LISTA newl() { LISTA l; if((l=(LISTA)malloc(sizeof(Lista)))==NULL) return NULL; l->nmax=2; l->liber=0; if((l->pv=malloc( N_INIT * sizeof(DATA) ) ) ==NULL) { free(l); l=NULL;} return l; } //------------------------------------// Distruge lista // void destroyl(LISTA l) { free(l->pv); free(l); } //--------------------------------------// Inserarea unui nou element // la sfarsitul listei // Daca lista este plina, extinde dimens. // LISTA ins_la_urma(LISTA l, DATA x) { DATA *w; int i;

35

if(este_plina(l)) { if((w=malloc( (l->nmax+N_INIT)*sizeof(DATA) ) )==NULL) return l; for(i=0;i<l->nmax;i++) w[i]=l->pv[i]; l->nmax = l->nmax+N_INIT; free(l->pv); l->pv = w; } l->pv[l->liber++]=x; return l; } // //--------------------------------------// Sterge ultimul element introdus // LISTA sterge_ultim(LISTA l) { if(!este_vida(l)) l->liber--; return l; } // //------------------------------------// Returneaza valoarea primului element // al listei // DATA primul(LISTA l) { return este_vida(l) ? ABSENT : l->pv[0]; } //------------------------------------LOGIC este_vida(LISTA l) { return l->liber==0; } //------------------------------------LOGIC este_plina(LISTA l) { return l->liber==l->nmax; } // //------------------------------------// Conversie lista -> sir // char *conv_lista_sir(LISTA l, char *s) { int i; char zona[10]; strcpy(s,"{"); if(este_vida(l)) strcat(s,"<vida>}"); else for(i=0;i<l->liber;i++) { sprintf(zona,FORMAT"%c",l->pv[i], i==l->liber-1?'}':','); strcat(s,zona); } return s; }

36

7. Liste simplu nlnuite


1.Obiective
Familiarizarea cu tipul de dat abstract list; Implementarea TDA list cu ajutorul pointerilor (lista simplu nlnuit); Implementarea unei aplicaii care sa utilizeze liste simplu nlnuite.

2.Aspecte teoretice
Lista este, dup cum s-a precizat in laboratorul precedent, o mulime de elemente, a crui numr variaz n timpul execuiei unui program. Lista simplu nlnuit vine in ntmpinarea acestui dinamism prin modul de implementare, si anume: un element (sau nod) al listei este un tip de data abstract ce conine pe lng informaia (sau informaiile) corespunztoare elementului, adresa urmtorului element al listei:
struct nod{ int info; struct nod * urm; };

lista consta intr-o singura variabila de tip pointer la struct nod care tine adresa primului element al listei:
struct nod * ListaElemente;

Lista simplu nlnuit are urmtoarele avantaje fa de lista implementat prin vectori: - nu este necesar alocarea unei zone continue de memorie ( ca in cazul vectorilor) - operaiile de adugare si tergere element se simplific, nemaifiind necesar mutarea tuturor elementelor Exist i un dezavantaj: - spaiul ocupat de o lista simplu nlnuit este mai mare dect n cazul vectorilor, datorit pointerului care intr in componena fiecrui element al listei. Pentru a utiliza o lista simplu nlnuit sunt necesare urmtoarele metode:
init() iniializeaz o list; adauga_inceput(l,e) insereaz n faa primului element din lista l, elementul e; adauga_sfirsit(l,e) - insereaz dup ultimul element din lista l, elementul e; adauga_stinga(l,e,f) insereaz n faa elementului e din lista l, elementul f; adauga_dupa(l,e,f) insereaz dup elementul e din lista l, elementul f; sterge_prim(l) terge primul element din lista l; sterge_ultim(l) terge ultimul element din lista l; sterge(l,e) - terge elementul e din lista l; distrugere(l) ncheie toate operaiile cu lista l, elibereaz eventual spaiul ocupat de list;

Alte metode: cauta(l,e) caut n lista l, elementul e; este_vida(l,e) testeaz dac lista l este vid(nu conine elemente); este_plina(l,e) testeaz dac lista l este plin(nu mai pot fi adugate elemente noi);
37

Observaii: La iniializarea listei se modific valoarea pointerului din variabila ListaElemente la NULL, pentru a arata ca nu exista nici un element (dac nu se realizeaz aceast operaie, variabila ListaElemente are o valoare diferit de NULL care poate fi confundat cu o adres de element i prin urmare, la o eventuala verificare a strii, lista apare ca avnd elemente). La inserarea unui element trebuie realizai urmtorii pai n ordinea specificat: o alocare zona de memorie de dimensiune egala cu numrul de octei necesari pentru a memora un element al listei, o memorarea in aceasta zona a informaiilor noi o realizarea legturii cu elementele deja existente in lista La tergerea unui element din lista trebuie realizai urmtorii pai n ordinea specificat: o pstrarea ntr-o variabil temporar a adresei elementului ce urmeaz a fi ters o realizarea legturilor astfel nct elementul de ters s nu mai apar n list o eliberarea zonei de memorie ocupat de elementul ce trebuie ters tergerea unui element sau a ntregii liste nu este echivalenta cu tergerea efectiva a informaiilor din memorie, ci vizeaz marcarea zonei de memorie ca fiind disponibil pentru stocarea altor informaii.

3. Tem de realizat n timpul laboratorului


Sa se scrie un program C care implementeaz tipul de data abstracta lista. Se vor putea efectua operaii cu liste nlnuite, ale cror elemente conin chei ntregi. Programul va afia meniul urmtor: C - citete un numr ntreg i l introduce n faa listei L R - citete un fiier text ce conine numere ntregi separate prin spaii i le introduce n lista L A - afieaz lista L S - caut un element in lista L E - elimina primul element din lista L W - salveaz lista L intr-un fiier text D - din lista L se formeaz doua noi liste, cu elementele negative i respectiv pozitive P - afieaz lista coninnd elementele pozitive N - afieaz lista coninnd elementele negative I - informaii despre autor T - terminare program In cazul opiunilor R si W se va afia coninutul fiierului citit/scris, iar numele fiierului va fi cerut utilizatorului. Se vor introduce opiuni suplimentare pentru testarea celorlalte metode ale TDA lista care au prototipuri in Lista.h (sterge_primul, ins_la_urma, sterge_ultim, sterge - terge un element de cheie dat, indiferent de poziie).

4. Fiiere puse la dispoziie


Pentru realizarea aplicaiei propuse la acest laborator se vor utiliza urmtoarele fiiere: data.h fiier header ce conine definiia tipului de informaie continuta de elementele din TDA lista simplu inlantuita; lista.h - fiier header ce conine prototipurile funciilor specifice TDA lista simplu inlantuita; lista.c - fiier surs C cu implementarea funciilor corespunztoare TDA lista simplu inlantuita. Programul demonstrativ va fi realizat sub forma unui fisier separat (demolist.c).
38

Fiierul data.h
#ifndef _DATA_H_ #define _DATA_H_ #define FALS 0 #define ADEVARAT (!FALS) typedef unsigned char LOGIC; // //----------------------------------------// Rezervat modificarilor utilizatorului // care va preciza tipul informatiei din // elementele TDA // PSG, 1.04.03 //----------------------------------------// typedef int DATA; #define FORMAT "%d" #define ABSENT 0 // //----------------------------------------#endif

Fiierul lista.h
#ifndef _LISTA_H_ #define _LISTA_H_ #include "data.h" // // Elaborat: PSG, 11.04.03 //---------------------------------// Proprietatile TDA // struct clist { DATA cheie; struct clist *urm; }; typedef struct clist Lista, *LISTA; // //---------------------------------// Metodele (operatiile) TDA // LISTA newl(void); LISTA ins_in_fata(LISTA l, DATA x); LISTA sterge_primul(LISTA l); LISTA ins_la_urma(LISTA l, DATA x); LISTA sterge_ultim(LISTA l); LISTA sterge(LISTA l, DATA x); LISTA cauta(LISTA l, DATA x); DATA primul(LISTA l); LOGIC este_vida(LISTA l); LOGIC este_plina(LISTA l); char *conv_sir_lista(LISTA l,char *s); // ... void destroyl(LISTA l); #endif

39

Fiierul lista.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "lista.h" // ---------------------------------------------------// Metodele TDA lista in implementarea // cu vector alocat static // Elaborat: PSG, 11.04.03 // Modificat:PSG, 13.04.05 // ---------------------------------------------------// Initializeaza o lista vida // LISTA newl() { return NULL; } // // ---------------------------------------------------// Distruge o lista vida // void destroyl(LISTA l) { LISTA p; for(;!este_vida(l); l=p) { p=l->urm; free(l); } } // // ---------------------------------------------------// Insereaza un element in fata listei // LISTA ins_in_fata(LISTA l, DATA x) { LISTA t; if((t = (LISTA)malloc(sizeof(Lista)))==NULL) { printf("\n\a EROARE la alocarea memoriei"); return l; } // alocare reusita t->cheie = x; t->urm = l; return t; } // // ----------------------------------------------------// // Cauta o cheie in lista si intoarce adresa elementului // LISTA cauta(LISTA l,DATA x) { for( ;!este_vida(l) ;l=l->urm) if(l->cheie==x) return l; return NULL; }

40

// // ---------------------------------------------------// // Returneaza cheia primului element al listei // sau ABSENT daca nu este in lista // DATA primul(LISTA l) { return este_vida(l) ? ABSENT:l->cheie ; } // // ---------------------------------------------------// Verifica daca lista este vida // LOGIC este_vida(LISTA l) { return l==NULL; } // // ---------------------------------------------------// Verifica daca lista este plina // Se poate rescrie aceasta functi // LOGIC este_plina(LISTA l) { return FALS; } // // ---------------------------------------------------// // Conversie lista in sir de caractere // char *conv_sir_lista(LISTA l,char *s) { char zona[20]; strcpy(s,"{"); if(este_vida(l)) strcat(s,"<vida>}"); else for(;!este_vida(l); l=l->urm) { sprintf(zona,FORMAT"%c",primul(l), este_vida(l->urm)?'}':','); strcat(s,zona); } return s; } // ---------------------------------------------------// // T E M A D E E F E C T U A T // ---------------------------------------------------LISTA sterge_primul(LISTA l) {} LISTA ins_la_urma(LISTA l, DATA x) {} LISTA sterge_ultim(LISTA l) {} LISTA sterge(LISTA l, DATA x) {}

41

5. Tem pentru studiu individual


La concertul de muzica clasica care are loc o data pe an in judeul Suceava, se realizeaz anul acesta un studiu despre oamenii care vin la acest spectacol, pentru a vedea daca se poate organiza de doua sau chiar trei ori pe an. Informaiile reinute despre fiecare persoana care i cumpr bilet sunt: adresa (nu cea exact; cea din care s rezulte zona in care locuiete), ocupaia, vrsta, numr bilet. In cazul in care o persoana cumpr bilete pentru mai multe persoane se vor cere informaii despre fiecare in parte. Sa se implementeze o aplicaie care sa permit efectuarea urmtoarelor operaii utiliznd lista simplu nlnuit: A. Adugare informaii despre o persoana. L. Listare informaii despre toate persoanele care si-au cumprat bilet pana la un moment dat S. tergere informaii despre o persoana in cazul in care aceasta renun la bilet D. Afiare bilete disponibile Z. Afiarea numrului de bilete vndute pe zone din ora V. Sa se realizeze trei liste corespunztoare fiecrui interval de vrsta in care se ncadreaz cumprtorii (10-25, 25- 40, 40-65) si sa se determine intervalul cu numr maxim de persoane. O. Sa se afieze toate persoanele care au o anumita ocupaie si au cumprat bilet pentru concert. T. Terminare program Observaii 1. Un element al listei n acest caz va arta n modul urmtor:
struct persoana{ int nr_bilet; char * adresa; char * ocupatie; int varsta; };
nr_bilet adresa ocupatie varsta

\0 \0

2. La adugarea unui element nou trebuie alocat memorie att pentru structura in sine ct i pentru cele dou iruri de caractere care vor tine adresa si ocupaia. 3. La tergerea unui element se va elibera mai nti zona alocat irurilor de caractere i apoi cea alocat structurii.

42

8. Stiva
1.Obiective
Familiarizarea cu tipul de dat abstract stiva; Implementarea TDA stiv prin motenire din TDA lista; Verificarea nchiderii corecte a parantezelor n cazul unei expresii matematice.

2.Aspecte teoretice
Stiva este un caz particular de structur de date liniar n care intrrile i ieirile se fac la un singur capt al ei. Structura de stiv presupune, conform definiiei, o anumit disciplin de acces. Se spune c accesul la o stiva este de tip LIFO (Last In - First Out): totdeauna se adaug un obiect "deasupra" ultimului depus; totdeauna se extrage ultimul obiect adugat. Aceast structur de date cunoate mai multe implementri (vectori alocai static sau dinamic, nlnuire simpl). Toate implementrile au n comun cunoaterea n permanen a vrfului stivei. Operaiile de inserare i respectiv extragere ale elementelor sunt foarte rapide deoarece nu necesit parcurgerea stivei i deci nu depind de numrul de elemente. Operaiile cu stiva poart urmtoarele denumiri consacrate: push inserare n stiv pop ndeprtarea elementului din vrful stivei top afiarea elementului din vrful stivei toppop operaia top urmat de pop Se prezint n continuare evoluia unei stive implementat prin nlnuire pentru urmtoarea succesiune de operaii (push(7), push(2), push (9), pop(). Vrful stivei (nceputul nlnuirii) este indicat chiar de pointerul s (spre primul element).
s este NULL stiva este vid push (7) s 7 push (2) s 2 push (9) s pop () s 2 7 9 2 7 7

43

3.Exemple
Pentru realizarea aplicaiei propuse la acest laborator se va porni de la urmtoarele fiiere: data.h fiier header pentru implementarea tipului DATA; lista.h - fiier header pentru implementarea TDA lista; lista.c fiier surs C cu implementarea funciilor corespunztoare TDA lista; stiva.h - fiier header pentru implementarea TDA stiva; stiva.c - fiier surs C cu implementarea funciilor corespunztoare TDA. Primele trei fiiere au fost prezentate n laboratorul corespunztor listelor.
//-------------------------------------------------------// F i s i e r u l s t i v a . h //-------------------------------------------------------#ifndef __STIVA_H_ #define __STIVA_H_ #include "lista.h" typedef LISTA STIVA; // initializare stiva extern STIVA news(); // inserare element in stiva extern STIVA push(STIVA,DATA); // indepartare element din stiva extern STIVA pop(STIVA); // afisarea elementului din varful stivei extern DATA top(STIVA); // afisarea elementului din varful stivei si stergerea lui extern STIVA toppop(STIVA ,DATA *); // testare stiva vida extern LOGIC is_emptys(STIVA); // testare stiva plina extern LOGIC is_fulls(STIVA); // conversie stiva la sir extern char * toString(STIVA s, char *zona); // eliberare spatiu alocat de stiva extern void destroys(STIVA); #endif

44

//-------------------------------------------------------// F i s i e r u l s t i v a . c //-------------------------------------------------------#include "stiva.h" #include "lista.h" STIVA news(){ return (STIVA)newl(); } //-------------------------------------------------------STIVA push(STIVA s,DATA x){ return ins_in_fata((LISTA)s,x); } //--------------------------------------------------------STIVA pop(STIVA s){ return (STIVA) sterge_prim((LISTA)s); } //--------------------------------------------------------DATA top(STIVA s){ return is_empty(s)?ABSENT : primul(LISTA)s); } //--------------------------------------------------------STIVA toppop(STIVA s, DATA *val){ *val=top(s); return pop(s); } //--------------------------------------------------------LOGIC is_emptys( STIVA s){ return este_vida((LISTA)s); } //--------------------------------------------------------LOGIC is_fulls(STIVA s){ return este_plina((LISTA)s); } // --------------------------------------------------------char * toString(STIVA s, char *zona){ // completati cu codul necesar conversiei stivei s la sir } //--------------------------------------------------------void destroys(STIVA s){ destroy((LISTA)s); }

45

4. Tem de realizat n timpul laboratorului


Exerciiul 1 S se realizeze o aplicaie tip meniu care s permit testarea operaiilor cu stive. Stiva va conine elemente de tip caracter:
P Q T U S A V inserarea unui element in stiva indepartarea elementului din varful stivei afisarea elementului din varful stivei afisarea si ulterior stergerea elementului din varful stivei afisarea starii stivei (plina, vida, contine elemente) afisarea stivei prin folosirea functiei toString verificarea inchiderii corecte a parantezelor rotunde in cazul unui sir de caractere, ignorand operanzii sau operatorii I info autor G gata program

Exerciiul 2 extindere verificare paranteze n aplicaia anterioar, la cazul v se presupune c irul conine numai paranteze rotunde. Problema validrii nchiderii corecte a parantezelor poate fi generalizat n sensul urmririi unor perechi de simboluri definite anterior. n cazul unei expresii incorecte s se genereze un mesaj de eroare ct mai explicit. Secvena se consider valid dac: fiecare pereche conine un simbol de tipul stnga i un simbol de tipul dreapta; fiecare simbol face parte din exact o pereche; secvena de simboluri care apare ntre simbol_stnga i simbolul_dreapta trebuie s satisfac cele dou condiii anterioare. De exemplu, fiind date perechile: ( - ), [ - ], { - }, S D, urmtoarea secven este valid: (S[{SD()[]}]D)

5. Tem pentru studiu individual


Exerciiul 1 evaluarea unei expresii aritmetice postfixate Pe lng notaia uzual a expresiilor aritmetice (notaia infixat) mai exist notaiile prefixate i respective postfixate. Ambele au avantajul c nu necesit paranteze pentru indicarea prioritilor. infixat: (5 - 3) * 9 prefixat: * - 5 3 9 postfixat: 5 3 9 *

Expresiile scrise n notaie postfixat pot fi uor evaluate utiliznd o stiv. Se citesc pe rnd cuvintele din irul de caractere reprezentnd expresia aritmetic. Dac respectivul cuvnt este un numr atunci acea valoare este inserat n stiv. La ntlnirea unui operator se preiau i se ndeprteaz din stiv ultimele dou valori iar rezultatul obinut prin aplicarea operatorului la cele dou valori se insereaz n stiv. Dup parcurgerea tuturor cuvintelor, n stiv ar trebui s se gseasc un singur element reprezentnd rezultatul expresiei. Aplicaia de realizat trebuie s afieze rezultatul unei expresii aritmetice postfixate (reprezentat sub forma unui ir de caractere). De asemenea va fi semnalizat o expresie greit.

46

9. Coada
1.Obiective
Familiarizarea cu tipul de dat abstract coad; Implementarea TDA coad prin vectori circulari; Implementarea unui simulator al serviciilor medicale oferite de un doctor de familie.

2.Aspecte teoretice
Coada este o structur special, care restricioneaz accesul la elementele sale astfel: Adugarea elementelor este permis numai la sfritul structurii tergerea este permis numai de la nceputul ei. O coad este caracterizat de expresia First In First Out (FIFO) Primul Venit Primul Servit. Cele mai uzuale implementri ale cozii sunt cu ajutorul: listelor simple nlnuite vectorilor circulari. n laboratorul de fa va fi abordat cea de-a doua implementare. Vectorii circulari se difereniaz de vectorii liniari prin faptul c, dup ocuparea tuturor celor NMAX poziii din vector, se continu cu ocuparea poziiilor de la nceputul vectorului ( 0, 1, etc.). Acest lucru este posibil numai n cazul TDA coad la care, ntre timp, au fost eliminate elemente de la nceputul vectorului. Utilizarea vectorilor circulari permite refolosirea zonei de memorie eliberat de elementele ce prsesc coada. Pentru a reprezenta TDA coad prin vectori circulari avem nevoie de o structur special, care s conin pe lng vectorul corespunztor cozii: doi indicatori ce vor specifica nceputului i sfritului cozii. F nceputul cozii (engl. Front) R sfritul cozii (engl. Rear) si o variabil rotire care este necesar pentru a diferenia cele 2 situaii cnd indicatorii F i R sunt egali (dac F = R i rotire = FALS, coada este vid; dac F = R i rotire = ADEVRAT, coada este plin).
struct coada{ unsigned F,R; unsigned char rotire; DATA v[NMAX]; };

Principalele operaii efectuate asupra acestei structuri de date se realizeaz prin intermediul metodelor: openq() iniializare coad; add(q,e) adugarea elementului e n coada q; rem(q) ndeprteaz din coada q primul element; front(q) returneaz valoarea primului element din coada q; isemptyq(q) returneaz ADEVRAT cnd coada este vid; isfullq(q) returneaz ADEVRAT cnd coada este plin; destroyq(q) elibereaz spaiul alocat cozii.

47

3. Tem de realizat n timpul laboratorului


Cele mai importante aplicaii ale structurii de tip coad sunt reprezentate de simularea unor situaii de ateptare reale. Vom considera un simulator ce modeleaz serviciile medicale oferite de un doctor de familie. Acesta sosete la ora 9 i dorete s termine programul la ora 13, deoarece n a doua jumtate a zilei cabinetul este ocupat de un coleg de-al su. n acest scop se realizeaz o simulare pe calculator a situaiei existente pentru a determina ora la care trebuie primit ultimul pacient astfel nct cabinetul s fie liber la ora 13 (se accept o eroare de 10 minute). Vom presupune c fiecare pacient cere un singur serviciu din urmtoarele tipuri: adeverin (scutire, concediu medical etc.) 5 min. consultaie (implic consultarea pacientului i scrierea unui bilet de trimitere la diverse cabinete de analize medicale) 10 min. tratament (se consider c pacientul are analizele efectuate i pe baza lor doctorul scrie tratamentul corespunztor) 7 min. Se consider c a sosit un nou pacient dac a trecut un anume interval de timp de la sosirea pacientului anterior. Acest interval este o valoare aleatoare ntre 0 si T_MAX (T_MAX = 20). Pacientul sosit va fi adugat n coad cu un tip de serviciu generat aleator numai dac timpul total de servire al pacienilor din coada nu depete durata maxim de edere a doctorului. Trecerea timpului va fi simulat de un contor ce va lua valori de la 0 la valoarea duratei totale de simulare (exp.: 4 ore n cazul de fa). La fiecare cuant de timp (1 min.) se vor efectua urmtoarele operaii: se verific dac nu a sosit un pacient. dac a sosit i timpul necesar servirii pacienilor nu depete durata total de simulare, se introduce n coad i se actualizeaz timpul necesar servirii pacienilor. Obs.: pentru fiecare pacient se va memora n coad momentul sosirii i tipul serviciului cerut de acesta. se actualizeaz situaia doctorului: Dac este liber i sunt pacieni pe sal, primul dintre ei este eliminat din coad i se ncepe servirea lui. Dac este un pacient n cabinet se scade o unitate din timpul necesar serviciului cerut de acesta. Dac timpul de servire devine 0, doctorul trece n starea LIBER. Aplicaia va simula trecerea timpului printr-o structur repetitiv i la fiecare cuant de timp ( 1 min) se vor efectua operaiile corespunztoare descrierii problemei, utiliznd metodele specifice TDA Coad. De asemenea, metodele corespunztoare TDA Coad care nu sunt implementate n fiierele puse la dispoziie vor fi programate n cadrul laboratorului. La final aplicaia va genera urmtoarele rezultate: un fiier text, cu antetul prezentat mai jos, n care trebuie nregistrai pacienii din ziua respectiv: Nr_ordine Timp_sosire Tip_serviciu Moment_servire pe ecran se va afia momentul n care pacienii nu au mai fost primii n sala de ateptare.

48

4. Fiiere puse la dispoziie


Pentru realizarea aplicaiei propuse la acest laborator se vor utiliza urmtoarele fiiere: data.h fiier header ce conine definiia tipului de informaie din TDA coada; coada.h - fiier header ce conine prototipurile funciilor specifice TDA coada; coada.c - fiier surs C care conine implementarea funciilor corespunztoare TDA coad realizat cu vectori circulari.
//-------------------------------------------------------// F i s i e r u l d a t a . h // (c)PSG2002 //-------------------------------------------------------#ifndef _DATA_H_ #define _DATA_H_ #define FALS 0 #define ADEVARAT !FALS typedef unsigned char LOGIC; //----------------------------------------// Rezervat modificarilor utilizatorului care va preciza tipul // informatiei din elementele TDA //----------------------------------------// typedef int DATA; #define FORMAT "%d" #define ABSENT 0 #endif //-------------------------------------------------------// F i s i e r u l c o a d a . h // (c)PSG2002, FG2005 //-------------------------------------------------------#ifndef __COADA_H_ #define __COADA_H_ #include "data.h" #define NMAX 10 struct coada{ unsigned F,R; LOGIC rotire; DATA pacienti[NMAX][2]; }; typedef struct coada *QUEUE; QUEUE newq(void); LOGIC add(QUEUE,DATA,DATA); LOGIC rem(QUEUE); LOGIC front(QUEUE,DATA*,DATA *); LOGIC isemptyq(QUEUE); LOGIC isfullq(QUEUE); char * toString(QUEUE,char *); void destroyq(QUEUE); #endif

49

//-------------------------------------------------------// F i s i e r u l c o a d a . c // (c)PSG2002, FG2005 //-------------------------------------------------------#include #include #include #include <stdio.h> <stdlib.h> <string.h> "coada.h"

//--------------------------------------------------------QUEUE newq(void){ QUEUE q; if((q=(QUEUE)malloc(sizeof(struct coada)))==NULL) printf("\n alocare imposibila"); else{ q->F = q->R = 0; q->rotire = FALS; } return q; } //--------------------------------------------------------LOGIC isfullq(QUEUE q){ return (q->F == q->R && q->rotire == ADEVARAT); } //--------------------------------------------------------LOGIC add(QUEUE q, DATA timp_sos, DATA tip_serv){ if ( isfullq(q) ) return FALS; q->pacienti[q->R][0] = timp_sos; q->pacienti[q->R][1] = tip_serv; if( ++ q->R == NMAX){ q->R = 0; q->rotire = ADEVARAT; } return ADEVARAT; }

50

10. Mulimi
1.Obiective
Familiarizarea cu structura de dat mulime reprezentat prin vectori caracteristici; Prezentarea tehnicilor utilizate la implementarea TDA mulime prin vectori de bii; Implementarea/testarea principalelor operaii cu mulimi.

2.Aspecte teoretice
Structura de date mulime cunoate mai multe implementri, cele mai utilizate fiind prin liste respectiv prin vectori de bii. A doua implementare este posibil doar n cazul modelrii n prealabil a mulimilor prin vectori caracteristici. Fie U un univers, E un vector care asociaz bijectiv fiecrui element din U un numr cuprins ntre 0 i |U|-1 numit poziia elementului i mulimea A inclus n U. Vectorul caracteristic al mulimii A n raport cu universul U are dimensiunea |U| i se noteaz cu CA. Dac elementul E[i] din U aparine mulimii A atunci CA[i] are valoarea 1 altfel valoarea 0. Pentru cazul general, este nevoie s fie stocat i vectorul E care s ofere o poziie fiecrui element din universul U. Dac ns universul U conine doar numerele ntregi din intervalul [0,n-1] atunci nu mai este necesar o structur suplimentar, valorile elementelor fiind chiar indicii din vectorii caracteristici.Considerm de exemplu: U = {0,1,2,3,4,5,6,7,8,9,10,11}; A = {2,5,9}; B = {0,4,8,9,11} Vectorii caracteristici ai celor dou mulimi sunt: CA CB
indici

0 1
0

0 0
1

1 0
2

0 0
3

0 1
4

1 0
5

0 0
6

0 0
7

0 1
8

1 1
9

0 0
10

0 1
11

Datorit faptului c valorile pe care le poate lua un element oarecare al unui vector caracteristic fac parte strict din mulimea {0,1} este posibil o important economie de memorie prin reprezentarea fiecrui element din vector prin cte un bit. Vectorii caracteristici din exemplul anterior au nevoie de cte doi octei pentru a putea fi memorai. CA CB
indici

0 0
7

0 0
6

1 0
5

0 1
4

0 0
3

1 0
2

0 0
1

0 1
0 15 14 13 12

0 1

0 0

1 1

0 1

primul octet

11 10 9 8 al doilea octet

Numrul de octei necesar a fi alocai este (|U|+7)/8; Pentru simplitatea n programare n cadrul unui octet numerotarea este inversat; Indicele x se afl n octetul x/8 la distana x%8 de captul din dreapta; poziionarea n cadrul octetului se realizeaz cu o masc obinut din 1 deplasat la stnga cu x%8.
51

3.Exemple
Sunt puse la dispoziie urmtoarele fiiere: data.h fiier header pentru implementarea tipului DATA; multime.h - fiier header pentru implementarea TDA mulime; multime.c fiier surs C cu implementarea funciilor corespunztoare TDA mulime; main.c - fiier surs C cu implementarea unui meniu ce testeaz operaiile specifice.

4. Tem de realizat n timpul laboratorului


1. S se studieze fiierele surs puse la dispoziie i s se implementeze funciile corespunztoare pentru opiunile nefuncionale: S intersecia mulimilor A, B T diferena mulimilor A, B Prototipul celor dou funcii se afl n fiierul multime.h. Este necesar definirea funciilor (n fiierul mulime.c) i apelarea corespunztoare (n fiierul main.c). 2. S se extind aplicaia pentru a permite trei opiuni suplimentare: E testarea egalitii mulimilor A, B C complementara mulimii A V verificarea relaiei lui de Morgan n forma C(AB) = C(A) U C(B) Este necesar declararea i definirea unei funcii care s testeze egalitatea dintre dou mulimi precum i definirea funciei de complementare a unei mulimi.
//-------------------------------------------------------// F i s i e r u l m u l t i m e . h //-------------------------------------------------------#ifndef _MULTIMI_H_ #define _MULTIMI_H_ #include "data.h" // proprietati TDA struct multime{ int n; // numarul de elemente char *pv; // pointerul zonei de octeti }; typedef struct multime Multime,*MULTIME; // metode (operatii) TDA MULTIME newSet(int n); MULTIME insert(MULTIME e, DATA x); MULTIME Delete(MULTIME e, DATA x); LOGIC member(MULTIME e, DATA x); int cardinal(MULTIME e); MULTIME Union(MULTIME A, MULTIME B); MULTIME intersect(MULTIME A, MULTIME B); MULTIME diff(MULTIME A, MULTIME B); MULTIME complementara(MULTIME A); char *conv_multime_sir(MULTIME e, char *zona); LOGIC isEmptySet(MULTIME e); LOGIC isUniverse(MULTIME e); void destroySet(MULTIME e); #endif
52

//-------------------------------------------------------// F i s i e r u l m u l t i m e . c //-------------------------------------------------------#include <stdio.h> #include <stdlib.h> #include <string.h> #include "multime.h" MULTIME newSet(int n) { //alocarea spaiului necesar informatiilor despre multime MULTIME e=(MULTIME) malloc(sizeof(Multime)); if (e!=NULL) {//daca alocarea a avut succes char *q; // se aloca spatiul pentru vectorul caracteristic q=(char *) malloc((n+7)/8); // daca alocarea nu poate fi realizata if (q==NULL) { free (e); // se elibereaza spatiul deja alocat return NULL; // multimea nu poate fi initializata } // se completeaza campurile corespunzatoare e->n = n; e->pv = q; // se initializeaza vectorul caracteristic cu 0 for(n=(n+7)/8 -1;n>=0;n--) q[n]=0; } return e; } MULTIME insert(MULTIME e, DATA x) { int ix=(int)x; // conversia de la tipul DATA la tipul int if (ix>=0 && ix<e->n) // testarea nedepasirii limitelor // setarea bitului ix din vect. caracteristic la valoarea 1 // prin operatia de SAU pe biti intre octetul ix/8 // si o masca ce contine 1 doar pe pozitia ix%8 // considerata de la dreapta spre stanga e->pv[ix/8] |= 1<< ix%8; return e; } LOGIC member(MULTIME e, DATA x) { // conversia de la tipul DATA la tipul int int ix=(int)x; // testarea nedepasirii limitelor if (ix>=0 && ix<e->n) // daca bitul ix din vectorul caracteristic are valoarea 1 // expresia de mai jos returneaza o valoare diferita de 0 // altfel returneaza valoarea 0 return e->pv[ix/8] & 1 << ix%8; // in caz de depasire a limitelor corespunzatoare // elementul x nu apartine multimii return FALS; }
53

MULTIME Delete(MULTIME e, DATA x) { int ix=(int)x; e->pv[ix/8] &= ~( 1 << ix%8 ); return e; } int cardinal(MULTIME e) { return e->n; } MULTIME Union(MULTIME A,MULTIME B) { MULTIME R; int i; if(A==NULL || B==NULL) { printf("\nErr: cel putin o multime este neinitiaizata."); return NULL; } if(A->n != B->n) { printf("\nEroare: universuri de cardinali diferiti"); return NULL; } if((R=newMultime(A->n))==NULL) return NULL; for(i=0;i<(A->n+7)/8;i++) R->pv[i] = A->pv[i] | B->pv[i]; return R; } void destroySet(MULTIME e) { if(e!=NULL) { free(e->pv); free(e); } } LOGIC isEmptySet(MULTIME e) { int i; for(i=0;i<(e->n+7)/8;i++) if(e->pv[i] !=0) return FALS; return ADEVARAT; } char *conv_multime_sir(MULTIME e, char *zona) { int i,j; char oct; if(e==NULL) return "Multime neintializata"; if(isEmptySet(e)) return "vida"; else { strcpy(zona,"{"); for(i=0;i<(e->n+7)/8;i++) { oct=e->pv[i]; for(j=0;j<8;j++) { if((oct & 1)!=0) sprintf(zona+strlen(zona), FORMAT",",i*8+j); oct>>=1; } } sprintf(zona+strlen(zona)-1,"}"); return zona; } }
54

//-------------------------------------------------------// F i s i e r u l m a i n . c //-------------------------------------------------------#include <stdio.h> #include <conio.h> #include <ctype.h> #include <process.h> #include "multime.h" #define INSERT 0 #define DELETE 1 char menu(void); void operatie(MULTIME a, char *denMultime, int tipOperatie); void main() { int n; char zona[200]; MULTIME a=NULL,b=NULL,r=NULL; printf("\nNr. maxim de elemente:"); scanf("%d",&n); while(1){ switch(menu()){ case 'A': if(a!=NULL) destroySet(a); a=newMultime(n); break; case 'B': if(b!=NULL) destroySet(b); b=newMultime(n); break; case 'I': operatie(a, "A", INSERT); break; case 'J': operatie(b, "B", INSERT); break; case 'D': operatie(a, "A", DELETE); break; case 'F': operatie(b, "B", DELETE); break; case 'G': printf("\nA=%s",conv_multime_sir(a,zona)); break; case 'H': printf("\nB=%s",conv_multime_sir(b,zona)); break; case 'R': printf("\nA U B=%s", conv_multime_sir( r=Union(a,b) , zona)); destroySet(r); break; case 'X': destroySet(a); destroySet(b); return; default:printf("\n Optiune inexistenta"); } } }

55

char menu() { printf("\n A-Initializare multime A "); printf("\n B-Initializare multima B "); printf("\n I-Inserare A "); printf("\n J-Inserare B "); printf("\n D-Delete A "); printf("\n F-Delete B "); printf("\n G-Afiseaza A "); printf("\n H-Afiseaza B "); printf("\n R-Afiseaza A U B "); printf("\n S-Afiseaza A intersectat B "); printf("\n T-Afiseaza A \\ B "); printf("\n X-Exit "); printf("\n"); printf("\n Introduceti optiunea: "); return toupper(getche()); } // ----------------------------------------------------------------// Procedura operatie este scrisa pentru acest program demo // fiind si o ilustrare a utilizarii tablourilor de pointeri // la functii. Procedura are urmatoarele argumente: // e - multimea cu care se va executa operatia (insert / delete) // denMultime - numele multimii (necesar pt. ev. mesaje de err.) // tipOperatie - tipul operatiei (0 = insert, 1 = delete) // Procedura citeste de la tastatura elementul de inserat/sters. // In cazul operatiei delete verifica apartenenta elementului. // ----------------------------------------------------------------void operatie(MULTIME e, char *denMultime, int tipOperatie) { char *denOperatii[]={"inserat","eliminat"}; MULTIME (*operatii[])(MULTIME e, DATA k)={insert,Delete}; DATA x; if(e!=NULL){ printf("\nElementul de %s in %s:", denOperatii[tipOperatie], denMultime); scanf(FORMAT,&x); if(x<0 || x>= cardinal(e)) printf("\nElementul "FORMAT" nu poate apartine lui %s:", x, denMultime); else if (tipOperatie==DELETE && !member(e,x)) printf("\nElementul "FORMAT" nu apartine lui %s:", x, denMultime); else e=operatii[tipOperatie](e,x); } else printf("\nNu ati initializat multimea %s:",denMultime); }

56

11. Arbori
1.Obiectiv
Familiarizarea cu tipul de data abstract Arbore nsuirea lucrului cu TDA Arbore; Parcurgerea arborilor binari Evaluarea expresiilor aritmetice

2.Aspecte teoretice
Un arbore este o structur de date ierarhizat n care elementele structurii, numite noduri, sunt legate ntre ele prin relaii de tip tata-fiu. Nodul fr nici un predecesor(tat) este numit rdcin, iar nodul care nu are nici un succesor(fiu) este numit frunz. Gradul unui nod este numrul de fii pe care i are acel nod. Nodurile care au grad zero se numesc noduri frunz sau noduri terminale. Gradul unui arbore este valoarea maxim a gradelor nodurilor sale, sau, cu atte cuvinte, gradul unui arbore este egal cu numrul maxim de fii pe care i are un nod. Un arbore binar este un arbore care are gradul 2. Exemplu. n figura 1, arborele binar reprezint expresia aritmetic (a+1)*(b-(a+c)*2).

Figura1. Reprezentarea unei expresii aritmetice prin arbore binar Traversarea unui arbore reprezint o metod de examinare sistematic a nodurilor unui arbore, astfel nct fiecare nod s fie vizitat o singur dat i s nu rmn niciun nod nevizitat. Se remarc patru strategii de traversare a unui arbore. n cazul arborilor binari, se utilizeaz o serie de prescurtri ale acestora, astfel: Preordine RSD (Rdcin, Stnga, Dreapta) se viziteaz Rdcina, apoi subarborele stng, dup care cel drept; la vizitarea fiecrui subarbore se aplic din nou aceeai regul de vizitare, ncepnd cu Rdcina sa. Inordine SRD (Stnga, Rdcin, Dreapta) - se viziteaz subarborele stng, apoi Rdcina, dup care subarborele drept. Postordine SDR (Stnga, Dreapta, ,Rdcin) - se viziteaz subarborele stng, apoi cel drept i la final Rdcina.
57

3.Teme de realizat n timpul laboratorului


1. Se considera o aplicatie demonstrativ de utilizare a arborilor binari. Sa se implementeze urmatorul meniu:
C R S D H I X constructie arbore afisare in format RSD (Radacina Stanga Dreapta) afisare in format SRD (Stanga Radacina Dreapta) afisare in format SDR (Stanga Dreapta Radacina) afisarea inaltimii arborelui info autor iesire din program (si eliberare memorie arbore)

Observatii: arborele se va reprezenta prin legaturi catre descendentii stanga si dreapta; informatia utila va fi de tip DATA (char); caracterul . (punct) indica absenta descendentului utilizarea comentariilor este obligatorie. 2. Exista numeroase aplicatii ale TDA arbore. Interesant se dovedeste a fi cazul in care arborele reprezinta o expresie aritmetica. Nodurile frunza constituie operanzii iar celelalte noduri constituie operatorii. Fiecare parcurgere prezentata anterior genereaza cate o modalitate de exprimare a expresiilor aritmetice: SRD forma infixata (forma clasica in care operatorii ocupa o pozitie centrala); RSD forma prefixata (operatorii preced operanzii); SDR forma postfixata (operatorii se afla dupa (post) operanzi). In contextul arborilor ce reprezinta expresii aritmetice sa se realizeze: modificarea optiunii S astfel incat expresia sa fie afisata cu paranteze adaugarea optiunii E evaluarea expresiei reprezentata de arborele binar (si afisarea rezultatului)

4. Fiiere puse la dispoziie


Pentru realizarea aplicaiei propuse la acest laborator se vor utiliza urmtoarele fiiere: data.h - pentru informaia utila; arbori.h - pentru definiiile si prototipurile specifice tipului arbore; arbori.cpp - pentru definiiile funciilor specifice tipului arbore; demo.cpp - pentru implementarea meniului prezentat anterior;

58

//-------------------------------------------------------// F i s i e r u l d a t a . h // (c)PSG2002 //-------------------------------------------------------#ifndef _DATA_H_ #define _DATA_H_ typedef unsigned char DATA; #define FORMAT "%c" #endif

//-------------------------------------------------------// F i s i e r u l a r b o r i . c // (c)PSG2002 //-------------------------------------------------------#include <stdio.h> #include <alloc.h> #include <conio.h> #include "arbori.h" #define max(a,b) ((a>b)?a:b) #define frunza(x) ((x->stg==NULL) && (x->dr == NULL)) #define prior(x) (x == '*' || x == '/') ARB creare_arbore (DATA x){ ARB a; if(x == '.') return NULL; a = (ARB)malloc(sizeof(Arbore)); if(a== NULL){ printf("\n Eroare la alocare"); return NULL; } a->nod = x; printf("\n Dati nodul stang pentru %c : ",x); a->stg = creare_arbore(getche()); printf("\n Dati nodul drept pentru %c : ",x); a->dr = creare_arbore(getche()); return a; }

59

//-------------------------------------------------------// F i s i e r u l a r b o r i . h // (c)PSG2002 //-------------------------------------------------------#ifndef _ARBORI_H_ #define _ARBORI_H_ #include "data.h" typedef struct arbore{ DATA nod; struct arbore *stg, *dr; } Arbore, *ARB; ARB creare_arbore (DATA ); void SRD(ARB ,DATA ); void RSD(ARB ); void SDR(ARB ); int inaltime(ARB ); int eval(ARB a); #endif

5. Teme pentru studiu individual


1. Sa se modifice optiunea S astfel incat sa se afiseze doar parantezele necesare 2. Sa se realizeze parcurgerea in latime (L) a arborelui utilizand TDA coada (implementata prin vectori circulari intr-un laborator anterior)

60

12. Metoda Greedy


1.Obiectiv
Aprofundarea metodei Greedy

2.Aspecte teoretice
Metoda Greedy se folosete n general n situaia n care este dat o mulime A i se cere s se gseasc o submulime B a sa care s ndeplineasc anumite condiii sau un anumit criteriu de optim. Aceast metod nu i propune gsirea celor mai bune soluii ale problemei date ci doar a uneia dintre ele care ndeplinete criteriul de optimizare ales. Mecanismul general al metodei Greedy este urmtorul: 1. se iniializeaz mulimea soluiilor cu mulimea vid (B=) 2. se alege un element x din mulimea A 3. se verific dac elementul ales poate fi adugat la mulimea soluiilor , dac da atunci va fi adugat: B=B{x} 4. se continu repetitiv cu pasul 2 pn cnd au fost determinate toate elementele din mulimea soluiilor Exist dou variante de proceduri pemtru metoda Greedy[1]:
procedura Greedy_1 (A, n, B) este B= pentru i=1,n executa x = ALEGE(A,n,i) daca POSIBIL(B,x) atunci ADAUG(B,X) @ @ sfarsit procedura Greedy_2 (A, n, B) este PREL(A,n) B= pentru i=1,n executa daca POSIBIL(B,ai) atunci ADAUG(B,ai) @ @ sfarsit

Unde: POSIBIL(B,x) este o funcie boolean care ntoarce adevrat dac B{x} poate fi soluie a problemei ADAUG(B,x) adaug elementul x la mulimea B PREL(A,n) prelucreaz mulimea A funcie de natura problemei ce se dorete rezolvat

Problem. Se cere sa se gaseasca o dispunere optim a n fiiere cu lungimile L1, L2, ... , Ln pe o band magnetic n ipoteza c timpul de citire al unui fiier este proporional cu lungimea sa, iar pe band citirea fiierului k implic i citirea celor k-1 fiiere precedente. Presupunem o distribuie uniform a frecvenelor de citire a fiierelor.

61

Aranjarea optim a fiierelor pe o band magnetic nseamn obinerea unui timp mediu de citire minim. Structura fiierelor pe band: nume informatii EOF fis.1 fis1 nume informatii EOF fis.2 fis2 ..... .....

Date de intrare L - lungimea benzii magnetice n - numrul de fiiere ce trebuie aranjate Nume_Fiier_1 - un ir de caractere ce conine numele primului fiier Dimensiune_Fiier_1 - lungimea n octei a informaiilor coninute n Fiier1 Nume_Fiier_2 Dimensiune_Fiier_2 ... ... Nume_Fiier_n Dimensiune_Fiier_n Date de ieire: Varianta 1: irul (N1 L1) (N2 L2) ... (Nm Lm), unde cuplul (Ni Li) reprezint numele i dimensiunea fiierului i. Varianta 2: Permutarea p=(p1, p2, ... , pn), a lui (1,2,...,n) pentru care se obine minimul timpului mediu de citire, elementele pi reprezentnd numerele de ordine ale fiierelor din introducerea datelor. Soluie propus Se poate demonstra [1] c soluia optim se obine atunci cnd fiierele sunt sortate n ordinea cresctoare a lungimii lor (lungime nume fiier + lungime informaie). Se va folosi funcia Greedy_2 cu urmtoarele observaii 1. funcia PREL(A, n) va crea un vector V (cu Vi=Lungime_nume_fiier_i + Lungime_informaie_i) i va sorta cresctor vectorul V 2. funcia POSIBIL(B,ai) va determina dac lungimea bandei magnetice nu este depit (Bi + ai L)

3.Tem de realizat n timpul laboratorului


1. Implementai metoda Greedy avnd n vedere formatul de intrare propus anterior precum i prima variant pentru datele de ieire. Meniul afiat de program va fi: C - Citire date de la tastatur F - Citirea datelor dintr-un fiier al crui nume este dat de la tastatur S - Sortarea datelor i afiarea lor dup modelul: Nume fiier, Lungime fiier G - Aplicarea algoritmului Greedy i afiarea rezultatelor dup modelul propus. I - Informaii autor E - Ieire program Se va afia mesajul Fr soluie atunci cnd nici un fiier nu poate fi scris pe banda magnetic.
62

4. Tem pentru studiu individual


Implementai metoda Greedy i afiai datele folosind cel de-al doilea format de ieire. Pentru sortarea datelor se va folosi funcia qsort oferit de mediul de programare Borland C i care are prototipul:
void qsort( void *base, size_t nelem, size_t width, int (*fcmp)(const void *, const void *));

Unde:

base - este adresa vectorului de sortat nelem - numrul de elemente din vector width - lungimea n octei (sizeof) al fiecrui element din vector fcmp - o funcie utilizator ce compar dou elemente ale vectorului

Exemple de utilizare ale funciei qsort: 1. Sortarea cresctoare a unui vector de numere intregi: 2.
#include <stdio.h> #include <stdlib.h> #include <string.h> int sortare_crescatoare(const void *a, const void *b) { return (*(int *)a - *(int *)b); } int v[] = {3,1,5,4,2}; int main(void) { int i; qsort((void*)v,sizeof(v)/sizeof(v[0]),sizeof(v[0]),sortare_crescatoare); for (i = 0; i < 5; i++) printf("%d\n", v[i]); return 0; }

63

2. Sortarea unui masiv de structuri:


#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Student{ char Nume[10]; int Nota; } *STUDENT; int sortare_descrescatoare(const void *a, const void *b) { return ( ((STUDENT)b)->Nota - ((STUDENT)a)->Nota); } Student s[] = {{"Marcel",9},{"George",5},{"Mihaela",8}}; int main(void) { int i; qsort((void*)s,sizeof(s)/sizeof(s[0]),sizeof(s[0]),sortare_descrescatoare); for (i = 0; i < 3; i++) printf("\nNume:%s Nota:%d",s[i].Nume, s[i].Nota); return 0; }

64

13. Backtracking recursiv


1.Obiectiv
Aprofundarea metodei de cutare cu revenire

2.Aspecte teoretice
Problem. ntre insulele unui arhipelag se afl n poduri. Un turist i propune s viziteze aceste poduri, o singur dat, pornind de la o anumit insul. S se afieze toate posibilitile de parcurgere a celor n poduri. Rezolvare Se pornete analiza problemei prin identificarea celor mai potrivite structuri de date care s modeleze coninutul problemei. Date de intrare n - numrul de poduri ins_start insula de la care se pornete pod[n] un vector de structuri de dimensiune n, care descrie fiecare pod i are ca membri dou numere ntregi reprezentnd cele dou insule (ins1, ins2), pe care le leag. Date de ieire irul x1, x2, ...xn, fiecare element xi reprezentnd indicele unui pod [0,n-1]. Procedura propus pentru rezolvarea problemei Pentru a mri viteza de execuie a procedurii recursive, se va considera c variabila n i tablourile x[] i pod[] sunt globale. La fiecare pas se testeaz dac podul i , cu i=0,n-1 , se poate concatena soluiei pariale determinate pn n acel moment.
procedura Plimbare(insula_crt, k) este daca n==k atunci *) scrie x[0],...,x[n-1] altfel pentru i=0,n-1 execut daca POSIBIL(i,k,insula_crt) atunci x[k]=i daca insula_crt==pod[i].ins1 atunci ins=pod[i].ins2 altfel ins=pod[i].ins1 @ Plimbare (ins, k+1) @ @ @ sfarsit

65

Dup ce se include la pasul k un pod n soluia parial, se determin noua ins_crt pentru pasul urmtor (acel capt al podului ales la pasul k ce nu se afl pe vechea ins_crt). Predicatele de extindere a soluiei la pasul k:
POSIBIL (alfa, k, ins_crt)

Vor verifica dac: - podul alfa nu a fost vizitat (alfa != x[i] pentru i=0,k-1) - insula curent este una din extremitile podului alfa (pod[alfa].ins1 == ins_crt
sau pod[alfa].ins2 == ins_crt ) functie POSIBIL (alfa, k, ins_crt) este pentru j=0,k-1 executa daca x[j] == alfa atunci intoarce FALS @ @ intoarce pod[alfa].ins1 == ins_crt sau pod[alfa].ins2 == ins_crt

n programul principal rezolvarea problemei va fi declanat prin apelul:


execut Plimbare (ins_start, 0)

3. Teme de realizat n timpul laboratorului


n timpul lucrrii de laborator vei programa rezolvarea acestei probleme conform algoritmului prezentat sau al unui alt algoritm la alegerea dumneavoastr. Vei lua n considerare faptul c datele de intrare vor fi preluate dintr-un fiier text cu n+2 nregistrri, avnd urmtorul format:
n ins_start ins_11 ins_12 ins_21 ins_22 ... ins_n1 ins_n2

Observaie. Toate valorile din fiier sunt ntregi. 1. Facei ca programul s afieze mesajul fr soluie, dac nu este posibil gsirea unei soluii n condiiile cerute. 2. Rescriei programul astfel nct s determine insula de pe care turistul s plece i s revin pe aceeai insul dup ce a parcurs toate podurile o singur dat.

66

4. Teme pentru studiu individual


Vei rezolva cel puin 2 probleme indicate de cadrul didactic. 1. La o Mas rotund privind Creterea rolului ntreprinderilor n finanarea nvmntului superior au fost invitate s trimit cte un reprezentant n firme. Este cunoscut faptul c fiecare firm invitat are una sau mai multe firme concurente printre celelalte invitate. Scriei un program care s aeze participanii la o masa rotund astfel nct reprezentanii a dou firme concurente s nu stea alturi. 2. ntre n orae exista o reea de osele care unesc dou orae ntre ele. S se determine toate posibilitile de alegere a oselelor, astfel nct sa se ajung din oraul s n oraul d. 3. Un student la filologie poseda n dicionare bilingve care permit traducerea dintr-o limba i intr-o limba j cu 1<=i, j<=n. Sa se determine toate seturile de dicionare care i permit studentului s realizeze o traducere ntre limba s i limba d. 4. Pe un deal, ntr-un punct oarecare, se afl o minge. S se determine toate drumurile pe care poate cobor mingea astfel nct s ajung la poalele dealului. 5. Sa se acopere un hol de lungime L cu un numr minim de buci de mochete de lungime li existente n depozit. 6. Se consider un labirint descris cu ajutorul unui tablou bidimensional. S se redacteze programul care determin toate drumurile de ieire din labirint. 7. ntr-un grup de persoane, fiecare persoana se cunoate pe sine si cunoate eventual alte persoane din grup. Sa se formeze si sa se afieze toate echipele posibile de persoane astfel nct, pentru o echip, fiecare din cele n persoane sa fie cunoscut de cel puin un membru al acelei echipe. 8. Sa se realizeze parcurgerea tabelei de ah de ctre un cal care pleac dintr-o poziie oarecare, astfel nct sa parcurg fiecare cmp al tablei o singura dat, mai puin cmpul de coordonate (i,j). 9. Un dresor trebuie sa scoat m lei si n tigri din arena, astfel nct sa nu scoat doi tigri unul dup altul. Sa se genereze toate posibilitile de niruire a leilor si tigrilor. 10. O caravan format din n cmile cltorete prin deert, n ir indian. Pentru a sparge monotonia zilelor lungi de drum, beduinul sef se hotrte sa schimbe aezarea cmilelor, astfel nct fiecare cmil sa nu mai vad in fata ei aceeai cmila de pn atunci. Sa se genereze toate posibilitile de aezare a cmilelor, cunoscnd modul de aezare din prima zi. 11. Un soldat trebuie sa parcurg un teren minat pentru a ajunge in propriile linii. Sa se genereze toate drumurile posibile prin care soldatul ajunge nevtmat la camarazii si.

67

12. Fie n persoane, n locuri de munca si C(i,j) salariul pretins de persoana i dac este angajat la locul de munca j. Sa se determine modul optim de angajare a tuturor persoanelor.
13. Dintr-un grup de n persoane, dintre care p femei, trebuie format o delegaie de k persoane din care l femei. S se precizeze toate delegaiile care se vor forma. 14. Se consider un labirint de form dreptunghiular avnd perei verticali i orizontali. S se gseasc drumul cel mai scurt dintre dou puncte date. 15. Fiind dat un carosaj dreptunghiular cu m linii i n coloane, n care anumite poziii sunt ocupate (interzise), se cere s se determine toate poziiile n care poate ajunge un mobil ce pleac din punctul iniial (i0, j0), tiind c el se poate deplasa doar astfel: cu o poziie la dreapta pe aceiai linie; cu o poziie la stnga pe aceiai coloan; cu o poziie n sus pe aceiai coloan. 16. Care este numrul minim de regi care pot fi aezai pe o tabl de ah, astfel nct s in sub ameninare toate ptratele neocupate de figuri ? 17. Care este numrul maxim de cai care pot fi aezai pe tabla de ah cu n2 ptrate, astfel nct s nu se amenine? 18. Problema bilei. Un teren este reprezentat sub forma unei matrice cu n linii i n coloane. Elementele (i, j) ce aparin mulimii numerelor reale reprezint cotele diferitelor poriuni din acest teren. Se presupune c o bil se gsete pe o poriune avnd o anumit cot. Se cere s se precizeze toate traseele posibile de a fi urmate de bil spre a iei din teren nvecinat cu o cot strict inferioar cotei terenului pe care se gsete bila. 19. Se consider o mulime format din n persoane, n care fiecare se cunoate pe sine i eventual, alte persoane. S se afieze grupurile care se pot forma cu aceste persoane, fiecare persoan din grup trebuind s cunoasc toate celelalte persoane ale grupului. Relaia persoana i cunoate persoana j este dat printr-o matrice

(C ) i, j = T
ij

1n

n care:

1, dac persoana i cunoa te persoana j C ij = 0, n caz contrar


Observaii: relaia nu este n mod normal simetric i nici tranzitiv, deci Cij=Cji n anumite cazuri, iar din Cij =1 i Cjk =1 nu rezult Cik =1 o persoan nu poate aparine dect unui singur grup. 20. Se consider n fete care urmeaz s se cstoreasc ntr-un mod optim cu n biei. Fetele i bieii i exprim preferinele unul fa de altul prin numere reale din intervalul [0, 1]. Preferina fetei i pentru biatul j este dat de fb[i, j], iar preferina biatului i pentru fata j este dat de bf[i, j]; elementele matricilor fb i bf sunt numere [ ] [ ] reale din intervalul [0, 1]. Biatul ales de fata i are numrul x[i]. Bineneles, vectorul x va fi un vector de [] permutare. Costul cstoriei fetei i cu biatul x[i] este fb [i, x[i]] bf[x [i], i], iar costul general (care trebuie [] [] [ ] ] maximizat) este suma dup i a acestor valori. Mai mult, se cere ca cele n cstorii cu ij astfel nct fata i s prefere biatul x[j] biatului x[i], iar biatul x[j] s prefere fata i fetei j. [] [] [] (G. M. 7-8 /1993)

68

14. Backtracking iterativ


1.Obiectiv
Aprofundarea metodei de cautare cu revenire

2.Aspecte teoretice
Exista doua variante de proceduri care realizeaza metoda cautarii cu revenire. Una dintre ele este cea recursiva, prezentata in laboratorul anterior. Cea de-a doua procedura este iterativa si va fi prezentata in laboratorul de fata. Problema: Daca doreste sa imprumute bani de la prietena sa, Radu trebuie sa ii faca cel putin un cadou. Ea nu face niciodata mai multe imprumuturi decat numarul de cadouri pe care le primeste. Pentru a imprumuta bani de la ea de n ori, trebuie sa ii ofere n cadouri. Sa se determine toate posibilitatile de a oferi cadouri pentru a obtine cele n imprumuturi. Date de intrare: Date de iesire: n - numarul de imprumuturi toate posibilitatile de oferire a cadourilor si obtinere a imprumuturilor

Exemplu: Se considera notatia C pentru cadou si B pentru imprumut (in engl. borrow). Pentru n = 2, ordinea poate fi : CBCB sau CCBB, deci in total 2 posibilitati. Rezolvare: Se considera vectorul solutie organizat ca o structura de date de tip stiva, la care inaltimea maxima este 2*nr_de_imprumuturi_ce_trebuie_efectuate, iar inaltimea curenta a stivei, respectiv nivel, reprezinta indicele componentei care urmeaza sa primeasca o valoare.
procedura ordineCadouri() este nivel = 1; init_stiva( nivel ); cat timp ( nivel > 0 ) executa repeta areSuccesor = succesor( nivel ); daca areSuccesor == ADEVARAT atunci esteElementValid = validare( nivel ); cat timp( areSuccesor si !esteElementValid ) daca ( areSuccesor == ADEVARAT) atunci daca ( esteSolutie ( nivel ) ) atunci afiseazaSolutie(); altfel nivel = nivel + 1; init_stiva( nivel ); @ altfel nivel = nivel - 1; @ @ sfarsit

69

Functia succesor realizeaza completarea unui nivel al stivei cu toate valorile existente pentru acel nivel, iar functia validare verifica daca este posibila completarea unui nivel al stivei cu valoarea aleasa la un moment dat. Daca s-a completat cu succes un nivel al stivei, se afiseaza solutia (daca este ultimul nivel) sau se trece la completarea urmatorului nivel. In caz contrar, adica nu s-a gasit nici o valoare posibila pentru un anumit nivel al stivei, se revine la alegerea elementului de pe nivelul anterior. Acesti pasi se repeta cat timp nivelul se mentine la o valoare mai mare decat 0. Nivelul va ajunge la valoarea 0 atunci cand nu mai exista succesor pentru primul nivel si se executa nivel = nivel 1. Functiile succesor si validare pot fi implementate sub forma:
functie succesor ( nivel ) este daca stiva[nivel] < nr_maxim_de_valori atunci stiva[ nivel] ++; intoarce ADEVARAT; @ intoarce FALS; functie validare ( nivel ) este *) daca nr. cadouri este mai mare decat *) sau nr. de imprumuturi este mai mare *) sau daca nr. de cadouri este egal cu element din vectorul solutie este intoarce FALS intoarce ADEVARAT

nr. total de cadouri de oferit decat nr. de cadouri cel de imprumuturi si ultimul un cadou

Functia init_stiva (nivel) realizeaza initializarea elementului de pe un nivel al stivei cu un element neutru (care nu se gaseste in domeniul de valori posibile pentru nivelul respectiv) .
procedura init_stiva( nivel ) stiva[nivel] = 0; sfarsit este

Functia esteSolutie verifica daca s-a ajuns la o solutie a problemei. In cazul problemei imprumutului, o solutie se obtine daca au fost completate 2 * n nivele ale stivei cu n imprumuturi si n cadouri.
functie esteSolutie( nivel ) este intoarce nivel == 2 * n

Pentru marirea vitezei de executie, functiile init_stiva si esteSolutie pot fi realizate ca macrodefinitii.

3. Teme de realizat n timpul laboratorului


1. Rezolvati problema specificata la inceputul laboratorului prin metoda iterativa a cautarii cu revenire. 2. Folosind metoda prezentata in acest laborator, rezolvati problema din cadrul laboratorului de backtracking recursiv.

70

Bibliografie
1. PENTIUC tefan Gheorghe, Structuri de date i algoritmi fundamentali, Curs, Universitatea tefan cel Mare, Suceava, 1993; 2. SORIN Tudor, Informatic, Tehnici de programare, Editura L&S, Bucureti 2000; 3. PENTIUC tefan-Gheorghe, TURCU Elena-Cristina, TURCU Corneliu-Octavian, MAHALU George, PETRIOR Cristinel, Programarea calculatoarelor, Editura Suceava, 1995. 4. IORGA Valeriu, OPINCARU Cristian, STRATAN Corina, CHIRITA Alexandru, Structuri de date i algoritmi. Aplicaii n C++ folosind STL. Editura Polirom, Bucureti, 2005.

71

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