Curs ASD Format B5

167
 Algoritmi şi structuri de date MINISTERUL EDUCAŢIEI ŞI CERCETĂRII UNIVERSITATEA “1 DECEMBRIE 1918” Lect. dr. Corina Rotar ALGORITMI ŞI STRUCTURI DE DATE Alba Iulia 2008 1

Transcript of Curs ASD Format B5

Page 1: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 1/166

Algoritmi şi structuri de date

MINISTERUL EDUCAŢIEI ŞI CERCETĂRIIUNIVERSITATEA “1 DECEMBRIE 1918”

Lect. dr. Corina Rotar

ALGORITMI ŞI STRUCTURI DE DATE

Alba Iulia

2008

1

Page 2: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 2/166

CUPRINS

I. Algoritmi şi programare. Descrierea algoritmilor .......................................2II. Elementele limbajului de programare C .................................................. 15III. Functii. Transmiterea parametrilor. Recursivitate.................................. 34IV. Tablouri. Tehnici de sortare................................................................... 43V. Structuri. Tipuri de date definite de utilizator......................................... 60VI. Lucrul cu fişiere ......................................................................................70VII. Alocarea dinamica a memoriei ............................................................. 78VIII. Listă simplu înlănţuită ......................................................................... 81IX. Lista dublu înlănţuită .............................................................................91X. Liste circulare. Stive. Cozi .....................................................................100XI. Arbori ................................................................................................... 110XII. Elemente de Grafuri. Algoritmi.......................................................... 127XIII. Metode de elaborare a algoritmilor. Divide et Impera......................132XIV. Metode de elaborare a algoritmilor.Greedy .......................................143XV. Metode de elaborare a algoritmilor. Backtracking. ........................... 148XVI. Metode de elaborare a algoritmilor.Programare dinamica................ 158

Page 3: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 3/166

Algoritmi şi structuri de date

I. ALGORITMI ŞI PROGRAMARE. DESCRIEREA

ALGORITMILOR 1. Programare. Etapele programării.

Programarea reprezintă activitatea complexă de elaborare a programelor.Programareanu se referă strict la scrierea codului sursă (descrierea în limbaj de programare a rezolvării problemei); această activitate implică parcurgerea maimultor etape:

a. Analiza problemei.Problemele reale cu care ne confruntăm nu sunt

formulate întotdeauna într-un stil clar, precis. De cele mai multe ori, problemelesunt formulate incomplet, ambiguu, lăsând programatorului sarcina de a determinacorect: ce se cunoaşte din problemă şi rezultatele cerute. Etapa de analiză a problemei se finalizează prin identificarea celor două elemente esenţiale aleformulării unei probleme:datele de intrare şi datele de ieşire .

b. Proiectarea algoritmuluipoate fi considerată etapa de creativitate a programării, în care folosindu-se de cunoştinţele şi experienţa dobândite, programatorul va identifica metoda de rezolvare a problemei date şi va dezvoltaalgoritmul corespunzător. Finalitatea acestei etape o constituie un algoritm descris

clar într-una dintre variantele de reprezentare algoritmică (scheme logice, pseudocod, sau chiar limbaj de programare – în cazul în care problema este dedificultate mică).

c. Traducerea în limbaj de programare(implementarea): este etapa în care seva efectua o “traducere” în limbaj de programare a descrierii algoritmului rezultatîn etapa de proiectare. Cunoaşterea în detaliu a regulilor sintactice ale limbajuluiales, experienţa şi stilul programatorului sunt ingredientele necesare şi suficienteale acestei etape.

d. Traducerea în cod maşină, execuţia şi testarea. Traducerea în cod maşinăse realizează automat cu ajutorul a două componente ale mediului de programare:compilatorului şi a editorul de legături. Testarea programului constă în execuţia sarepetată pentru o mulţime de date de intrare (date de test) şi verificareacorectitudinii rezultatelor oferite. Rezultatele incorecte ne semnalează o eroarelogică de proiectare şi necesită o revizuire a algoritmului şi re-parcurgerea etapelor programării.

e. Întreţinerea este ultima etapă a programării şi constă din acţiuni deactualizare a produsului final şi de asistenţă oferită beneficiarului.

Dintre toate aceste etape, cea care este mai solicitantă este etapa de proiectare.Practic, parcurgerea corectă a acestei etape va face diferenţa între programatori şiamatori. Esenţa programării constă în capacitatea programatorului de a elabora şidescrie clar metoda de rezolvare a problemei. Orice eroare apărută la nivelul etapei

2

Page 4: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 4/166

Algoritmi şi structuri de date

de proiectare a algoritmului va avea repercusiuni asupra produsului final, generânderori logice.

2. Definirea algoritmilor

Aşa cum am subliniat mai sus, etapa de proiectare a algoritmilor este cea maicomplexă dintre cele etapele enumerate ale programării. Noţiunea de algoritm, proprietăţile pe care trebuie să le îndeplinească acesta şi modalităţile dereprezentare standardizată a algoritmilor fac subiectul paragrafelor următoare.

Cuvântulalgoritmprovine din pronunţia fonetica a numelui matematicianuluiarab Al-Khwarizmi Muhammed ibs Musa (780-850), care se referă lareguli precisepentru descrierea proceselor de calcul din aritmetică. Aceiaşi descriere seregăseşte în lucrarea Elementele lui Euclid , cca. 300 î.Hr., când pentru prima datăse descrie o secvenţă ordonată de reguli clare pentru descrierea rezolvării unor probleme. De altfel, algoritmul de determinare a celui mai mare divizor comun adouă numere (algoritmul lui Euclid) este considerat ca primulalgoritmdin istorie.

În limbajul uzual, prin algoritm se înţelege o metodă de rezolvare a unei probleme, alcătuită dintr-o mulţime de paşi, dispuşi într-o ordine stabilită, ale căror parcurgere ne conduce la rezultatul dorit. Algoritmii informatici, despre care vomdiscuta în acest capitol, sunt definiţi mult mai riguros, surprinzând proprietăţileobligatorii pe care aceştia trebuie să le îndeplinească.

Definiţie: Un Algoritm (informatic) reprezintă o secvenţă finită şi ordonată de reguliclare, a căror parcurgere ne permite ca, pornind de la o mulţime de date de intrare, să obţinem în modeficient rezultatelecorecteale problemei.

3. Proprietăţile algoritmilor:

Orice algoritm informatic verifică următoarele proprietăţi:

1. Generalitate -un algoritm nu rezolvă o singură problemă, ci o clasă de probleme de acelaşi tip.

2. Finitudine -acţiunile algoritmului trebuie să se termine după un număr finit de operaţii, aceasta pentru orice set de date valide

3. Claritate - acţiunile algoritmului trebuie să fie clare, simple şi rigurosspecificate

4. Corectitudine- algoritmul trebuie să producă un rezultat corect (date deieşire) pentru orice set de date de intrare valide

5. Eficienţă -algoritmul trebuie să fie eficient privind resursele utilizate, şianume să utilizeze memorie minimă şi să se execute într-un timp minim.

Regulile prin care algoritmul exprimă maniera de rezolvare a problemei sunt de4 tipuri:1. reguli de intrare prin care se realizează introducerea datelor de intrare în

memoria unui sistem de calcul virtual sau real

3

Page 5: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 5/166

Algoritmi şi structuri de date

2. reguli de calcul care permit efectuarea operaţiilor elementare aritmetice3. reguli condiţionale prin care se va decide continuarea sau nu a

algoritmului printr-o secvenţă de reguli4. reguli de ieşire prin care se permite furnizarea rezultatelor finale ale

algoritmuluiÎn funcţie de tipurile de reguli pe care le conţine, un algoritm poate fi:

- Algoritm liniar– conţine doar reguli de tipul 1,2,4- Algoritm ramificat– conţine cel puţin o regulă de tipul 3- Algoritmi repetitivi (ciclici)– o secvenţă de reguli se repetă de

un număr finit de ori.

4. Obiecte si operaţii ale algoritmilor

Algoritmii informatici operează cu următoarele obiecte fundamentale:- constante- variabile

Constanta – reprezintă o mărime a cărei valoare nu se modifică în timpulexecuţiei (parcurgerii) algoritmului.

Variabila – reprezintă o mărime a cărei valoare este modificabilă în timpulexecuţiei algoritmului.

Cuvântulvariabilă este unul fundamental în programare. Prin această noţiune sedenumesc date de tipuri diferite. Tipurile de date sunt clasificate ca tipurielementare (întreg, real, caracter) şi tipuri structurate. Datele elementare suntunităţi indivizibile de informaţie, iar datele de tip structural sunt alcătuite prinasamblarea datelor elementare. Printr-un tip de dată se înţelege în general atâtdomeniul de valori posibile ale datelor, cât şi operaţiile specifice datelor de acel tip.Introducerea şi utilizarea unei variabile în descrierea algoritmului corespundeidentificării şi manipulării unei date de un tip de dată presupus. Variabila are ataşatun nume, o valoare curentă care aparţine domeniului tipului specificat şi implicăcunoaşterea mulţimii de operaţii posibile la care ia parte. În algoritmii informatici,variabilele sunt toate datele de intrare, datele de ieşire (rezultatele finale ale problemei) şi datele intermediare (acele date care corespund unor rezultate parţialeale problemei ce intervin în procese ulterioare pentru determinarea rezultatelor finale).

În anumite situaţii, acţiunea algoritmilor este îndreptată asupra: fişierelor şi aarticolelor. Fişierul reprezintă o mulţime structurată şi omogenă de date şi articolul este unitatea atomică a fişierului.

Obiectele pe care le utilizează un algoritm sunt supuse unor operaţii demanipulare. Secvenţa de paşi descrisă de algoritm este parcursă într-o anumităordine dictată de operaţiile de control. Cele două categorii de operaţii formeazăoperaţiile principale ale algoritmilor informatici:

- Operaţii de intrare-ieşire – permit introducerea în memoriasistemului de calcul (real sau virtual) a datelor de intrare şi respectiv,redarea rezultatelor obţinute

4

Page 6: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 6/166

Algoritmi şi structuri de date

- Operaţii de atribuire – prin intermediul acestor operaţii, uneivariabile i se atribuie valoarea unei alte variabile, a unei constante saurezultatul evaluării unei expresii

- Operaţii de calcul– sunt operaţiile executate cu ajutorul expresiilor

- Operaţii de decizie– condiţionează execuţia unui operaţii sau grupede operaţii în urma evaluării unor expresii la valorile logice – adevărat, fals.

- Operaţii de apel– permit apelul unei instrucţiuni sau a unui grup deinstrucţiuni în vederea executării acesteia de un număr finit de ori

- Operaţii de salt– permit continuarea algoritmului dintr-un anumit punct al acestuia

- Operaţii auxiliare– operaţii specifice lucrului cu baze de date saufişiere.

5. Descrierea algoritmilor. Scheme logice

Reprezentarea algoritmilor poate fi făcută în două maniere:- grafic– prin intermediul schemelor logice- textual – prin intermediul unor limbaje standardizate (limbaj

pseudocod, limbaj de programare)Schemele logice sunt reprezentări grafice ale algoritmilor informatici construite

pe baza unei mulţimi de simboluri graficeconectate prin intermediul săgeţilor .Mulţimea de simboluri grafice şi semnificaţia acestora este prezentată încontinuare:

a. Simbolurile delimitatoare: având rolul de a marca începutul şi sfârşitulschemei logice, corespunde momentelor de start şi stop a algoritmuluidescris corespunzător.

b. Simboluri de intrare-ieşire – corespunzătoare operaţiilor de intrare-ieşire prin care se realizează comunicarea cu exteriorul sistemului de calculvirtual.

5

Page 7: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 7/166

Algoritmi şi structuri de date

c. Simboluri de atribuire - calcul – pentru reprezentareaoperaţiilor decalcul şi atribuire. Detaliile referitoare la operaţii sunt înscrise în interiorul blocului.

d. Simbolul de decizie – utilizate pentru reprezentareaoperaţiilor de decizie.Sunt simboluri cu o singură intrare şi cel puţin două ieşiri.

e. Simbolul de procedură – se folosesc pentru reprezentareaoperaţiilor de

apel . Sunt apelate proceduri sau module externe (care sunt descrise în altă parte).

f. Simboluri auxiliare: Conectorii şi săgeţile – asigură consistenţa schemei

logice.

Utilizarea corectă a simbolurilor grafice permite descrierea oricărui algoritminformatic. Se evidenţiază trei structuri fundamentale corespunzătoare: parcurgeriisecvenţiale a unei succesiuni de paşi, ramificării algoritmilor şi execuţiei repetate a

6

Page 8: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 8/166

Algoritmi şi structuri de date

unei secvenţe de operaţii. Cele trei structuri fundamentale sunt:structurasecvenţială, structura alternativă, structura repetitivă, şi sunt descrise prin blocuri de simboluri logice astfel:

Denumirestructură Reprezentare grafică SemnificaţieStructurasecvenţială

Execuţia secvenţială aoperaţiilor descrise însimbolurile de calcul:S1, …Sn

Structuraalternativă

Execută secvenţa S1 dacăcondiţia Cond este adevăratăSAU execută secvenţa S2 dacăCond este falsă

Execută secvenţa S dacăcondiţia Cond este adevăratăSAU nu execută secvenţa SdacăCond este falsă.

Structurarepetitivă

Structura repetitivă precondiţionată :

Cât timp condiţiaCond rămâneadevărată repetă execuţiasecvenţei SStructura repetitivă postcondiţionată :

Repetă execuţia secvenţei S câttimp condiţia Cond rămâneadevărată

Observaţie: Diferenţa dintre structurile repetitive precondiţionată şi postcondiţionată constă în poziţia simbolului de decizie corespunzător etapei deverificare a condiţiei de continuare a execuţiei blocului:

- structura precondiţionată presupune iniţial verificarea condiţiei şi apoiexecuţia secvenţei

- structura postcondiţionată presupune execuţia secvenţei şi apoiverificarea condiţiei

Această diferenţă va genera un număr minim de repetări a secvenţei S diferit pentru cele două structuri: minim 0 execuţii pentru structura precondiţionată şiminim 1 execuţie a secvenţei în structura postcondiţionată, în situaţia în care de la prima evaluare a condiţiei aceasta este falsă.. 6. Exemple de scheme logice

7

Page 9: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 9/166

Algoritmi şi structuri de date

Exemplul 1 . Algoritmul de determinare a soluţiilor ecuaţiei de gradul 2:02 =++ cbxax . Rezolvarea problemei presupune tratarea celor 4 cazurilor

identificate în funcţie de datele de intrare furnizate:1. rădăcinile ecuaţiei sunt reale

2. ecuaţia de gradul II nu are rădăcini reale3. ecuaţia este de gradul I4. ecuaţia este imposibilă

Exemplul 2. Algoritmul de determinare a produsului primelor n numere naturale.

8

Page 10: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 10/166

Algoritmi şi structuri de date

Exemplul 3. Algoritmul de determinare a celui mai mare divizor comun a douănumere:

7. Pseudocod

Pseudocodul este un limbaj standardizat intermediar între limbajul natural şi

limbajul de programare. Descrierea algoritmilor cu ajutorul limbajului pseudocodînlătură din neajunsurile utilizării schemelor logice, fiind mult mai flexibil şinatural decât acestea. În plus, descrierea în pseudocod permite convertirea cuuşurinţă a algoritmilor astfel exprimaţi într-un limbaj de programare.

9

Page 11: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 11/166

Algoritmi şi structuri de date

Limbajul pseudocod foloseşte două tipuri de propoziţii:1. Propoziţiile standard: proprii limbajului pseudocod2. Propoziţiile ne-standard: acele propoziţii ce descriu în limbaj uzual

operaţii ce urmează a fi detaliate, rafinate ulterior. Aceste propoziţii sunt marcate prin simbolul#.

Există o concordanţă între simbolurile grafice ale schemelor logice şi propoziţiile limbajului pseudocod. De asemenea, structurile fundamentale pot fidescrise prin propoziţii proprii limbajului pseudocod.

Tabelul următor prezintă concordanţa dintre descrierea grafică şi propoziţiile pseudocod pentru operaţii specifice algoritmilor:

Schema logică Pseudocod

Algoritmul NUME-ALGORITM este:

SfârşitNUME-ALGORITM sau SfAlgoritm

Citeştea1,a2,…,an

Tipăreştea1,a2,…,an

Limbajul pseudocod, pentru a uşura traducerea ulterioară a algoritmului înlimbaj de programare, permite folosirea unei propoziţii standard echivalentă uneiadintre instrucţiunile populare ale limbajelor de programare. Aceasta propoziţiecorespunde unei structuri repetitive cu număr cunoscut de repetări şi se descrieastfel:

Schema logică Pseudocod

Pentru var de la I la F cu pasul pas Execută S

Sfârşit Pentru

- structura ciclică cu număr cunoscut de repetări

10

Page 12: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 12/166

Page 13: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 13/166

Algoritmi şi structuri de date

AltfelTipăreşte “Imposibil de

rezolvat”SfDacă

Altfel Δ = b2-4acDacă Δ≥ 0 atunci

ab x 2)(1 ∆−−=

ab x 2)(2 ∆+−=

Tipăreştex1,x2Altfel

Tipăreşte “Rădăcini complexe“SfDacă

SfDacăSfârşit EcuaţieGradII

Exemplul 2. Algoritmul de determinare a produsului primelor n numere naturale.

AlgoritmFactorialeste:Citeşte n P:=1Pentru i de la1 la n cu pasul 1

Execută P:=P * iSfârşit PentruTipăreşte P

Sfârşit Factorial

Exemplul 3. Algoritmul de determinare a celui mai mare divizor comun a douănumere.

AlgoritmEuclideste:Citeşte a,brest = a modulo bCâttimp(rest ≠ 0)

a = b

b = restrest = a modulo bSfârşit câttimpTipăreşte b

Structură repetitivă precondiţionată

Structură repetitivă cunumăr cunoscut derepetări

12

Page 14: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 14/166

Algoritmi şi structuri de date

SfârşitEuclid

10. Subalgoritmi

O problemă de dificultate sporită necesită uneori o împărţire în subprobleme dedificultate mai mică în baza principiuluidivide et impera. Algoritmii de rezolvare asubproblemelor rezultate sunt mai uşor de descris şi vor constitui subalgoritmiaialgoritmului global de rezolvare a problemei considerate. Deseori se poate întâlnisituaţia ca o anumită secvenţă de operaţii să fie executată de mai multe ori pentrudate de intrare diferite. În aceste cazuri este utilă construirea unui subalgoritmcorespunzător secvenţei de operaţii şi apelarea acestuia în algoritmul global ori decâte ori este nevoie.

Subalgorimii sunt practic algoritmi care rezolvă subprobleme ale unei problemedate. Acest lucru indică faptul că orice subalgoritm verifică proprietăţile degeneralitate, finitudine, claritate, corectitudine ale algoritmilor informatici.Caracterul de generalitate va fi asigurat prin parametrizarea subalgoritmilor.Aceştia vor primi la intrarenu datele de intrare ale problemei ci date intermediareale problemei globale sau rezultate parţiale din procesele de calcul. Ieşirilesubalgoritmilor sunt date pe care algoritmul general le va prelucra ulterior.Comunicarea dintre subalgoritm şi algoritmul “părinte” se realizează prinintermediul parametrilor. În pseudocod sintaxa generală a unui subalgoritm esteurmătoarea:

Subalgoritm NumeSubalgoritm( lista parametrii formali)

…. //operaţii asupra parametrilor din listaSfârşit NumeSubalgoritm

Apelarea unui subalgoritm din algoritmul apelant se face prin propoziţia:Cheamă NumeSubalgoritm(listă parametrii actuali)

Lista parametrilor formali va conţinenume genericeale datelor de intrare şidatelor de ieşire ale subalgoritmului. Lista parametrilor actuali conţine numeledatelor concrete care se doresc a fi transmise subalgoritmului şi numele sub care sereţin rezultatelor parţiale ale subalgoritmului.

La apelul unui subalgoritm parametrii formali (generici) din listă se vor înlocuicu parametrii concreţi (actuali).

Exemplu: Să se descrie un algoritm de determinare a maximului dintre 4 valoridate, evidenţiind subalgoritmul de determinare a maximului dintre oricare douăvalori.

Subalgoritm Maxim2(DI: x ,y; DE: Max)Dacăx>yatunci

Max=xAltfel

Max=y

SfDacăSfârşit Maxim2

Algoritm Maxim4 este: Apelul repetat al subalgoritmului, pentru

diferiţi parametriactuali

13

Page 15: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 15/166

Algoritmi şi structuri de date

Citeştea,b,c,dCheamă(a,b; max1)Cheamă(c,d; max2)Cheamă(max1,max2 ; maxim)Tipăreştemaxim

Sfârşit Maxim4

Rezolvarea problemelor cu ajutorul calculatorului presupune:1. Modelarea matematică a problemei2. Alegerea unei metode de rezolvareModelarea matematică şi alegerea metodei de rezolvare se îmbină cu

conceperea algoritmului rezultând ceea ce numim proiectarea programului. În fazade elaborare a algoritmului trebuie să se ţină seama de proprietăţile fundamentaleale algoritmilor: generalitate, claritate, finitudine, corectitudine şi eficienţă.Calitatea implementării software este dependentă de calitatea algoritmului elaborat.De aceea, faza de dezvoltare a algoritmului de rezolvare a unei clase de problemetrebuie abordată cu o deosebită atenţie.

14

Page 16: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 16/166

Algoritmi şi structuri de date

II. ELEMENTELE LIMBAJULUI DE PROGRAMARE C

Limbajul de programare C a fost dezvoltat la începutul anilor ’70 de către KenThompson şi Dennis M. Ritchie. Popularitatea acestui limbaj a fost câştigatădatorită avantajelor pe care le prezintă:

- programele scrise în C sunt portabile eficiente- permite utilizarea principiilor programării structurate- oferă facilităţi de manevrare a biţilor, octeţilor şi adreselor de memorie- este un limbaj dedicat paradigmei programării procedurale

Prin limbaj de programare înţelegem totalitatea regulilor sintactice şi semantice prin care se pot comunica unui computer algoritmii de rezolvare a problemelor.

Elementele unui limbaj de programare sunt: alfabetul, unităţile lexicale,unităţile sintactice şi comentarii.

A. Alfabetul limbajului Ceste format din:

1. <literă>::=A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Z|Y|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|z|y|_ 2. <cifră> ::= 0|1|2|3|4|5|6|7|8|93. <simboluriSpeciale>::=<simboluriSpecialeAfişabile>|<simboluriSpecialeNeafişabile><simboluriSpecialeAfişabile>::=!|,|”|%|#|&|(|)|*|/|+|-|:|

;|<|=|>|?|[|]|\|~|{|}|||.|’|spaţiu|<simboluriSpecialeNeafişabile>::=\n |\t |\b |\r |\f |\v |\a

B. Unităţile lexicale:

1. Identificatori2. Cuvinte cheie (cuvinte rezervate)3. Constante4. Operatori

C. Unităţile sintactice:

1. Expresii2. Instrucţiuni

D. Comentarii:au rolul de a justifica textul sursă redactat şi de a oferi omai bună înţelegere a acestuia. Comentariile sunt marcate în programul

sursă prin // sau /*…*/Exemple: //variabilai are semnificaţia unui contor /* acest program determină

soluţiile ecuaţiei de gradul II*/

15

Page 17: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 17/166

Algoritmi şi structuri de date

B. Unităţile lexicale ale limbajului C

Unităţile lexicale sunt elementele atomice ale unui program, formate cu ajutorulsimbolurilor precizate de alfabet.

B.1. Identificatorii: sunt secvenţe de litere şi cifre ale limbajului definit careîncep obligatoriu cu o literă sau caracterul ‘_’, având rolul de a identificaconceptele utilizate în program. Identificatorii corespund unor nume devariabile,nume de constante simbolice, nume de funcţii.

Variabile, tip de dateVariabilă:- are un nume care o identifică (acest nume este exprimat printr-un

identificator)- are asociată o locaţie de memorie în care se regăseşte valoare curentă,conţinutul acestei locaţii de memorie se poate schimba

- are un anumittip de date, care exprimă natura şi dimensiunea valorilor pecare le ia

Regulă: într-un program C, toate datele (variabile) trebuie declarate pentru a putea fi folosite. Prin declararea unei date se înţelege precizarea tipului dateirespective şi stabilirea identificatorului. Tipul datei ne spune domeniul valorilor datei cât şi lungimea de reprezentare internă. Declararea datelor se face prin

instrucţiuni de declarare de tip de date:<instrucţiune de declarare de tip>::= <tip><listă de identificatori>;

unde:<tip> poate fi un tip predefinit (vezi lista tipurilor predefinite în C), un tipdefinit de programator sau tipul specialvoid (tip nedefinit ).

Exemple:int a,b,c; // declararea a trei variabile simple de tip întregfloat var;//declararea unei variabile simple de tipul real, virgulă flotantă însimplă preciziechar ch ; // declararea unei variabile de tip caracter

B.2. Cuvintele rezervate(cuvinte cheie) sunt identificatori care au osemnificaţie specială. Orice cuvânt rezervat nu poate avea altă utilizare într-un program decât cea predefinită. Mulţimea cuvintelor cheie ale limbajului C este prezentată în tabelul următor:

Cuvintele cheie ale limbajului Cauto defaul

tfloat registe

r switch

break do for return typedef case double go to short unionchar else if signed unsignedconst enum int sizeof void

16

Page 18: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 18/166

Algoritmi şi structuri de date

continue extern long static volatilestruct while

Lista cuvintelor rezervate conţine şi setul de tipuri predefinite ale limbajului C.

Tipurile predefinite ale limbajului corespund tipurilor elementare de date: întreg,real, caracter. Aceste tipuri sunt introduse prin cuvintele rezervate:

Tipulpredefinit Semnificaţie Domeniul de valori

int întreg reprezentat intern pe 16 biţi,în cod complementar faşă de 2

[-32768,32767]

short întreg reprezentat intern pe 16 biţi,în cod complementar faşă de 2

[-32768,32767]

long întreg reprezentat intern pe 32 biţi,în cod complementar faşă de 2

[-2147483648,2147483647]

unsigned întreg fără semn reprezentat pe 16 biţi

[0,65535]

unsigned long

întreg fără semn reprezentat pe 32 biţi

[0,4294967295]

char caracter reprezentat intern princodul ASCII corespunzător pe 8 biţi

[0.255]

float Real, reprezentat în virgulă flotantă,simplă precizie – pe 32 biţi

[- 38104,3 ⋅ , 38104,3 ⋅ ]- valorile minime cuprinse înintervalul [- 38104,3 −

⋅ ,38104,3 −

⋅ ] se confundă cu 0

double Real, reprezentat în virgulă flotantă,dublă precizie – pe 64 biţi

[- 308107.1 ⋅ , 308107.1 ⋅ ]- valorile minime cuprinse înintervalul [- 308107.1 −

⋅ ,308107.1 −

⋅ ] se confundă cu0

unsigned char

Caracter, reprezentare internă fărăsemn, pe 8 biţi, echivalent implicit pentruchar

[0,255]

signed char

Caracter, reprezentare internă cusemn, pe 8 biţi

[-128,127]

long double

Real, reprezentat în virgulă flotantă,dublă precizie – pe 80 biţi

- valoarea minimă absolutăreprezentabilă: 4932104,3 −

- valoarea maximă absolutăreprezentabilă: 4932101.1 +

B.3. Constante

17

Page 19: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 19/166

Algoritmi şi structuri de date

Constantele sunt mărimi ale căror valoare nu se modifică pe parcursul execuţieiunui program. Constantele se clasifică în patru categorii:

- Constantecaracter - Constante“şir de caracter”

- Constantenumerice- Constante simbolice

Constante caracter Constanta caracter este un simbol care are ataşată valoarea codului ASCII al

caracterului corespondent.. Un caracter este reprezentat în memoria calculatorului pe un octet (8 biţi).

Există două categorii de caractere: caractere afişabile (imprimabile) şi caractereneafişabile:

<constanta caracter>::= ‘ <caracter> ‘<caracter>::=<caracter afişabil (ASCII)> |<caracter neafişabil>O constantă caracter grafică (afişabilă) se specifică incluzând caracterul

între simbolurile apostrof: ‘ ‘. Exemple:

‘A’ – codul ASCII 65‘a’ – codul ASCII 97‘+’ – codul ASCII 77‘2’ – codul ASCII 50

O constantă caracter non-grafică (neafişabilă) au notaţii speciale, se specifică

utilizând caracterul backslash (\) şi apostroful (‘).Exemple:Întoarcerea cu un spaţiu (Backspace) ‘\b’ – codul ASCII 8Retur car ‘\r’ – codul ASCII 13Linie nouă ‘\n’ – codul ASCII 10

Constante şir de caractereSunt formate dintr-o succesiune de caractere care se delimitează prin ghilimele:

“exemplu”. Fiecare caracter al şirului se reprezintă în memoria calculatorului pe unoctet, prin codul ASCII corespunzător. Sfârşitul secvenţei de coduri ale caracterelor dintr-un şir este marcată în memorie de un octet special cu valoarea NULL,corespunzător caracterului ‘\0’.Observaţie: reprezentarea în memorie a lui ‘k’ este diferită de reprezentarea lui“k”. Astfel, şirului “k” îi este alocat un spaţiu de 2 octeţi, ultimul fiind cel cemarchează sfârşitul NULL.

Constante numericeConstantele numerice sunt în faptnumerele. În limbajul C se face o distincţie

între numere, în funcţie de tipul (întreg sau real), baza de numeraţie şi preciziacodificării.

Numerele întregi zecimale,exemple: -123, 5, +5. Numerele octale întregi, încep cu cifra 0 şi sunt de forma: 0c…c, unde ceste cifră octală. Exemple: 0452 , unde 452 este numărul în baza 8

18

Page 20: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 20/166

Algoritmi şi structuri de date

Numerele hexazecimale întregi: încep cu 0x sau 0X şi sunt de forma:0xc…c unde c sunt cifre hexazecimale. Exemplu: 0xabbd. Numerele flotante de tip real în simplă precizie[{+/-}]dd…d . dd…dPot să conţină semnul (+ sau -) specificat la începutul scrierii urmat de partea întreagă, punctul zecimal şi partea fracţionară.Exemple: +23.567 , -.667 , .4567 Numerele flotante de tip real în dublă precizie[{+/-}]dd…d . dd…d {E / e} [{+/-}] dd sau:[{+/-}] <parte întreagă>.<parte fracţionară> {E/e} [{+/-}] <exponent>Exemple:0.345E2 (corespunzător valorii 0.345*102)-0. 012e-3 (-0.012*10-3)22.0e12 (=22*1012)

Constante simboliceDefinirea constantelor simbolice se face prin directiva de preprocesaredefine,

prin construcţia:#define <NumeConstantă> <ValoareAsociată>Ex: #define PI 3.1415

#define raza 124

B.4. OperatoriiOperatorii sunt reprezentaţi de simboluri sau secvenţe de simboluri care intră în

alcătuirea expresiilor.În funcţie de tipul operaţiilor pe care le induc, operatorii limbajului C sunt

clasificaţi:a. Operatori aritmetici b. Operatori de incrementare şi decrementarec. Operatori logicid. Operatori relaţionalie. Operatori de deplasaref. Operatori la nivel de biţig. Operatori de asignare (atribuire)h. Operatorul condiţionali. Alţi operatori

După numărul operanzilor pe care îi implică, operatorii pot fi:- unari- binari- ternari

Operatorii aritmetici Operatori aritmetici unari:

<OperatoriAritmeticiUnari>::= - | +Au rolul de a specifica semnul unei expresii. Se folosesc în construcţii de

următoarea formă:{+/-}<expresie>

19

Page 21: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 21/166

Algoritmi şi structuri de date

Dacă o expresie nu este precedată de semn se consideră implicit semnul +(pozitiv).

Exemple: +12.34, -0.56, +(a-2), etc.

Operatori aritmetici binari:<OperatorAritmeticBinar>::= +| - | * | / | %

Au semnificaţia operaţiilor aritmetice: adunare, scădere, împărţire, inmulţire,modulo şi se utilizează în structuri de forma:

<expresie1><OperatorAritmeticBinar><expresie2>Expresiile 1, 2 pot fi reprezentate de constante, variabile, nume de funcţii sau

alte expresii aritmetice.Exemple: a+b, (a+b) / 2, suma(a,b) % c , etc.

Operatorii de incrementare-decrementare

<OperatorulDeIncrementare>::= ++Se foloseşte în construcţii de forma:

++<expresie> (preincrementare)<expresie>++ (postincrementare)

Semnificaţia acestuia este următoarea:++<expresie> este echivalent cu <expresie> := <expresie>+1, unde prin simbolul “:=“ se înţelege “i se atribuie”

<OperatorulDeDecrementare>::= --Se foloseşte în construcţii de forma:

--<expresie> (predecrementare)<expresie>-- (postdecrementare)

Semnificaţia acestuia este următoarea:--<expresie> este echivalent cu <expresie> := <expresie>-1

Diferenţa dintre preincrementare şi postincrementare:Fie următoarele două expresii:

1. A:=++B2. A:=B++si B are valoarea iniţială 4.

Pentru prima expresie, în urma efectuării calculelor B va avea valoarea 5 şi Ava avea valoarea 5 dat fiind faptul că prima acţiune este aceea de incrementareurmată de atribuire. În al doilea caz, B are valoarea 5 iar A=4, dat fiind faptul căatribuirea se face înaintea incrementării.

Operatorii relaţionali:<OperatorRelaţional>::= = = | != | < | <= | > | >=

Cu semnificaţia:= = egal!= diferit<= mai mic sau egal>= mai mare sau egal, etc.

20

Page 22: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 22/166

Algoritmi şi structuri de date

Se folosesc în construcţii de forma:<expresie1><OperatorRelaţional><expresie2>

O structură de forma anterioară este denumită expresie relaţională şi esteevaluată la una dintre valorile logice de adevăr True (1) sau False (0)

Exemplu: Fie expresia2<3 ; în urma comparării operanzilor (constantenumerice în acest caz) se constată că valoarea logică este “adevăr” ceea ceconduce la evaluarea expresiei 2<3 la valoarea 1 (Adevărat).

Operatorii logici:<OperatorLogic> ::= && | || | !

Cu semnificaţia:&& - operatorul AND (ŞI) conjuncţia|| - operatorul OR (SAU) disjuncţia! - operatorul NOT (negaţia)

Exemple:(a<b) && (b !=c) , a || (!a)

Operatori de deplasare:<OperatorDepalsare>::= << | >>

Sunt operatori binari utilizaţi în construcţii de forma:<expresie1><OperatorDeplasare><expresie2>

unde: expresiile sunt evaluate în prealabil la valori întregi;Operatorii de deplasare corespund operaţiilor de deplasare pe biţi, efectul

acestora fiind acela de a provoca deplasarea biţilor din reprezentarea binară aîntregului dat de expresia 1 la stânga (<<) sau la dreapta (>>) cu un număr de poziţii specificat de valoarea întreagă a expresiei 2. Regulă : Prin aceste operaţii de deplasare, biţii deplasaţi în afara limitei dereprezentare se pierd, iar biţii eliberaţi sunt completaţi cu 0 sau 1 în funcţie desemnul întregului respectiv: pozitiv sau negativ:

A<<B are semnificaţia de deplasare a biţilor din reprezentarea binară a luiA cu B poziţii la stângaA>>B are semnificaţia de deplasare a biţilor din reprezentarea binară a luiA cu B poziţii la dreapta

Operatorii la nivel de biţi:Aceştia corespund operatorilor logici (boolean): ŞI, SAU, Negaţie, SAU

EXCLUSIV<OperatoriBoolean>::= & | | | ~ | ^

& - ŞI| - SAU~ - Negaţia^ - SAU EXCLUSIV

21

Page 23: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 23/166

Algoritmi şi structuri de date

Operatorii la nivel de biţi se utilizează în manevrarea biţilor din reprezentările binare ale operanzilor întregi sau caracter.

Exemplu:Fie A şi B două numere întregi ale căror reprezentări pe 16 biţi sunt:

A= 0001 0010 1010 1011 şiB= 1101 1111 0000 0101

Atunci:A&B= 0001 0010 0000 0001A|B = 1101 1111 1010 1111

Operatori de asignare (atribuire):<OperatorAsignare>::= = | += | -= | *= | /= | %= | >>= | <<= | &= | != | ̂ =

Cea mai simplă operaţie de asignare este cea formată prin construcţia:<variabilă> = <expresie>

având semnificaţia următoare: expresia din partea dreaptă a operatorului deasignare este evaluată iar rezultatul evaluării (o valoare) este atribuit variabilei din partea stângă a operatorului =.

În cazul general, când avem asignări de forma:

<variabilă> <operator> = <expresie>unde: <operator>::=+|-|*|/|%|>>|<<|&|!|^ , structură este echivalentă cu:<variabilă>=<variabilă> <operator> <expresie>

Operatorul condiţional:Este un operator ternar format din două simboluri “?” şi “:” şi folosit în construcţiide forma:

<expresie1>? <expresie2>:<expresie3>Semnificaţie: expresiile 1,2,3 sunt evaluate şi valoarea de evaluare a expresieiglobale este valoarea expresiei 2 dacă expresia 1 este adevărată altfel valoareaexpresiei 3 dacă expresia 1 este falsă.Exemple: (A<B) ? A : B

(A= =0) ? “egal cu zero” : “diferit de zero”

Operatorul secvenţial “,”:Se foloseşte în construcţii de forma:

<expr1> , <expr2> , <expr3> , …. , <exprn>Expresia globală de mai sus se evaluază de la stânga la dreapta, valoarea finală estecea rezultată în urma evaluării ultimei sub-expresiiexprn.

Operatorul de conversie explicită ( cast)

22

Page 24: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 24/166

Algoritmi şi structuri de date

Efectul operatoruluicast este conversia explicită a unei expresii la un alt tip dedată decât cel implicit. Utilizarea operatorului se face prin construcţii: (tip)expresie, undetip - reprezintă tipul de date spre care se face conversia.

Expresiile de formavar=expresiesemnifică evaluarea prima dată a expresiei, şidacă tipul rezultatului obţinut este diferit de cel al variabilei, se realizeazăconversia implicitala tipul variabilei. Înconversiile explicite , operatorul cast apareîn expresii de forma:var = (tip) expresieşi prin această operaţie, variabila primeşte valoarea la care a fost evaluată expresia convertita la tipul explicittip.

C. Unităţile sintactice

Unităţile sintactice sunt elemente complexe alcătuite prin combinarea a douăsau mai multe unităţi lexicale.

C.1. ExpresiiExpresiile sunt secvenţe de operatori şi operanzi. În funcţie de tipul operatorilor utilizaţi, expresiile pot fi: expresii aritmetice, expresii logice, relaţionale, etc.Operanzii care intră în alcătuirea expresiilor pot fi:

- variabile- constante- apel de funcţii- alte expresii

C.2. InstrucţiuniInstrucţiunile sunt propoziţii care respectă regulile limbajului de programare în

care sunt redactate. Instrucţiunile pot fi simple sau compuse.

A. Instrucţiunea expresie: orice expresie urmată de caracterul; devineinstrucţiune.Sintaxa instrucţiuni expresie este următoarea:

<expresie>;Exemplu: a=b+c;

B. Instrucţiunea bloc: este formată din simbolurile { } în interiorul cărorasunt scrise alte instrucţiuni. Ordinea de execuţie a instrucţiunilor grupateeste ordinea apariţiei acestora în bloc (instrucţiunile din bloc se execută secvenţial ):Sintaxa:

{<instrucț iune_1><instruc iune_2>ț…<instruc iune_n>ț

}Rolul acestei instrucţiuni este de a grupa mai multe instrucţiuni simple,compuse sau alte instrucţiuni bloc.

23

Page 25: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 25/166

Algoritmi şi structuri de date

C. Instrucţiunile de ramificare- corespund structurilor alternative: decizie simplă şi decizie multiplă.

Instrucţiuneaif

Sintaxa instrucţiunii:if ( <expresie> )<instrucţiune_1>

else<instrucţiune_2>

sau:if ( <expresie> )

<instrucţiune_1>

Unde, instrucţiunile 1 sau 2 pot fi de asemenea instrucţiuni compuse sau blocde instrucţiuni.

Efectul instrucţiunii:<expresia> este evaluată şi dacă valoarea obţinută în urma evaluării este

diferită de 0 se execută instrucţiunea 1, altfel se execută instrucţiunea 2.Cele două instrucţiuni 1 şi 2 se exclud reciproc.Instrucţiunea IF simplă nu conţine parteaelse <instrucţiune 2>Instrucţiunea IF completă conţine ambele ramuri.

Exemple:

if (a!=0)b=1/a;

If (a>=b)maxim=a;

elsemaxim=b;

if (delta>=0){x1=(-b-sqrt(delta))/2*a;x2=(-b+sqrt(delta))/2*a;}

Sintaxa limbajului C permite ca în cadrul instrucţiunilor compuse ce constituie

cele două ramuri ale structurii alternative IF să existe alte structuri alternative IF. Oastfel de construcţie se denumeşte structură alternativă imbricată sau instrucţiuni IFimbricate.

Instrucţiunea switch

- reprezintă o generalizare a structurii alternative (if ).- se poate înlocui printr-o secvenţă de structuri alternative imbricate.În structura instrucţiuniiswitcheste regăsită o instrucţiune simplă de a cărei

prezenţă depinde execuţia corectă a instrucţiunii alternativeswitch. Aceastainstrucţiune are sintaxa:

break;Rolul instrucţiunii break este de a întrerupe execuţia instrucţiunii curente şi de a

trece la execuţia următoarei instrucţiuni ce urmează instrucţiunii switch.Sintaxa generală:

24

Page 26: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 26/166

Algoritmi şi structuri de date

switch (<expresie>){

case <val1> : <instrucţiune_1>; break;case <val2> : <instrucţiune_2>; break;…case <valn> : <instrucţiune_n>; break;[default : <instrucţiune_default>;] //opţional

};

Efectul instrucţiunii:- Se evaluează expresia dintre paranteze la o valoare.- Se “caută” secvenţial valoarea la care a fost evaluată expresia în lista

de valori val1, val2, …valn.- Dacă nu se găseşte nici o valoare val1, val2,…valn egală cu valoarea la

care a fost evaluată expresia se va executa, dacă este precizată,instrucţiunea default sau efectul instrucţiunii switch este nul- Dacă s-a găsit o valoare egală cu valoarea expresiei se va executa

instrucţiunea corespunzătoare şi se va părăsi structura alternativă.

Exemplu: Afişarea numelui zilei din săptămână căreia îi corespunde un număr 1,2,...,7:

switch (numar){

case 1: printf(\n Luni”);break;case 2: printf(\n Marti”); break;case 3: printf(\n Miercuri”); break;case 4: printf(\n Joi”); break;case 5: printf(\n Vineri”); break;case 6: printf(\n Sambata”); break;case 7: printf(\n Duminica”); break;default:printf(\n nu este numar 1,2,3,4,5,6,7”);

}

D. Instrucţiunile de ciclareÎn pseudocod am evidenţiat cele trei tipuri de structuri repetitive. Acestora le

corespund trei instrucţiuni de ciclare în limbajului C:Structura repetitivă precondiţionată -> instrucţiuneawhileStructura repetitivă postcondiţionată -> instrucţiuneado … whileStructura repetitivă cu număr prefixat de repetări -> instrucţiuneafor

InstrucţiuneawhileSintaxa:

while(<expresie>) //antetul instrucţiunii<instrucţiune> //corpul instrucţiunii

25

Page 27: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 27/166

Algoritmi şi structuri de date

unde: <instrucţiune> poate fi o instrucţiune simplă, compusă, şi poate conţinealte instrucţiuni while, caz în care spunem că avem o instrucţiune while imbricată

Efectul instrucţiunii:În primul pas, se evaluează expresia dintre paranteze. Dacă rezultatul evaluării

este o valoare non-nulă (adevărat ) se execută instrucţiunea din corpul while şi procesul se reia prin reevaluarea expresiei. Dacă rezultatul unei evaluări este nul, seîntrerupe execuţia instrucţiunii while, şi programul se continuă cu următoareainstrucţiune ce urmează instrucţiunii while.

Simplificat, o instrucţiune while are semnificaţie:“Cât timp expresia este adevărată repetă corpul de instrucţiuni”

Observaţie: corpul instrucţiunii while este posibil să nu se execute nici o dată, însituaţia în care expresia evaluată este de la început falsă.Exemplu 1:Se tipăreşte valoarea unui contor până când acesta devine mai maredecât 10. Valoarea iniţială a contorului este 0.

i=0;while (i<=10)

{printf (“%d”, i);i++;}

Exemplu 2:Se calculează suma primelor 10 numere naturale, respectiv: 1+2+3+…+10

i=1;s=0; //iniţializareawhile (i<=10)

{s=s+i;i++;}

Instrucţiuneado…while

Sintaxa:do<instrucţiune> //corpul

while (<expresie>);

<instrucţiune>: poate fi o instrucţiune simplă, compusă, şi poate conţine alteinstrucţiuni do…while, caz în care spunem că avem o instrucţiune repetitivăimbricată.

Efectul instrucţiunii do…while:- în primul pas se execută corpul instrucţiunii do…while- Se evaluează expresia dintre paranteze

26

Page 28: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 28/166

Algoritmi şi structuri de date

- dacă rezultatul evaluării expresiei este adevărat se reia procesul prinexecuţia corpului instrucţiunii, în caz contrar se încheie execuţiainstrucţiunii do…while

Semnificaţie:“Execută blocul de instrucţiuni până când expresia devine falsă”

Observaţie: corpul unei instrucţiuni repetitive postcondiţionate se execută cel puţino dată. (chiar dacă expresia este falsă de la prima evaluare).

Exemplu 1. Citeşte un caracter de la tastatură până când se introduce caracterul‘0’.

do{

scanf(“%c”,&caracter);}

while (caracter<>’0’);

Exemplu 2.Calculează suma unor numere întregi citite de la tastatură până laintroducerea unui număr negativ sau zero:

suma=0;do{

scanf(“%d”, &nr); //citeste numărul curentsuma=suma+nr;

} while (nr>0) ;

Exemplu 3:Programul următor citeşte un text (terminat prin Enter ) şi afişeazănumărul de vocale din compunerea textului.

#include <stdio.h>void main(){

char t; //caracterul curentint contor=0;printf("Introduceti textul: ");do

{scanf("%c",&t); //citire caracter cu caracter textulif ((t=='a')||(t=='e')||(t=='i')||(t=='o')||(t=='u'))

contor++;} while (t!=10); //10 – este codul ASCII pentru Enter

printf("Numarul de vocale: %d",contor);}

Instrucţiuneafor

Sintaxa:for ( <expresie1> ; <expresie2> ; <expresie3> )<instrucţiune>

27

Page 29: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 29/166

Algoritmi şi structuri de date

Unde:- cele trei expresii din antetul instrucţiunii sunt separate prin

caracterul;- <instrucţiune> poate fi simplă, compusă sau poate conţine o

altă instrucţiune repetitivă for.- <expresie1> - reprezintă expresia de iniţializare. (iniţializareacontorului)

- <expresie2> - reprezintă o expresia ce este evaluată şi de acărei valori de evaluare depinde repetarea corpuluiinstrucţiunii.

- <expresie3> - reprezintă expresia de actualizare (actualizareacontorului)

Efect:- În primul pas, se evalueazăexpresia1, respectiv se execută secvenţa de

iniţializare- Se evalueazăexpresia2(această expresie are acelaşi rol ca <expresie> din

structura while sau do…while )- Dacă rezultatul evaluării anterioare este adevărat se executăcorpul

instrucţiuniifor şi apoi se execută secvenţa de actualizare specificată prinexpresie3

- Dacă rezultatul este fals, se încheie execuţia for.

Exemplu 1:Afişarea primelor 10 numere naturale.

for ( i=1; i<=10; i++)printf(“\n %d”, i);

Exemplu 2:Calcularea lui n!

fact=1;for (i=1;i<=n;i++)

{fact=fact*i;}

E. Apelul funcţiilor de intrare - ieşire

Operaţiile de intrare-ieşire (citirea datelor de intrare şi afişarea rezultatelor) nuse realizează prin instrucţiuni ale limbajului C, ci prin apelarea unor funcţiispeciale, definite înbibliotecilede funcţii ale limbajului C.

Funcţiile printf , scanf

- printf şi scanf sunt funcţii predefinite de intrare–ieşire definite în biblioteca stdioPentru a putea folosi aceste funcţii într-un program C este necesară în prealabil

specificarea prin directivă de preprocesare a fişierului antet (header ) ce conţine prototipurile acestora:

#include <stdio.h> //la începutul programului sursă

28

Page 30: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 30/166

Algoritmi şi structuri de date

Prin apelul funcţiei printf se realizează afişarea pe ecran a mesajelor, datelor,valorilor unor variabile sau rezultate finale sau intermediare ale programului.

Sintaxa apelului funcţiei printf :printf(“sir de formatare”, expr1, expr2, …)

unde:- expr1, expr2, … sunt expresii separate prin virgulă şi pot reprezenta

variabile, constante sau orice expresie evaluabilă (aritmetică, logică,relaţională, etc.)

- sir de formatareeste încadrat de caracterele ghilimele “ ” şi reprezintăforma sub care vor fi tipărite pe ecran valorile expresiilor.

Efect: prin apelul funcţiei printf se realizează afişarea pe ecran a datelor într-unanumit format.

Sir de formatarepoate conţine doar text şi lista de expresii poate fi vidă, caz încare prin apelul funcţiei printf se tipăreşte pe ecran textul specificat în acest cîmp.Exemple:

printf(“exemplu de program!”) printf(“\n acest text este afisat pe ecran”)

În general sir de formatarepoate conţine:- Text- Specificatori de format- Secvenţe escape

Secvenţele escape sau comenzi de control pot fi de două tipuri: secvenţenegrafice şi secvenţe grafice sau afişabile. Numărul specificatorilor de format esteegal cu numărul de expresii separate prin virgulă. Fiecare specificator de format sereferă la modul de redare a valorii expresiei de pe poziţia corespondentă:

Secvenţele escape negrafice:

\n – trecere la linie nouă\t – deplasare la dreapta cu un tab\b – deplasare la stânga cu o poziţie\r – revenire la începutul rândului\f – trecere la pagina următoare\a – semnal sonor

Secvenţele escape grafice:\’ – afişare apostrof \” – afişare ghilimele\\ - afişare backslash\xCC – afişare caracterul al cărui cod ASCII în hexazecimal este dat prinsecvenţa CC de cifre în baza 16.

Specificatorii de format<specificator de format>::= % [-] [m.[n]] [l] <conversie><conversie>::= d|o|x|X|u|s|c|f|e|E|g|G

29

Page 31: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 31/166

Algoritmi şi structuri de date

- caracterul – dacă apare semnifică cadrarea la stânga a rezultatuluicorespunzător specificatorului curent

- m - specifică numărul minim de caractere ale datei ce va fi afişate

- .n - semnifică în cazul datelor numerice numărul de cifre după punctulzecimal- l - semnifică conversie din formatul internlong în formatul extern.

Conversie specifică tipul de conversie din formatul intern (reprezentareainternă) în cel extern (cum va fi afişat):

d – întregint cu semno – întreg în octalx, X – întreg în hexazecimal (litere mici sau MARI pentru cifrele a,b,…f respectiv A,B,…F)u – întreg fără semn (unsigned)c – din codul ASCII al reprezentării binare interne -> caracteruls – din şirul de coduri ASCII -> şirul de caracteref – conversie din float sau double în formatul extern zecimale,E - conversie din float sau double în formatul cu mantisă şi exponentg,G – conversiile de la f şi E sau f şi e dar alegerea se face pentru numărulminim de poziţii

Exemple:

printf(“valoarea intreaga a= %d”,a); printf(“realul a= %5.2f”,a);

printf(“%d + %d = %d”,a,b,a+b);

printf(“suma este %4.4f” , suma);

Sintaxa apelului funcţiei scanf :

printf(“sir de formatare”, adr1, adr2, …)Efect:prin apelul funcţiei scanf se realizează citirea de la tastatură datelor într-un anumit format.

Şirul de formatareare aceeaşi semnificaţie ca şi la funcţia printf .Şirul de adrese: adr1, adr2,…adrn se asociază specificatorilor de format

păstrând ordinea. O adresă se specifică prin precedarea numelui variabilei deoperatorul unar adresă notat &. Astfelvar este numele unei variabile, iar &var esteadresa de memorie la care se stochează valoarea variabilei.

Excepţie: nu se utilizează operatorul adresă în cazul în care variabila este o

variabilă specială pointer , respectiv când numele variabilei este o adresă dememorie.

Exemple:

30

Page 32: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 32/166

Algoritmi şi structuri de date

scanf (“%d”, &x);

scanf (“%d %d %f”,&a,&b,&x);

scanf(“%d %d %d”, &x[0], &x[1], &x[2]);

scanf(“%s %s %d”, nume, prenume, &varsta);

Structura unui program C

Redactarea unui program în limbajul C este liberă atâta timp cât se respectăregulile sintactice, semnele de punctuaţieşi se folosescconstrucţiile specificeînmod corect. Programul C este constituit dintr-o secvenţă de instrucţiuni, într-oordine determinată, corespunzător algoritmului de rezolvare a problemeiconsiderate. Instrucţiunile programului pot fi instrucţiuni de declarare sau definirea unor variabile, funcţii şi instrucţiuni care se regăsesc în corpul funcţiilor.

Structura unui program Ceste următoarea:

<program>::= [<directive de procesare>][<instrucţiuni de declarare a variabilelor globale>]<funcţii>

Directivele de preprocesare: sunt numite şi comenzi de preprocesare şi apariţielor în program nu este obligatorie. Sunt marcate prin simbolul # (diez) care le precede.

Exemplu:/* includerea bibliotecii standard de funcţii de intrare-ieşire */

#include <stdio.h>

Instrucţiuni de declarare a variabilelor globale: opţional; Anumite variabilesunt folosite în cadrul mai multor funcţii, având o utilizare globală., fapt pentrucare aceste variabile sunt declarate în secvenţa de declarare a variabilelor cucaracter global (în afara oricăror funcţii ale programului).

Funcţii:sunt unităţi independente ale unui program prin care se reprezintă unsubalgoritm (procedura, modul) al unui algoritm de rezolvare a unei probleme date.

Clasificare funcţii:1. Funcţii standard – au nume prestabilit, sunt constituite în biblioteci defuncţii standard2. Funcţii utilizator – au nume ales de către utilizator şi sunt construite decătre acesta3. Funcţia principală (main)

Un program C conţine obligatoriu funcţia principalămain. Putem avea maimulte funcţii utilizator declarate şi definite sau alte funcţii standard ce sunt apelatedar în prealabil au fost incluse, prin directive de preprocesare, bibliotecile din carefac parte.

31

Page 33: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 33/166

Algoritmi şi structuri de date

Sintaxa funcţiei main:void main (void){

//declaraţii locale//instrucţiuni…

}

Exemplu de program C:#include <stdio.h> //rezolvarea ec. de gradul II#include <math.h>

void main(void){double a,b,c,x1,x2,delta;printf("\nDati coeficientii ecuatiei de gradul II: ");scanf("%lf,%lf,%lf",&a,&b,&c);if (a==0)

{if (b==0)

printf("ecuatie imposibila!");else

{ x1=-c/b;printf("Solutia ecuatiei de grad I: %lf",x1);

}}

else{ delta=b*b-4*a*c;

if (delta>=0){

x1=(-b-sqrt(delta))/2*a;x2=(-b+sqrt(delta))/2*a;printf("Solutiile ec. gr. II: %lf, %lf",x1,x2);

}else

printf("Ecuatia de gr. II nu are solutii reale!");}

}

Probleme:1. Să se citească un sir de n numere întregi de la tastatură şi să se calculeze sumaacestora.2. Să se citească n numere întregi şi să se numere câte elemente sunt pozitive.3. Să se scrie un program C pentru afişarea relaţiei dintre două numere: < , > sau =.4. Scrieţi un program C pentru rezolvarea ecuaţiei de gradul II

32

Page 34: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 34/166

Algoritmi şi structuri de date

Obs. Pentru scrierea unui program care rezolvă ecuaţia de gradul 2 este necesarăcunoa terea funcţiei de extragere a radicalului: sqr(<parametru>) al cărei prototipș se află în bibliotecamath.h5. Să se scrie un program C care citeşte două numere reale şi un caracter: + , - , /sau * şi afişează rezultatul operaţiei aritmetice corespunzătoare.6. Să se scrie un program C care afişează toţi multiplii dek mai mici decât ovaloare datăn.7. Să se scrie un program C care calculează şi afişează puterile lui 2 până la n,adică 2, 22,23, …, 2n .

33

Page 35: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 35/166

Algoritmi şi structuri de date

III. FUNCTII. TRANSMITEREA PARAMETRILOR.RECURSIVITATE.

Funcţia reprezintă o unitate de sine stătătoare a unui programului C, prinintermediul căreia se descrie un subalgoritm de rezolvare a unei subprobleme.Într-un capitol precedent am subliniat importanţa subalgoritmilor în descrierea

unor metode de rezolvare a problemelor. Programele C permit o traducere adescrierilor algoritmice bazate pe subalgoritmi prin posibilitatea definirii unor funcţii utilizator care tratează aspecte parţiale ale rezolvării. Un program C poateconţine funcţia principalămaindar şi alte funcţii definite de către programator saufuncţii predefinite din bibliotecile standard.

Limbajul C este suplimentat prinbibliotecicare conţin funcţii înrudite prinintermediul cărora se realizează diferite operaţii. Aceste funcţii de biblioteci pot fiapelate în programele dezvoltate dacă în prealabil s-a inclus bibliotecacorespunzătoare prin directive de preprocesare#include. (spre exemplu funcţiilestandard scanf şi printf ale bibliotecii stdio)

Funcţiile definite de utilizator au următoarea sintaxă:

<tip> NumeFuncţie (<tip1><arg1>,…,<tipn><argn>){<instrucţiuni de declarare de tip a variabilelor locale>

……………<instrucţiuni>……………}

- Corpul funcţieicuprinde între acolade {} conţine partea de declarare avariabilele locale funcţiei respective şi partea de prelucrare a datelor:secvenţă de instrucţiuni prin care se prelucrează variabilele locale saualtele cu caracter global.

- În antetul unei funcţii este precizattipul de dată pe care îl returnează<tip>. Acesta poate fivoid , caz în care funcţia nu returnează nimic.

- Parantezele rotunde (….) ce urmează numelui funcţiei delimiteazălistaargumentelor funcţiei.

- Fiecărui argument îi este precizattipul şi numelesub care este referit încadrul funcţiei curente.

Prototipul funcţiei: este format de antetul funcţiei din care poate să lipseascănumele parametrilor formali:

<tip> NumeFuncţie (<tip1>,…,<tipn>) ; //declararea unei funcţiiLa definirea unei funcţii, argumentele precizate în antetul acesteia se numesc

parametrii formali. La apelul funcţiei, parametrii formali sunt înlocuiţi deparametrii actuali:

Apelulunei funcţii se face prin construcţia:

34

Page 36: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 36/166

Algoritmi şi structuri de date

NumeFuncţie (pa1, pa2, … , pan);

Categorii de funcţii:

1. Funcţie fără tip şi fără parametrii

Există posibilitatea definirii de către utilizator a unor funcţii care nureturnează nimic şi lista parametriolor acestora este vidă:

void NumeFuncţie(){… //corpul functiei}

Apelul funcţiei se face printr-o construcţie de forma: NumeFuncţie();

Exemplu: Se defineşte o funcţieCifrecare tipăreşte cifrele arabe. Funcţiava fi apelată în funcţiamain.

#include <stdio.h>

void Cifre(){int i; //declaraţie de variabilă localăfor(i=0;i<=9;i++) printf(“%d”,i);}

void main(void){Cifre(); //apelul functiei Cifre}

2. Funcţii cu tipDacă unei funcţii îi este precizat tipul (diferit devoid ) acest lucru ne spune

că funcţia returnează codului apelant o valoare de acest tip. În caz contrar, funcţianu returnează valoare. Tipul funcţiei reprezintă în fapt tipul de dată al valorii pecare o returnează. Instrucţiuneareturn, folosită în cadrul funcţiei cu tip definite,are sintaxa:

return <expresie>;şi are rolul de a reveni în programul apelant ş de a returna acestuia o valoare detipul precizat.

Funcţia poate fi apelată printr-o instrucţiune de asignare:ValoareReturnată= NumeFuncţie();//membrul stâng al instrucţiunii este o

variabilă de tipul returnat de funcţie

35

Page 37: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 37/166

Algoritmi şi structuri de date

Exemplu: Programul C conţine o funcţieCitireValoare,care citeşte o valoarenumerică întreagă de la tastatură şi returnează această valoare funcţiei mainapelantă, pe care aceasta o va afişa pe ecran.

#include <stdio.h>

int CitesteValoare (){int numar; //declaraţie de variabilă localăscanf(“%d”,&numar);return numar;}

void main(void){

int valoare;valoare=CitesteValoare();//apelprintf(“valoarea este: %d”,valoare);}

void main(void)//varianta compacta

{printf(“valoarea este: %d”,CitesteValoare() );}

3. Funcţii parametrizateFuncţiile cu parametri corespund acelor subalgoritmi care prelucrează date de

intrare reprezentând rezultate intermediare ale algoritmului general. Intrărilefuncţiei sunt descrise prinlista parametrilor formalice conţine nume generice aledatelor prelucrate în corpul funcţiilor. Parametrii efectivi sunt transmişi la apelulfuncţiilor, aceştia înlocuind corespunzător parametrii generici specificaţi. Înlimbajul C transmiterea parametrilor actuali funcţiilor apelate se face prin valoare:înţelegând prin aceasta că valorile curente ale parametrilor actuali sunt atribuite parametrilor generici ai funcţiilor.

Exemplu:int minim(int a, int b){ return ( (a>b)?a:b) }

//apelul din functia mainint nr1,nr2, min;nr1=7; nr2=6;min=minim(nr1,nr2); // la apela va primi valoarea 7 şib – valoarea 6min=minim(nr2,nr1); // la apela va primi valoarea 6 şib – valoarea 7

Fie funcţia:tip NumeFuncţie (tip1 pf 1, tip2 pf 2, … , tipn pf n){…};

La apelul: NumeFuncţie (pa1, pa2, … , pan);se vor transmite prin valoareparametrii actuali şi fiecare parametru formal din

antetul funcţiei este înlocuit cuvaloarea parametrului actual. Dacă parametrul

36

Page 38: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 38/166

Algoritmi şi structuri de date

actual este o expresie, aceasta este evaluată la o valoare, ulterior este copiată în parametrul formal corespunzător.

Observaţie: modificările aduse parametrilor formali în cadrul funcţieiapelate nu afectează valorile parametrilor actuali. Exempul următorevidenţiază acest aspect:

#include <stdio.h>

void putere(int n) //ridică la pătrat valoarea n şi afişeazărezultatul{

n=n*n;printf(“ valoarea lui n in functie este %d”,n); //n este 25

}void main(void){

int n=5;printf(“ valoarea lui n inainte de apel este %d”,n);// efectul: valoarea lui n inainte de apel este 5putere(n);// efectul: valoarea lui n in functie este 25printf(“ valoarea lui n dupa de apel este %d”,n);// efectul: valoarea lui n dupa de apel este 5 (!nu s-a

modificat parametrul actual)}

În multe situaţii este necesar ca efectul operaţiilor din corpul unei funcţii apelateasupra parametrilor de intrare să fie vizibil şi în corpul apelant. În exemplulanterior efectul dorit este acela ca variabilan după apel să păstreze rezultatulridicării la pătrat. Transmiterea prin valoare nu permite acest lucru. În schimb,transmiterea prin adresă realizată prin intermediul variabilelor de tip pointer asigură modificarea valorilor parametrilor actuali.

Pentru a înţelege mecanismultransmiterii parametrilor prin adresă în limbajulC, vom defini în continuare noţiunea de pointer .

Pointeri

Pointer= variabilă care are ca valori adrese de memorie.Sintaxa de declarare a unei variabile pointer:

tip * p; //variabilă pointer spre tipPrin această declaraţie s-a introdus o variabilă ale cărei valoare este adresa unei

zone de memorie ce poate reţine o dată de tipultip.Fie x o variabilă simplă de tipul tip:tip x;

şi p un pointer (variabilă de tip pointer) care are ca valoare adresa variabilei x.Pentru a face o atribuire unei variabile de tip pointer p se foloseşte construcţia: p=&x; // semnificaţia:lui p i se atribuie adresa variabilei x.

37

Page 39: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 39/166

Algoritmi şi structuri de date

Variabila pointer p : AdresPrin construcţia&xne referim laadresa variabilei x.Prin construcţia *p ne referim lavaloarea variabilei x.

- Operatorul* se numeşteoperator de indirectare- Operatorul & se numeşteoperator adresă Expresia*&x are aceiaşi semnificaţie cu expresiax.

Transmiterea parametrilor prin adresăTransmiterea prin adresăse realizează prin variabile de tip pointer şi ne

asigură de modificarea valorii parametrilor actuali.Transmiterea prin prin adresa este realizată astfel:

1. Parametrii formali ai funcţiei se declară ca fiind de tippointer;tip NumeFuncţie (tip1*p1, tip2*p2, … , tipn*pn){…};

2. La apel, argumentele funcţiei suntadreseleparametrilor actuali; NumeFuncţie (&p1, &p2, … ,&pn)

Exemplu:#include <stdio.h>

void putere(int *p ) //ridică la pătrat valoarea n şi afişeazărezultatul{

*p =*p * *p ;//ridică la pătrat valoarea referită de p : *p printf(“ valoarea lui n in functie este %d”, *p ); //n este 25

}

void main(void){

int n=5;printf(“ valoarea lui n inainte de apel este %d”,n);// efectul: valoarea lui n inainte de apel este 5putere( &n);// efectul: valoarea lui n in functie este 25printf(“ valoarea lui n dupa de apel este %d”,n);

// efectul: valoarea lui n dupa de apel este 25 (!s-amodificat parametrul actual)}

38

Page 40: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 40/166

Algoritmi şi structuri de date

Exerciţiu: Să se scrie o funcţie care interschimbă valorile a două variabiletransmise ca parametrii.

Pentru construirea funcţiei cerute este utilă transmiterea prin adresă, deoarece,efectul interschimbării trebuie să fie vizibil şi în codul apelant. Prezentăm încontinuare două variante de implementare, prima dintre acestea foloseştetransmiterea implicită prin valoare, fapt pentru care nu corespunde rezultatuluidorit. Cea de-a doua este varianta corectă, folosindu-ne detransmiterea parametrilor prin adresă (prin pointeri).

void interschimbare(int a, intb){int auxiliar;auxiliar=a;a=b;b=auxiliar;}

void interschimbare(int *a,int *b){int auxiliar;auxiliar=*a;*a=*b;*b=auxiliar;}

//Apelul:int x,y;x=1;x=2;interschimbare(x,y)

//Apelul:int x,y;x=1;x=2;interschimbare(&x,&y)

//EfectulInainte de apel:x=1y=2

După apel:x=1y=2

//EfectulInainte de apel:x=1y=2

După apel:x=2y=1

Probleme:

1. Dezvoltaţi un program C care determină minimul dintr-un şir de numerecitite de la tastatură (fără a utilizatablouri), punând în evidenţă funcţia caredetermină minimul dintre două valori.

2. Scrieţi o funcţie care rezolvă ecuaţia de gradul II. Funcţia va avea 5argumente: coeficienţii ecuaţiei (a,b,c) şi posibilele soluţii (x1,x2). Funcţiareturnează un număr întreg cu semnificaţia:

- -1, ecuaţia nu este de gradul II- 0 , ecuaţia are soluţii complexe- 1, ecuaţia are soluţii reale

Primii trei parametrii se transmit prin valoare, ultimii doi - prin adresă.

39

Page 41: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 41/166

Algoritmi şi structuri de date

RECURSIVITATE

Recursivitatea se obţine prin instrucţiunea de apel a unei funcţii în corpuldefinirii funcţiei respective:

<tip> NumeFuncţie (<tip1><arg1>,…,<tipn><argn>){<instrucţiuni de declarare de tip a variabilelor locale>……………<instrucţiuni>……………

NumeFuncţie (pa1, pa2, … , pan); //auto apelul funcţiei……………}

La fiecare apel al funcţiei recursive, pe stiva programului sunt depuse noul setde variabile locale (parametrii). Chiar dacă variabile locale au acelaşi nume cu celeexistente înainte de apelarea funcţiei, valorile lor sunt distincte, şi nu existăconflicte de nume. Practic, ultimele variabile create sunt luate în considerare înoperaţiile conţinute de funcţie.

Problemă 1:Să se calculeze P(n)=n! printr-o funcţie recursivă. Analiza problemei: Pornind de la observaţia că produsul P(n)=1*2*…(n-1)*n se

mai poate formula ca:P(n)=P(n-1) * n, vom defini o funcţie factorial care tratează problemadeterminării lui P(k) pe baza formulei anterioare, presupunând că P(k-1) estecalculabil după acelaşi procedeu. P(k-1)=P(k-2)*(k-1).

Funcţia autoapelantă trebuie să conţină o condiţie de terminare a recursivităţii.În problema calculului n!, condiţia de terminare a recursivităţii se deduce dinobservaţia că 1! are valoarea 1, ceea ce nu mai necesită un calcul suplimentar.

Apelul iniţial al funcţiei factorial se va face pentru parametrul actualn-reprezentând data de intrare a programului. Funcţia returnează la ieşirea din apelrezultatul dorit n!.

int factorial(int k){if (k>1)

return (k*factorial(k-1));else

return 1;}…//apelul functiei

int p;p=factorial(n);

Execuţia pas cu pas:

40

Page 42: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 42/166

Algoritmi şi structuri de date

Considerămn=31. La apelul iniţial factorial(n)se transmite valoarea 3 parametrului formalk şi

se predă controlul funcţiei apelate2. Din condiţia adevărată 3>=1 rezultă amânarea revenirii din funcţie şi un

nou apel factorial(2); la ieşirea din primul apel se va return 3*factorial(2).3. Apelul factorial(2) va produce transmiterea valorii 2 la parametrul formalk şi predarea controlului funcţiei apelate pentru valoarea curentă a parametrului

4. Condiţia adevărată 2>=1 produce o nouă apelare factorial(1)cu amânarearevenirii din apelul curent; la ieşirea din acest al doilea apel se va return2*factorial(1).

5. Apelul factorial(1) va produce transmiterea valorii 1 la parametrul formalk şi predarea controlului funcţiei apelate pentru valoarea curentă a parametrului

6. Din condiţia falsă1>1 rezultă că la ieşirea din acest apel se va return1 şi funcţia nu se mai apelează .

7. Revenirea din ultimul apel este urmată de revenirile în cascadă din apelurile precedente în ordinea inversă, ceea ce conduce la rezultatul 3*2*1 = 6.

factorial n n*

n* (n

Recursivitatea poate fi de mai multe feluri, în funcţie de numărul de apeluriconţinute de funcţia (subalgoritmul) recursivă:

1. recursivitate liniară: funcţia conţine cel mult un autoapel -exemplu funcţia factorial descrisă anterior 2. recursivitate neliniară: funcţia conţine două sau mai multe apeluri

recursive – exemplu fibonaccidescris în continuare

Problema 2: Se cere determinarea celui de-al n-lea termen din şirul luiFibonacci.

Analiza problemei:Se cunoaşte că:

- primii doi termeni ai şirului sunt 0,1:o Fibonacci(0)=0o Fibonacci(1)=1

- oricare termen este format prin însumarea celor doi termeni precedenţi:

41

Page 43: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 43/166

Algoritmi şi structuri de date

o Fibonacci(k)=Fibonacci(k-1)+ Fibonacci(k-2)Funcţia recursivă este:

int Fibonacci(int k){

if (k<=1) return k;else

return Fibonacci(k-2) + Fibonacci(k-1); //douăautoapeluri}

Problema 3.Determinarea celui mai mare divizor comun a două numere a şi b.(prin funcţie recursivă)

Analiza problemei: cmmdc(a,b) poate fi:1. a, dacăb = 0

2. cmmdc(b, a mod b), dacăb≠0Prin a mod bse înţelege restul împărţirii întregi a luia la b

Pe baza observaţiei precedente, funcţia recursivă cmmdc se construieşte astfel:int cmmdc(int m, int n){

if(n==0)

return m;returncmmdc(n,m%n); //autoapel

}

Recursivitatea este o tehnicăcostisitoaredatorită spaţiului de memorie blocat pentru reţinerea variabilelor locale create la fiecare apel. Există diferite metode deeliminare a recursivităţii din programele C, pentru a preîntâmpina acest neajuns.Descriem în continuare procedura de eliminare a recursivităţii liniare:1. Se utilizează o listă care se iniţializează ca fiind vidă. În această listă vor fi

salvaţi parametrii formali şi variabilele locale ale funcţiei recursive. Operaţiile posibile cu lista folosită sunt:adăugarea unui nou element în capătul listei şiextragereaunui element din capătul listei(vezi conceptul de stivă )

2. Câttimp condiţia de continuare a recursivităţii este adevărată execută:- Adaugă ( salvează ) în listă valorile actuale pentru parametrii

funcţiei recursive si variabilele locale- Execută instrucţiunile funcţiei recursive- Modifica valorile argumentelor funcţiei recursive (actualizarea

parametrilor)3. Dacă la terminarea pasului 2 lista nu este vidă, se extrage mulţimea de

variabile din capătul acesteia, se calculează valoarea dorită şi se executainstrucţiunile ce apar după apelul funcţiei recursive, apoi se trece la pasul 2.Dacă lista este vidă se termină execuţia algoritmului.

42

Page 44: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 44/166

Algoritmi şi structuri de date

IV. TABLOURI. TEHNICI DE SORTARE.

Tablourile în limbajul C suntvariabile cu indici. Pot fi de două categorii,tablouri unidimensionale (vectori) sau multidimensionale. La nivel abstract, untablou unidimensional se poate defini ca o listă ordonată de n valori de acelaşi tip: x1,x2, … ,xn. Fiecare poziţiei din cadrul tabloului conţine elementul xi, respectiv ovaloare de tipul specificat.

Declararea unuitablou unidimensionalîn limbajul C se face astfel:<tip> NumeTablou [NumarElemente];

Unde <tip> este tipul de date al elementelor tabloului, NumarElemente este unnumăr natural sau o constantă cu valoare întreagă pozitivă prin care se precizează

numărul elementelor din tablou, NumeTablou este un identificator prin care estedenumit vectorul.- Referirea unui element al tabloului se foloseşte numele tabloului şi indicelecorespunzător. Spre exemplu:int x[100];- Pentru a referi elementul de pe poziţia i vom scrie x[i-1], dat fiind faptul că primul element al şirului este x[0].- Tablourilor li se asociază locaţii de memorie consecutive, de aceeaşilungime în care sunt stocate valorile fiecărui element.- Observaţie: numele tabloului (spre ex.x) este o variabilă a cărei valoareeste adresa de memorie a primului element din şir (pointer).

Declarareatablourilor n-dimensionale:<tip> NumeTablou [N1] [N2] …[Nn];

Unde N1, N2 … Nn reprezintă numărul de elemente pe fiecare dimensiune.- Referirea unui element al tabloului multidimensional se face prinidentificatorul tabloului (numele) şi specificarea poziţiei pe fiecaredimensiune:- NumeTablou [i1] [i2] …[in].

Exemplu:

int A[20] [30];//declararea uneimatrice(tablou bi-dimensional) de 20 linii si 30 coloane.- Primul element al tabloului bidimensional declarat mai sus este A[0][0], iar numele tabloului conţine adresa primului element memorat.

Observaţie: Numele unui tablou în C este de fapt un pointer, avînd ca valoareadresa primului sau element. La transmiterea vectorilor ca parametrii ai unor funcţii se va ţine cont de acest aspect.

Exemplu:int T[100]; //tablou de 100 intregi Numele tabloului, T - reprezintă adresa primului element al sau, respectiv,

adresa lui T[0].

43

Page 45: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 45/166

Algoritmi şi structuri de date

Tablourile sunt structuri de date:- compuse: sunt formate din mai multe elemente (de acelaşi fel)- ordonate: există o relaţie de ordine dată de poziţia elementelor în

tablou

- omogene: toate elementele unui tablou au acelaşi tipTablourile unidimensionale vor fi denumite în continuarevectori.

Pointeri şi tablouri. Operaţii cu pointeri

Între tablouri şi variabilele pointer există o strânsă legătură: numele unui tabloueste un pointer, fiind de fapt adresa primului element al tabloului respectiv:

tab

tab[0] tabExemplu:

int tab[100];//tab – este adresa elementului t[0]

Observaţie: Deoarece memoria alocată unui tablou este o zonă contiguă, respectiv,elementele tabloului sunt grupate, cunoscând adresa primului element, printr-ooperaţie elementară se poate accesa oricare alt element al tabloului.

Operaţii cu pointeri:

Asupra pointerilor se pot efectua următoarele operaţii:- incrementare/decrementare- adunarea/scădere cu un întreg- diferenţa a doi pointeri

Fie declaraţia următoare:<tip> *p; //p este un pointer la tipul <tip>

Efectul operaţiilor de incrementare/decrementare este următorul:

p++ şi ++p echivalent cu: p=p+dim p-- şi --p echivalent cu: p=p-dimunde:dim reprezintă dimensiunea exprimată în octeţi a unei variabile de tipul

<tip> Exemplu.int *p; p++;//p se măreşte cu 2, deoarece o variabilă de tipulint se memorează pe 2 octeţi

Adunarea şi scăderea unui întreg Fie: <tip> *p;

int k;Expresiile: p+k, p-k sunt expresii valide în limbajul C, având semnificaţiile

următoare:

44

Page 46: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 46/166

Algoritmi şi structuri de date

p+k - reprezintă o adresă de memorie; valoarea p+k este egală cu valoarealui p mărită cuk*dim, undedim- dimensiunea exprimată în octeţi a tipului <tip>

p-k - are valoarea p micşorată cuk*dim, undedim- dimensiunea exprimatăîn octeţi a tipului <tip>

Accesarea elementelor unui tablou poate fi făcută şi prin operaţii cu variabile pointer:

d dim octeti

tab[0] tab[1]

tab tab+1 tab

Exemplu:int tab[100]; //tablou de 100 întregiint i;

(tab) – adresa primului element tab[0](tab+1) – adresa celui de-al doilea element tab[1](tab+i) – reprezintă adresa celui de-al(i-1)-lea element al tabloului, respectiv esteadresaelementuluitab[i]*(tab+i) – reprezintăvaloareaelementuluitab[i]

Diferenţa a doi pointeri:Două variabile de tip pointer prin care se referă elementele aceluiaşi tablou potfi scăzute. Fie tabloultab şi doi pointerip şi q care adresează elementeletab[i] şitab[j]. Diferenţap-q este un număr întregk , reprezintândnumărul de elementecare desparte cele două adrese. Această dimensiune se poate determina princalculul elementar: k=(j-i).

Între adresele p şi q se află un număr de (j-i) elemente, respectiv, (j-i)*dimocteţi, undedim- dimensiunea necesară reprezentării unui element al tabloului.

tab[i] ......

dim

Şiruri de caractere

Operaţiile cu şiruri de caractere se efectuează prin apelul unor funcţii de bibliotecă specifice. Prototipurile funcţiilor care manipulează şiruri de caractere seaflă în fişierul antet string.h.

45

Page 47: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 47/166

Algoritmi şi structuri de date

Orice şir de caractere se va păstra într-o zonă de memorie contiguă. Nereamintim că unei variabile de tipulchar îi este necesară o zonă de memorie de 1octet, pentru reţinerea codului numeric corespunzător (reprezentarea internă ). Unşir de caractere, declarat ca tablou unidimensional de tipchar va ocupa o zonă denocteţi terminată printr-un octet suplimentar cu valoarea '\0’ – caracterul nul, princare s-a marcat terminarea şirului.

Ex:char sir[20];Folosind relaţia dintre tablouri şi pointeri, putem utiliza în programe declaraţii

de forma:char *psir;Accesarea caracterelor din compunerea şirului va fi posibilă prin variabile

indexate sau prin operaţii cu pointeri:sir[0] sau *psir – codul numeric (ASCII) al primului caracter din sir sir[1] sau *(psir) - codul numeric al celui de-al doilea caracter din sir sir sau psir – adresa primului caracter sir+1 sau psir+1 – adresa celui de-al doilea caracter din sir

Pentru manipularea şirurilor de caractere, biblioteca standardstring.h pune ladispoziţie funcţii speciale dedicate operaţiilor specifice.

Lungime unui şir de caractereLungimea unui şir de caractere este definită prin numărul caracterelor care intră

în compunerea şirului. Funcţia standardstrlen este utilă în determinarea lungimiiunui şir de caractere: unsigned strlen(const char *s) Exemplu:

char const *psir = “text”unsigned l;l= strlen(psir); // luil i se va atribui 4

//numărul de caractere, excluzând marcatorul NULL)Copierea unui şir de caractere

- este operaţia prin care un şir de caractere sursă este copiat într-o altăzonă de memorie ataşată unui alt şir de caracteredestinaţie

- funcţia specifică este:strcpy

char * strcpy(char *destinatie, const char * sursa)

Funcţia are ca efect copierea tuturor caracterelor în zona de memorie referită dedestinatiedin zona de memorie referită de sursa. (inclusiv caracterul NULL)

Funţiastrcpy returnează la revenire adresa de început a zonei în care s-a copiatşirul (pointer-uldestinatie)

Exemplu: Interschimbarea a două şiruri de caractere:void schimb(char a[20],char b[20]){

char aux[20];

46

Page 48: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 48/166

Algoritmi şi structuri de date

strcpy(aux,a);strcpy(a,b);strcpy(b,aux);

}

Concatenarea a două şiruri de caractereSe realizează prin apelul funcţieistrcat:char * strcat(char *destinatie,const char * sursa)

Apelul funcţiei are ca efect copierea şirului de la adresa sursa în zona dememorie imediat următoare şirului de la adresadestinatie. La revenire, funcţiareturnează adresadestinaţie.

Compararea a două şiruri de caractereOperaţia de comparare a două şiruri presupune verificarea codurilor ASCII ale

caracterelor din compunerea şirurilor. Compararea şirurilor de caractere este ooperaţie utilă în probleme care cer ordonarea lexicografică a unor secvenţe de text.

char * strcmp(const char * sir1,const char * sir2)Funcţiastrcmpreturnează:- valoare negativă, dacă sir1<sir2- 0, dac ă sir1=sir2- valoare pozitivă, dacă sir1>sir2

Exemplu: Program de generare a parolelor. Pentru un cuvânt dat, parola va fiobţinută prin scrierea de la dreapta la stânga a caracterelor de pe poziţiile impare.

#include <stdio.h>#include <string.h>void main(){

char pass[20],cuv[20];int i,n;

pass[0]=NULL;

printf("dati cuv ");scanf("%s",&cuv);i=(strlen(cuv)-1);if (i%2) i--;n=0;while (i>=0){

pass[n]=cuv[i];i-=2;

n++;}pass[n]=NULL;printf("parola este %s",pass);

}

47

Page 49: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 49/166

Algoritmi şi structuri de date

Operaţiile specifice cu vectori sunt:1. parcurgerea

a. pentru accesarea şi/sau modificarea elementelor (citirea şi

afişarea) b. pentru numărarea elementelor ce verifică o condiţie2. căutarea secvenţială3. minimul/maximul dintr-un vector4. inserarea şi ştergerea unui element pe o poziţie dată5. concatenarea a doi vectori6. interclasarea a doi vectori7. sortarea

a. sortarea prin selecţie b. sortarea prin numărarec. sortarea prin metoda bulelor (prin interschimbare)

Alte variante de sortare vor fi descrise în capitolele dedicate metodelor de programare (ex. sortarea rapidă şi sortarea prin interclasare)

1. Parcurgerea tablourilor

//Parcurgerea tablourilor –citirea şi afişarea unui vector

void citire_tablou(int t[], int *n){int i;printf(“dati dimensiunea tabloului:”); scanf(“%d”,n);for(i=0;i<*n;i++)

scanf(“%d”, &t[i]);}

void afisare_tablou(int t[], int n){int i;for(i=0;i<n;i++)

printf(“%d”, t[i]);}…int tablou[30];int dim_tablou10;

citire_tablou(tablou, &dim_tablou);//apelul funcţiei de citire tablou

afisare_tablou(tablou, dim_tablou);//apelul funcţiei de afişare tablou

Legătura dintre pointeri şi tablouri influenţează maniera de transmitere atablourilor ca parametri unei funcţii. Oferim o altă variantă de funcţie care citeşte

48

Page 50: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 50/166

Algoritmi şi structuri de date

un tablou unidimensional, în care se folosesc expresii cu pointeri, iar parametrulformal este declarat ca pointer:

void citire_tablou_II(int *pt, int *n){int i, valoare;printf(“dati dimensiunea tabloului:”); scanf(“%d”,n);for(i=0;i<*n;i++)

{scanf(“%d”, &valoare);*(p+i)=valoare;}

}

//Parcurgerea tablourilor – numărarea elementelor ce verifică o condiţie dată

int numara_pozitive(int t[], int n){int i, contor;contor=0;for(i=0;i<n;i++)

if (t[i]>0)contor++;

return contor;}

2. Căutarea secvenţială- operaţia de căutare presupune parcurgerea element cu element a vectorului, înordinea dată de indecşi//Căutarea : determinarea poziţiei pe care se află valoarea căutatăint cauta_cheie(int t[], int n, int cheie)

{int i;for(i=0;i<n;i++)

if (t[i]==cheie)

return i; //poziţia valorii căutatereturn -1;//dacă nu s-a găsit valoarea se întoarce -1}

3. Determinarea minimului/maximului dintr-un vector

Principiul este următorul:- se presupune că elementul de pe prima poziţie din vector este minimul- se parcurge vectorul element cu element (de la a 2-a poziţie, până la

ultima), comparându-se minimul presupus cu valoarea curentă dinvector

- dacă elementul curent este mai mic decât minimul presupus, se vaactualiza valoarea minimului, în caz contrar se trece la următorulelement fără a altera minimul presupus

49

Page 51: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 51/166

Algoritmi şi structuri de date

Pentru determinarea maximului procedeul este similar, modificându-se doar operatorul logic utilizat în condiţia de actualizare a maximului presupus.

Algoritmul descris în pseudocod pentru determinarea minimului dintr-un vector x1,x2,...,xn este următorul:

AlgoritmMinim esteCiteşte: x1,x2,...,xn, n //vectorul x de n elemente; dimensiunea nFiemin=x1Pentru i de la 2 la n //se parcurge vectorul

Dacă xi<minatuncimin=xi

SfDacăSfPentruTipăreşteminSfAlgoritm

// codul sursă C corespunzător algoritmului descris//se citesc în prealabil dimensiunea şi elementele vectorului x

int x[100];int i, min, n;citire_tablou(x,&n);min=t[0];for(i=0;i<n;i++)

if (x[i]<min0)min=x[i];printf(”Minimul este:%d”, min);

4. Inserarea/ştergerea unui element

Inserarea unui element nou pe o poziţie k în vector presupune efectuareaurmătoarelor operaţii:

- mărirea dimensiunii vectorului cu 1.- mutarea cu o poziţie la dreapta a tuturor elementelor situate pe poziţiile

mai mari decâtk - inserarea propriu-zisă a noului element pe poziţia k.

Ştergereaelementului de pe poziţiak presupune operaţiile următoare:- mutarea la stânga cu o poziţie a tuturor elementelor situate la dreapta

poziţieik - micşorarea dimensiunii vectorului cu 1

5. Concatenarea a doi vectori

Rezultatul concatenării a doi vectori de dimensiunen1, respectivn2, este un altreilea vector de dimensiunen1+n2, format prin copierea elementelor primuluivector urmată de copierea elementelor celui de-al doilea vector. Concatenarea este

50

Page 52: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 52/166

Algoritmi şi structuri de date

o operaţie simplă fapt pentru care vor lăsa ca exerciţiu definirea unei funcţii C carerealizează această operaţie.Observaţie: operaţia de concatenarea diferă semnificativ de operaţia deinterclasare. 6. Interclasarea a doi vectori

Interclasareaeste procedeul prin care, pornind de la două secvenţe ordonate deelemente se formează o secvenţă care conţine toate elementele primelor două şieste ordonată.

Operaţia de interclasare se aplică asupra a doi vectori sortaţi rezultând un altreilea vector cu proprietăţile:

- conţine toate elementele vectorilor iniţiali- este ordonat

Fie X şi Y doi vectori ordonaţi crescător, de dimensiune n, respectiv m:x[1],x[2],...,x[n]y[1],y[2],...,y[m]

Se doreşte obţinerea vectorului ordonat z: z[1],z[2],...,z[p], format din toateelementele celor doi vectori de intrare.

Principiul este de a completa element cu element vectorul rezultat Z, princopierea elementelor vectorilor X şi Y păstrând relaţia de ordine. Interclasarea serealizează prin executarea următoarelor etape:

1. Cât timp mai există elemente de parcurs în ambii vectori: X,Y, aceştiase parcurg secvenţial:a. Se compară elementele curente ale celor doi vectori X şi Y, şi

cel mai mic dintre acestea se copiază în vectorul Z2. Dacă au mai rămas elemente neparcurse în vectorul X, se vor copia în

Z3. Dacă au mai rămas elemente neparcurse în vectorul Y, se vor copia în

Z

Parcurgerea vectorilor X,Y,Z presupune utilizarea a trei variabilecursor cusemnificaţia poziţiei curente în vectorul corespunzător:

Fie i – cursorul care indică poziţia curentă în vectorul XFie j – cursorul care indică poziţia curentă în vectorul YFie k – cursorul care indică poziţia curentă în vectorul Z

Algoritmul Interclasare este:Citeşten, x[1],x[2],...,x[n]Citeştem, y[1],y[2],...,y[m]Fie i=1,j=1 //poziţiile de start în vectorii de intrare

Fie k=1 //poziţia de start în vectorul rezultatCâttimp(i<=n şi j<=m)Dacăx[i]<y[j]atunci

z[k]=x[i]

51

Page 53: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 53/166

Algoritmi şi structuri de date

k=k+1 //trecere la următoarea poziţie în vectorul Zi=i+1//trecere la următoarea poziţie în vectorul X

Altfelz[k]=y[j]k=k+1 //trecere la următoarea poziţie în vectorul Z j=j+1//trecere la următoarea poziţie în vectorul Y

SfDacăSfCâttimpDacăi<natunci //au mai rămas elemente în vectorul X

Pentru w de la i la n //se copiază elementele rămase în Xz[k]=x[w]k=k+1

SfPentru SfDacăDacăj<matunci //au mai rămas elemente în vectorul YPentru w de la j la m //se copiază elementele rămase în Y

z[k]=y[w]k=k+1

SfPentru SfDacă p=k-1 // sau p=n+mTipăreştez[1],z[2],...,z[p]

SfAlgoritm // Interclasare

TABLOURIn-DIMENSIONALE

Adesea, este necesară prelucrarea datelor structurate în tablourimultidimensionale. Un caz particular este cel al tablourilor bidimensionale,cunoscute sub denumirea dematrice. Structura de matrice este reprezentată înmatematică prin:

=

mnmm

n

n

x x x

x x x

x x x

X

...............

...

...

21

22221

11211

Toate elementele unei matrice sunt de acelaşi tip şi dimensiunile matricei sereferă la numărul de linii (m) şi de coloane (n). În limbajul C, declararea uneistructuri de tablou bi-dimensional se face prin construcţia:

tipElement NumeTablou[linii] [coloane], unde:- tipElement este tipul de dat[ al elementelor - linii şi coloane – specifică dimensiunea memoriei alocate tabloului

identificat prin NumeTablouUn tablou bidimensionaleste reprezentat într-o succesiune de locaţii de

memorie referite prin acelaşi identificator ( NumeTablou). Fiecare element altabloului este referit prin poziţia sa în cadrul şirului. Poziţia este precizată prin

52

Page 54: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 54/166

Algoritmi şi structuri de date

două numere pozitive (indecşi), care reprezintă cele două dimensiuni (linie şicoloană).

Prin declaraţiatipElement NumeTablou[linii] [coloane] s-au alocat în memorieun număr de octeţi egal culinii*coloane*sizeof(tipElement ), necesari memorăriielementelor acestei structuri de date. Zonă de memorie rezervată tabloului estecontiguă.

Numele tabloului este adresa primului element memorat, accesat princonstrucţia: NumeTablou[0][0], astfel încît în prelucrările tablourilor, în mod uzualse consideră numerotarea liniilor şi a coloanelor începând de la 0.

Accesarea elementului de pe linia i, coloana j se face prin construcţia NumeTablou[i][j]. Ne reamintim că sintaxa NumeTablou[i]este echivalentă uneioperaţii cu pointeri exprimată prin expresia: NumeTablou+i. Într-o manierăsimilară, expresia NumeTablou[i][j]poate fi exprimată printr-o operaţie cu pointeri: NumeTablou+i+j.

Citirea elementelor unei matrice este posibilă prin citirea pe rînd a fiecăruielement din compunerea sa. În acest sens se vor parcurge mulţimile indecşilor delinie şi coloană prin două instrucţiuni repetitive (ciclice) imbricate. Codul C de mai jos are ca efect citirea unei matrice de numere întregi:

int mat [10][10];int i,j;printf(“\nIntroduceti nr. de linii ”);scanf(“%d”,&m);printf(“\nIntroduceti nr. de coloane ”);scanf(“%d”,&n);

for(i=0; i<m; i++)for(j=0; j<n; j++)

{printf(“\n Matrice[%d][%d] = : ”,i,j);

scanf(“%d”,& mat [i][j]);}

Afişareavalorilor unei matrici (în formatul uzual) este descrisă prin secvenţaurmătoare :

printf(“\n Matricea este: ”);for(i=0; i<m; i++){

for(j=0; j<n; j++)printf(“%d”, mat [i][j]);

printf(“\n”);}

În programele de prelucrare a matricelor este utilă implementarea funcţiilor

corespunzătoare operaţiilor de intrare –ieşire cu aceste structuri: citirea uneimatrice, afişarea unei matrice. Funcţiile respective vor avea ca parametri atâtdimensiunile tabloului (numărul de linii şi coloane) dar şi adresa primului element(numele tabloului). Parcurgerea în cadrul funcţiilor a tablourilor cu ajutorul

53

Page 55: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 55/166

Algoritmi şi structuri de date

indecşilor ascunde în fapt un calcul de adrese: cunoaşterea adresei de început azonei de memorie alocate tabloului permite accesarea tuturor elementelor sale.

În privinţa parametrilor formali, antetul funcţiei de citire poate fi exprimat:void citire (tipElement NumeTablou[Mmaxim][Nmaxim], intlinii, intcoloane)

Exemplu: Programul următor determină suma şi produsul a două matrici:

#include <stdio.h>#include <conio.h>#define DimMax 10 //numărul maxim de elemente

//pe linii si coloane

void afisare_matrice(int n,int m,int a[DimMax][DimMax]){

int i,j;for(i=0;i<n;i++)

{ for(j=0;j<m;j++)printf("%d ",a[i][j]);printf("\n");

}}

void citire_matrice(int *n,int *m,int a[DimMax][DimMax]){

int i,j;printf("\nIntroduceti nr. de linii n=");scanf("%d",n);printf("\nIntroduceti nr. de coloane m=");scanf("%d",m);printf("\nIntroduceti elementele matricei\n");for (i=0;i<*n;i++)

for(j=0;j<*m;j++){printf("a[%d,%d]=",i,j);scanf("%d",&a[i][j]);}

printf("\n");}

void suma(int n,int m, int a[DimMax][DimMax],int b[DimMax][DimMax], int c[DimMax][DimMax]){int i,j;

for(i=0;i<n;i++)for(j=0;j<m;j++)

c[i][j]=a[i][j]+b[i][j];}

void produs(int n,int m,int p, int a[DimMax][DimMax],int b[DimMax][DimMax],int c[DimMax][DimMax]){

int i,j,k;int s;for(i=0;i<n;i++)

54

Page 56: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 56/166

Algoritmi şi structuri de date

for(j=0;j<p;j++){

s=0;for(k=0;k<m;k++)

s=s+a[i][k]*b[k][j];

c[i][j]=s;}}

void main(){

int n,m,p;int a[DimMax][DimMax];int b[DimMax][DimMax];int c[DimMax][DimMax];

citire_matrice(&n,&m,a);citire_matrice(&m,&p,b);produs(n,m,p,a,b,c);afisare_matrice(n,p,c);suma(n,m,a,b,c);afisare_matrice(n,m,c);

}

ALGORITMI DE SORTARE

Sortarea reprezintă procedeul prin care o mulţime de elemente este aranjatădupă o relaţie de ordine dată.

Sortarea prin selecţieFie x1,x2,...,xn un vector den elemente.Principiul este acela de a considera subvectorul xi,…,xn şi de a determina

minimul din această secvenţă, urmând ca minimul rezultat să se interschimbe cuelementul xi. Procedeul se va repeta pentru oricarei=1,…,n-1.

Algoritm SortareSelecţie este:Citeşten, x1,x2,...,xn

Pentru i de la 1 la n-1//determină poziţia şi valoarea minimului subvectorului xi,…,xn

pozmin=imin=xi Pentru j de la i+1 la n

Dacăx j <min atunci pozmin=jmin=x j

SfDacăsfPentru//interschimbare xi cu minx pozmin=xi

55

Page 57: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 57/166

Algoritmi şi structuri de date

xi=minSfPentruSfAlgoritm

Exemplu:

/*program care citeste un vector de numere intregi,ordoneaza elementele vectorului prin metoda sortarii prin selectie

si tipareste vectorul ordonat */

#include <stdio.h>

void citireSir(int x[],int *n){int i;

printf("\ndati n=");scanf("%d",n);for(i=0;i<*n;i++)

{printf("\nX[%d]=",i+1);scanf("%d",&x[i]);}

}

void tiparireSir(int x[],int n){int i;for(i=0;i<n;i++)

printf("%d ",x[i]);}

void SSort(int x[],int n){int i,j,aux,poz;for(i=0;i<n;i++)

{//caut in sirul i .... n elementul minimaux=x[i];poz=i;for(j=i+1;j<n;j++)

if (x[j]<aux){aux=x[j];poz=j;}

//interschimb cu x[i]x[poz]=x[i];x[i]=aux;}

}

void main(){int a[100],n;

citireSir(a,&n);SSort(a,n);

56

Page 58: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 58/166

Algoritmi şi structuri de date

tiparireSir(a,n);}

Sortarea prin inserţieFie x1,x2,...,xn un vector den elemente

Principiul acestei tehnici este acela de a privi tabloul ca fiind împărţit în douăsubtablouri: x1,...,xi-1 şi xi,...,xn. Se presupune că primul subtablou este deja ordonatşi se urmăreşte inserarea elementului xi în subtabloul ordonat astfel încât dupăefectuarea inserţiei subtabloul rezultat să rămână ordonat. Acest procedeu se vacontinua privind tabloul iniţial ca două subtablouri : x1,...,xi şi xi+1,...,xn. Cunoscândcă primul subtablou este deja ordonat (ne-am asigurat de acest lucru la operaţia deinserare precedentă), se va continua cu inserarea elementului xi+1 în x1,...,xi şiobţinerea subtabloului ordonat x1,...,xi+2. Procedura se repetă până când nu mai suntelemente de inserat în subtabloul stâng.

Inserarea unui element oarecare xi presupune determinarea poziţiei în care va fidepus. Aceasta se rezumă la parcurgerea subtabloului în care se va face inserarea,de la stânga la dreapta, şi determinarea primul element xk care este mai mare decâtxi. În acel momentk devine poziţia pe care va fi depus xi. Parcurgerea subtablouluise poate face şi în sens invers, de la dreapta la stânga, însă în acest caz se vadeterminak – poziţia primului element xk care verifică condiţia că este mai micdecât xi.

Prima împărţire a tabloului este în punctuli=2, ceea ce produce un subvector format din doar elementul x1 şi subvectorul x2,...,xn. Se poate observa că primulsubtablou este deja ordonat.

Algoritm SortareInserţie este:Citeşten, x1,x2,...,xn

Pentru i de la 2 la n//inserez elementul xi în subvectorul stângx0=xi

j=i-1Câttimp(x j>x0)

x j+1=x j

j=j-1SfCâttimpx j+1=x0

SfPentruSfAlgoritm

Exemplu:Funcţia următoare realizează sortarea prin inserţie a unui vector.

void SInsert(int x[],int n){int i,j,aux,k;for(i=1;i<n;i++){

//caut pentru x[i] pozitia buna in subsirul din stanga

57

Page 59: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 59/166

Algoritmi şi structuri de date

//1.....i-1k=i-1; aux=x[i];//salvez valoarea curenta de inserat în aux while ((aux<x[k])&& (k>=0))

//primul element mai mic decat aux{x[k+1]=x[k];

k--;}// k+1 reprezinta pozitia pe care se insereaza auxx[k+1]=aux;}

}

Sortarea prin interschimbare (BubbleSort )

Metoda sortării prin interschimbare constă în parcurgerea repetată a vectoruluişi compararea pe rând a perechilor de elemente consecutive urmată deinterschimbarea valorilor acestora în situaţia în care relaţia de ordine dorită nu esteverificată.

La fiecare parcurgere se va presupune că vectorul este ordonat (marcarea acestei presupuneri se face printr-un cod), însă la determinarea unei perechi de elementeconsecutive care necesită interschimbare, presupunerea este anulată.

Algoritmul se va termina în condiţiile în care la o parcurgere anterioară,completă a vectorului, presupunerea s-a dovedit adevărată.

AlgoritmSortareInterschimbareeste//ordonare crescătoare după valorile elementelor

Citeşten, x1,x2,...,xn

RepetăOrdonat=AdevăratPentru i de la 1 la n-1

Dacăxi>xi+1 atunciCheamăInterschimbare(xi,xi+1)Ordonat=fals

SfDacăSfPentruPânăcând(Ordonat=Adevărat)

SfAlgoritm

Exemplu: Funcţia următoare realizează sortarea prin interschimbare a unui vector.

void SBubble(int x[],int n){int cod; //false sau adevaratint i,j,aux,k;do{cod=0; //presupun vectorul ordonat

for(i=0;i<n-1;i++)

58

Page 60: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 60/166

Algoritmi şi structuri de date

{if (x[i]>x[i+1])

{//Interschimb veciniiaux=x[i];

x[i]=x[i+1];x[i+1]=aux;cod=1;//am gasit vecini care nu respecta//relatia de ordine}

}}while (cod!=0);}

Probleme propuse spre rezolvare:1. Se dă o matrice cu numere întregi, de n linii şi m coloane. Să se determine

numărul elementelor pozitive din compunerea matricei.2. Se dă un tablou bidimensional de numere întregi organizat în n linii şi n

coloane (matrice pătratică). Să se ordoneze crescător elementele de pediagonala principală a matricei.

3. Fiind dată o matrice A de n linii şi coloane, formată din numere reale, săse construiască o matrice B de n linii şi m+1 coloane, ale cărei prime mcoloane sunt copiate din matricea A şi ultima coloană este formată dinvalorile sumelor elementelor de pe fiecare linie a matricei A.

4. Să se determine inversa unei matrice.5. Determinaţi cel mai mic număr pozitiv al unui vector den numere întregi.

59

Page 61: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 61/166

Algoritmi şi structuri de date

V. STRUCTURI. TIPURI DE DATE DEFINITE DE UTILIZATOR.

Datele pot fi clasificate în două categorii:

- Date simple, izolate: tipurile acestora sunt predefinite în limbajul C (ex.int. double, float, char)- Date grupate, sau structurate:tablourile şi structurile, care permit

prelucrarea globală dar şi individuală a fiecărui element al datei respective.

Structurile: reprezintă o modalitate de grupare a datelor care nu sunt neapăratde acelaşi tip (spre deosebire de tablouri). Este necesară uneori referirea la o datăcare cuprinde mai multe elemente, exempludata calendaristică , avândcomponentele: zi, luna, an.

Prin structură în limbajul de programare, înţelegem o colecţie de dateneomogene(de tipuri diferite), grupate sub un singur nume. Exista posibilitateaaccesului la fiecare componentă a structurii , cât şi posibilitatea referirii înansamblu a structurii definite.

Sintaxa declarării unei structuri:struct NumeStructură

{ <instructiuni de declarare de tip> } nume1, nume2, …, numeN;

unde:<instructiune de declarare de tip>::= <tip> <lista identificatori>

Observaţie: Identificatorii: NumeStructură , nume1, …,numeN pot sa lipseascădar nu toţi odată. Astfel:

- Dacă NumeStructură lipseşte, cel puţinnume1trebuie să apară în construcţie- Dacănume1, …, numeN lipsesc, atunci este obligatoriu ca NumeStructură se

fie prezent.- În situaţia în care NumeStructură este prezent, prin acest lucruse defineşte

un nou tip de datădenumit NumeStructură .-Dacănume1, … numeN sunt prezente ele reprezintă date de tipul nou introdus

NumeStructură .- Dacă una dintre datele din compunerea unei structuri este detipul pointer la

tipul de date introdus prin structura respectivă , numim structurarecursivă :

struct NumeStructură //structura recursivă { struct NumeStruct * data;//pointer la tipul de date struct NumeStructură

<instructiuni de declarare de tip> } nume1, nume2, …, numeN;

Exemple:

60

Page 62: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 62/166

Algoritmi şi structuri de date

struct DataCalendaristică{

int zi;int luna;int an;

} DataNasterii, DataAngajarii;

-prin această construcţie am introdus un tip nou (DataCalendaristică) şi am definitdouă variabile de tipul nou introdus (DataNasterii şi DataAngajarii)

struct {int zi;int luna;int an;

} DataNasterii, DataAngajarii;

-prin această construcţie NU am introdus un tip nou ci doar am definit douăvariabile structurate (DataNasterii şi DataAngajarii).

struct DataCalendaristică{int zi;int luna;int an;

}

…struct DataCalendaristică DataNasterii, DataAngajarii;

- prin această construcţie am definit un tip nou (DataCalendaristică) şi ulterior s-audeclarat două variabile structurate (DataNasterii şi DataAngajarii) de tipulDataCalendaristică.

Există posibilitatea declarării unor tablouri de date structurate. Spre exemplu,avem nevoie într-un program de un şir de 100 date calendaristice, pe care dorimulterior să le prelucrăm. Cum se declară un tablou de date structurate?

struct NumeStructură{<instrucţiuni de declarare de tip>}

struct NumeStructură TablouDeStructuri[N];

- prin această construcţie am declarat un tablou unidimensional de N datestructurate. Fiecare element al tabloului este reprezentat de o grupare de date. Exemplu:struct DataCalendaristică

{int zi; int luna;int an;}

61

Page 63: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 63/166

Page 64: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 64/166

Algoritmi şi structuri de date

Exemplu.struct DataCalendaristică *p;

Avem nevoie de pointeri la structuri în următoarea situaţie:- În cazul în care avem o funcţie ce prelucrează o variabilă de tipul unei

structuri, transmisă ca parametru, şi dorim ca efectul modificărilor dincorpul funcţiei apelate să se regăsească şi în functia apelanta. Spreexemplu, dorim să citim o dată de tip structură printr-o funcţie, iar valorile citite în corpul funcţiei trebuie să fie vizibile în programul apelant.

Exemplu:void Citire(struct DataCalendaristică *p)

{ int ziuaN,lunaN,anulN;scanf(“%d”,&ziuaN);(*p).zi=ziuaN;

scanf(“%d”,&lunaN);(*p).luna=lunaN;scanf(“%d”,&anulN);(*p).an=anulN;}

Struct DataCalendaristica DC;//Apelul functiei :Citire(&DC);

Pentru simplificarea sintaxei codului sursă, construcţia(*p).NumeComponentăse poate înlocui cu contrucţia:p->NumeComponentă.

Tipuri de date utilizator

În foarte multe situaţii este nevoie ca utilizatorul să-şi definească noi tipuri dedate pe care le prelucrează în program. Introducerea unui noutip de date utilizator se face prin construcţiilestruct. Noul tip de date este referit prin:struct NumeStructură iar datele se vor declara prin instrucţiunile de declarare:

struct NumeStructură data1, data2, …datan;

Pentru a utiliza în mod mai flexibil numele noului tip de date introdus,respectiv, de a renunţa la cuvântul cheiestruct în declaraţii de date se va utilizadeclaraţia de tip.

Limbajul C permite atribuirea unui nume pentru un tip predefinit sau pentru noutip definit de utilizator prin construcţia:

typedef TIP NumeTip;În continuare cuvântulNumeTippoate fi utilizat în declaraţii de date ca şi

cuvintele cheie (rezervate limbajului C) care denumesc tipurile (int, float, etc.) Exemplu:Redenumirea tipuluiint al limbajului C:

typedef int INTREG;Declararea unei variabile X de tipul int se poate face astfel:

INTREG X; //identică cu declaraţia: int X;

63

Page 65: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 65/166

Algoritmi şi structuri de date

În cazul tipurilor definite de utilizator, introduse prin declaraţii de structură, putemasigna un numenoului tip printr-o construcţie de forma:

typedef structNumeStructură{<instructiuni de declarare de tip>} NumeTip;

Declararea unor variabile de tipul anterior se face astfel:NumeTipdata1, data2, … datan;

Exemplu1:Program care citeşte un şir de structuri de tipul Persoana şi afişeazăacest şir ordonat după câmpul nume.

#include <stdio.h>

#include <string.h>typedef struct{int zi;int luna;int an;

}TData;typedef struct {

char cnp[13];char nume[20];char prenume[40];TData datanasterii;char adresa[40];

}TPersoana;

void citirePers(TPersoana *p){char aux[40];printf("\n Introduceti CNP="); scanf("%s",aux);

strcpy(p->cnp,aux);printf("\n Introduceti Nume="); scanf("%s",aux);

strcpy(p->nume,aux);

printf("\n Introduceti Prenume="); scanf("%s",aux);strcpy(p->prenume,aux);printf("\n Introduceti zi nastere:");

scanf("%d",&p->datanasterii.zi);printf("\n Introduceti luna nastere:");

scanf("%d",&p->datanasterii.luna);printf("\n Introduceti an nastere:");

scanf("%d",&p->datanasterii.an);}

void tiparirePers(TPersoana p)

{printf("\n%s %s %s %d.%d.%d ", p.cnp,p.nume,p.prenume,p.datanasterii.zi,p.datanasterii.luna,p.datanasterii.an);

64

Page 66: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 66/166

Algoritmi şi structuri de date

}

void sortNUME(TPersoana per[],int nr){int cod,i;

TPersoana aux;do{cod=1;

for(i=0;i<=nr-2;i++)if(strcmp(per[i].nume,per[i+1].prenume)>0)

{//interschimb per[i] cu per[i+1]aux=per[i];per[i]=per[i+1];

per[i+1]=aux;cod=0;}

}while (cod==0);}

void main(){TPersoana per[20]; //tablou de structuriint nr;printf("\n dati numarul de persoana:");scanf("%d",&nr);

for(int i=0;i<nr;i++)citirePers(&per[i]);sortNUME(per,nr);for(i=0;i<nr;i++)

tiparirePers(per[i]);}

Probleme propuse spre rezolvare:

3. Să se definească un nou tip de dată pentru entitatea Punct (3D), săse denumească acest tipTipPunct şi să se declare 3 date de acesttip utilizator.

4. Scrieţi un program care citeşte într-un tablou un număr dek structuri de tipul utilizator Marfa. Câmpurile structurii sunt:codMarfa, DenumireMarfa, PretMarfa, CantMarfa, Valoare. Sevor calcula valorile mărfurilor (valoare=pret*cantitate) şi tabloulse va ordona descrescător după valorile obţinute şi se va afişa peecran. (valoarea produselor nu se va citi, aceasta urmînd a ficalculată după formula dată )

5. Să se scrie un program care:- Defineşte un nou tip de date Punct2D (puncte în plan)- Defineşte un tip de date Triunghi

65

Page 67: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 67/166

Algoritmi şi structuri de date

- Citeşte de la tastatură un tablou unidimensional (şir) dedate de tipul triunghi.

66

Page 68: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 68/166

Algoritmi şi structuri de date

TIP ABSTRACT DE DATE

Printip de datese înţelege domeniul valorilor şi operaţiile specificate datelor deacel tip. Tipurile de date se clasifică în tipuri elementare (ex. numeric real, numericîntreg, caracter) şi structurate (omogene – tablouri, neomogene - structuri).Majoritatea limbajelor de programare oferă posibilitatea manipulării datelor de tipelementar dar şi introducerea de noi tipuri de date. Pentrutipurile de date definitede utilizator , programatorul îşi va construi module specifice de prelucrare a datelor de acel tip.

Prezentăm ca exemplu un modul C care conţine definirea tipului de dateabstractRational.

Reamintim că un număr raţional este un număr care poate fi exprimat prinfracţiam/n, undem şi n sunt numere întregi. Reprezentarea unui număr raţional se poate face printr-o structură cu două componente de tip întreg, semnificând întregiim şi nai fracţieim/n. Identificăm următoarele operaţii cu numere raţionale:

- Iniţializare: stabileşte valorile implicite pentrum=0,n=1.- Definire: stabileşte valorile pentru componentelemşi n.- Modificare unei componentemsaun ( setm, setn)- Accesarea unei componente ( getm, getn)- Adunarea a două numere raţionale- Înmulţirea a două numere raţionale- Reducerea unui raţional(prin împărţirea lui m şi n la cel mai mare divizor

comun al celor doi întregi- Testarea egalităţii a două numere raţionale- Testarea relaţiei de ordine dintre două numere raţionale- Inversul unui raţional

Fiecare operaţie din cele enumerate va fi definită prin intermediul unei funcţii Ccorespunzătoare în modulul prezentat mai jos.

TAD RATIONAL

#include <stdio.h>

typedef struct{int m;int n;

}Rational;

void initializare(Rational *a){

a->m = 0;

a->n = 1;}

void definire(Rational *a, int m_nou, int n_nou){ a->n = n_nou;

67

Page 69: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 69/166

Algoritmi şi structuri de date

a->m = m_nou;}

void setm(Rational *a, int m_nou){

a->m = m_nou;}

void setn(Rational *a, int n_nou){

a->n = n_nou;}

int getm(Rational a){ return a.m;}

int getn(Rational a){ return a.n;}

int cmmdc(int x, int y){ int aux;

if (x < y){

aux = x;x = y;y = aux;

}while ( x != y)

if ( x > y)x = x -y;

elsey = y -x;

return x;}

void reduce(Rational *a){ int x; //cel mai mare divizor comun

x = cmmdc(a->m, a->n);a->m = a->m / x;a->n = a->n / x;

}

void print(Rational a){ printf("\n %d/%d ", a.m, a.n);}

void inmultire(Rational a, Rational b, Rational *c){ c->m = a.m * b.m ;

c->n = a.n * b.n;

68

Page 70: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 70/166

Algoritmi şi structuri de date

reduce(c);}

void adunare(Rational a, Rational b, Rational *c){ c->m = (a.m * b.n + b.m * a.n);

c->n = a.n * b.n;reduce(c);}

int egalitate(Rational a, Rational b){if ((a.m*b.n)==(a.n*b.m))

return 1;return 0;

}

Rational invers(Rational a){ Rational aux;

aux.m=a.n;aux.n=a.m;return aux;

}

int maiMic(Rational a, Rational b)//verifica relatia de ordine a<b{if (((a.n*b.n>0) &&(a.m*b.n<=a.n*b.m))||

((a.n*b.n<0) &&(a.m*b.n>=a.n*b.m)))return 1;return 0;

}

Problemă : Urmând exemplul prezentat anterior (TAD Rational) să se conceapătipul abstract de dateComplex , dezvoltând o bibliotecă de funcţii specificeoperaţiilor cu numere complexe.

69

Page 71: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 71/166

Algoritmi şi structuri de date

VI. LUCRUL CU FIŞIERE

Prin fişier se înţelege colecţie ordonată de elemente pe care le numimînregistrări. Fişierele sunt păstrate pe suporturi externe reutilizabile: hard disk,floppy disk, etc. Prelucrarea fişierelor implică un număr de operaţii specificeacestora:

1. Creare fişier 2. Deschidere fişier 3. Citire din fişier 4. Adaugare – scriere în fişier 5. Actualizare fişier 6. Poziţionare în fişier 7. Ştergere fişier

Operaţiile specifice fişierelor se realizează prin intermediul unor funcţiistandard existente în biblioteca limbajului C. Există două nivele de tratare afişierelor:

1. Nivelul inferior– face apel direct la sistemul de operare2. Nivelul superior– face apel la proceduri specializate de prelucrare a

fişierelor, care utilizează structuri speciale de tipul FILE.

Nivelul inferior de prelucrare a fişierelor

Pentru a putea prelucra un fişier lanivel inferior acesta trebuie să fie creat în prealabil.

1. Crearea unui fişiernou se realizează prin apelul funcţieicreat care are prototipul:

int creat (const char*cale , intmod );Unde:

- cale – este un pointer spre un şir de caractere prin care este specificatnumele complet al fişierului (calea)- mod – un număr întreg prin care se specifică modul de acces al

proprietarului la fişier. Acest mod poate fi definit folosind constantesimbolice:

S_IREAD – proprietarul poate citi fisierul S_IWRITE – proprietarul poate scrie fisierul S_IEXE – proprietarul poate executa programul conţinut de fişierul respectiv

Utilizarea acestei funcţii implică includerea fişierelor:io.hşi stat.h.

70

Page 72: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 72/166

Algoritmi şi structuri de date

Observaţie:Indicatorii demod pot fi combinaţi. Astfel pentru a crea un fişier încare avem drepturi de scriere şi citire vom utiliza construcţia: S_IREAD|S_IWRITE.

Funcţiacreat returnează un număr întreg care are semnificaţia descriptorului defişier (dacă este pozitiv) sau eroare (dacă este -1).

Descriptorul de fişier este reprezintă un număr întreg pozitiv ataşat fişierului prelucrat, prin intermediul căruia se identifică un fişier în operaţiile specificerealizate asupra acestuia.

2. Deschiderea unui fişierDeschiderea fişierului se realizează prin apelul funcţieiopenal cărei prototip

este:int open (const char*cale , intacces );

Utilizarea acestei funcţii presupune includerea fişierelor io.h şi fcntl.h:

#include <io.h>#include <fcntl.h>

- cale – pointer la un şir de caractere prin care se specifică calea completă afişierului ce va fi deschis.

- acces – întreg prin care se specifică modul de acces la fişier:O_RDONLY– numai în citireO_WRONLY – numai în scriereO_RDWR – citire-scriereO_APPEND – adăugare la sfârşitul fişieruluiO_BINARY – prelucrare binarăO_TEXT – prelucrare text

Valorile de acces pot fi combinate prin caracterul ‘|’ , spre exemplu: O_RDONLY|O_BINARY Funcţia returnează un întreg nenegativ (descriptorul de fişier) sau –1 în caz de

eroare. Exemplu:

int df;df=open(“nume.txt”,O_APPEND);

Observaţii: Dacă nu este specificată complet calea fişierului, se consideră implicit calea

curentă.Calea completă a unui fişier este specificată printr-un şir de caractere de forma:

Litera:\Dir1 \ Dir2 …. \Dir Unde:

- Litera poate fi A,B,C … reprezintă litera de identificare a discului (ex:C – harddisk, A – floppy disk)

- Dir1, DIr2, … sunt nume de subdirectoareDacă specificăm calea fişierului în apelul funcţieiopen, toate caracterele \

trebuie dublate

71

Page 73: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 73/166

Algoritmi şi structuri de date

Exemplu:int df;df = open (“C:\\Borlandc\\bin\\text.cpp”, O_RDWR);

3. Citirea din fişierSe realizează prin funcţiaread , prototipul acesteia se află în fişierul io.h:

int read(int df, void *mem, unsigned lung);unde:

- df – descriptorul ataşat fişierului (returnat de funcţia open)- mem – pointer spre zona de memorie în care se va păstra înregistrarea

citită din fişier - lung – lungimea înregistrării exprimată în număr de octeţi

Funcţiaread returnează un întreg reprezentând numărul de octeţi citiţi din fişier sau: –1 în caz de eroare, 0 la terminarea fişierului Efectul:Prin apelul funcţieiread se citeşte din fişier înregistrarea curentă; la un

apel următor se va citi următoarea înregistrare, ş.a.m.d până la sfârşitul fişierului. Exemplu: citirea din fişier caracter cu caracter până la terminarea fişierului şi

afişarea pe monitor a conţinutul acestuia:int df, i;char c;df=open(“proba.txt”,O_RDONLY);do{

i=read(df, c, sizeof(char) );//sizeof(char) returnează numărul de octeţi//necesari tipului specificat între paranteze.printf(“%c”, c);

}while (i>0);

4. Scrierea în fişierFuncţiawrite , prototipul acesteia se află în fişierul io.h:

int write(int df, void *mem, unsigned lung);unde:

- df – descriptorul ataşat fişierului (returnat de funcţia open)- mem – pointer spre zona de memorie din care se preia informaţia ce se vascrie în fişier

- lung – lungimea înregistrării exprimată în număr de octeţi

Funcţiawrite returnează un întreg reprezentând numărul de octeţi scrişi dinfişier, în general numărul specificat de parametrul lung. Dacă cele două valori suntdiferite, este semnalat prin acesta un caz de eroare.

Exemplu: scrierea într-un fişier a unei secvenţe de caractere…int df, i;char text[30] = “Acest text se scrie in fisier!”;df=open(“proba.txt”,O_APPEND);write(df, text, 30);

72

Page 74: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 74/166

Algoritmi şi structuri de date

5. Poziţionarea în fişierCitirea şi scrierea în fişiere se face în mod secvenţial, ceea ce înseamnă că

înregistrările se scriu una după alta pe suportul fişierului şi citirea se face înaceeiaşi ordine în care au fost scrise. Dacă dorim ca accesul la înregistrări să sefacă într-o ordine diferită decât cea implicită se poate utiliza funcţialseek pentru poziţionarea în fişier:

long lseek(int df, long depl, int orig);unde:

- df – descriptorul de fişier - depl – deplasamentul exprimat în număr de octeţi- orig– este un număr întreg ale cărui valori semnifică:

0 – deplasamentul se consideră de la inceputul fişierului1 – deplasamentul se consideră din poziţia curentă

2 – deplasamentul se consideră de la sfârşitul fişieruluiFuncţia returnează poziţia faţă de începutul fişierului.

6. Închiderea fişieruluiFuncţiacloseavând prototipul:

int close (int df); //df - descriptorul de fişier Utilizarea funcţieicloseimplică includerea fişierului bibliotecăio.hReturnează:

0 – la închiderea normală a fişierului-1 – în caz de eroare

Nivelul superior de prelucrare a fişierelorFuncţii de manipulare a fişierelor sunt definite în bibliotecile standard ale

limbajului. Prototipurile funcţiilor se găsesc în fişierul antetstdio.h. Fişierul carese prelucrează este identificat în mod unic printr-un pointer de fişier (uzualdenumim acest pointer de fişier pf).

În limbajul C există tipul de date FILE (fişier) prin care se defineşte structura

datelor dintr-un fişier. În declaraţiile de tip vom avea nevoie de o secvenţă:FILE *pf;1. Deschiderea unui fişierFuncţia de deschidere a unui fişier se numeşte: fopenşi prototipul funcţiei este

următorul:FILE *fopen(const char *nume, const char *mod);

În declaraţiile de tip vom avea nevoie de o secvenţă:FILE *pf, fopen();

Argumentele funcţiei:nume– şir de caractere prin care se identifică numele fişierului de pe disc pe care dorim să-l accesăm.mod – şir de caractere prin care se specifică modul de acces la fişier.

Modurile valide de deschidere a fişierului sunt:“r” - deschidere pentru citire

73

Page 75: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 75/166

Algoritmi şi structuri de date

“w” - deschidere pentru scriere (informaţia din fişier se pierde ladeschiderea în acest mod)“a” - deschide pentru scriere (fără pierderea informaţiei din fişier) saucreează fişier “r+” - deschide pentru actualizare“w+” - deschide sau creează fişier pentru actualizare (pierdereainformaţiei)“a+” - deschide sau creează fişier pentru actualizare (fără pierdereainformaţiei anterioare)

Efectul apelării funcţiei: deschide fişierul specificat prin nume în modul deacces dorit şi returnează un pointer spre structura FILE (FILE *pf ) care ulterior seutilizează pentru a identifica fişierul în operaţiile ce se efectuează asupra sa. În cazde insucces, funcţia returneazăNULL. Exemplu:FILE *pf; //pointer spre FILE…pf=fopen(“fis1.dat”, “r”);// deschid fişierul fis1.dat pentru a putea citi informaţiiif (pf==NULL)

{printf(“\n Nu s-a putut deschide fisierul”);exit(1); //iesire din program}

2. Închiderea fişieruluiFuncţia de închidere a unui fişier se numeşte fclose şi are prototipul:

int fclose(FILE *pf);Argumentul funcţiei:

pf – pointer spre FILE, identifică fişierul ce se închideFuncţia returnează 0 în caz de succes sau EOF (end of file) în caz de insucces.În declaraţiile de tip vom avea nevoie de o secvenţă:

int fclose();3. Scrierea în fişier

Funcţia de scriere în fişier: fprintf are prototipul:int fprintf(FILE *pf, const char* sir_format, lista_arg);Argumentul funcţiei:

pf – pointer spre FILE, identifică fişierul ]n care se efectuează scriereasir_format, lista_arg - au aceiaşi semnificaţie ca şi în cazul funcţiei

printf Funcţia returnează în caz de succes numărul de caractere scrise sau un număr

negativ în caz de insucces. Exemplu:

fprintf(pf, “Rezultatul este: %d”, rezultat);

4. Citirea din fişierFuncţia de citire din fişier: fscanf are prototipul:

74

Page 76: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 76/166

Algoritmi şi structuri de date

int fscanf(FILE *pf, const char* sir_format, lista_arg);Argumentul funcţiei:

pf – pointer spre FILE, identifică fişierul din care se efectuează citireasir_format, lista_arg - au aceiaşi semnificaţie ca şi în cazul funcţiei scanf

Funcţia returnează în caz de succes numărul de caractere citite sau un număr negativ în caz de insucces. Exemplu:

fscanf(pf, “%d”, &x);5. Poziţionarea în fişierÎn mod firesc accesul la înregistrările unui fişier se produce în mod secvenţial,

prin parcurgerea înregistrărilor de la începutul fişierului până la înregistrareadorită. Funcţia de bibliotecăfseek este utilă deoarece are ca efect poziţionarea înfişier fără a fi necesară parcurgerea explicită a înregistrărilor anterioare celei

căutate.Prototipul funcţiei este:int fseek (FILE *pf, long increment, int mod)

modpoate fi:0 – dacă increment – indică numărul de octeţi faţă de începutul fişierului1 – dacă increment – indică numărul de octeţi faţă de poziţia curentă2 – dacă increment – indică numărul de octeţi faţă de sfârşitul fişierului

În parcurgerea înregistrărilor dintr-un fişier, în mod frecvent este necesarăverificarea dacă s-a ajuns sau nu la sfârşitul fişierului. În acest scop se va folosifuncţia: feof

int feof(FILE *stream);Funcţia returnează 1 dacă s-a ajuns la sfârşitul fişierului, 0 dacă nu s-a ajuns

la sfârşitul fişierului şi -1 în caz de eroare.

Alte funcţii de prelucrare a fişierelor

Funcţiilefgetcşi fputcau prototipueileint fgetc(FILE *pf);

int fputc(int c, FILE *pf);

Efectul : citirea/scrierea unui caracter din/în fişierul identificat prin pointerul pf .Funcţia fgetc – returnează caracterul citit. Exemplu:Programul citeşte caracter cu caracter un fişier şi afişează conţinutul

acestuia pe ecran:#include <stdio.h>void main(void){

int c;FILE *ptr;

ptr = fopen("c:\\test.txt","r");

while ((c = fgetc(ptr)) != EOF){

75

Page 77: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 77/166

Algoritmi şi structuri de date

printf("%c",c);}fclose(ptr);

}

Funcţiilefgetsşi fputsau prototipurileint *fgets(char *sir, int n, FILE *stream);int fputs(const char *sir, FILE *stream);

Efectul : citirea/scrierea unui şir de caractere din-în fişierul identificat prin pointerul pf .

Operaţiile deinserare sau ştergerea unei înregistrări din fişier sunt operaţiicomplexe realizate în mai multe etape. Se folosesc funcţiile de bibliotecă standardenumerate (deschidere fişier, creare fişier, scriere, citire, etc.) în implementarea

operaţiilor de inserare-ştergere, însă nu există funcţii standard corespunzătoarecelor două operaţii ca atare.

Inserarea pe o poziţiek a unei noi înregistrări presupune parcurgereaurmătoarelor etape:

1. deschiderea fişierului iniţial în citire2. crearea unu fişier auxiliar şi deschiderea sa în modul scriere 3. parcurgerea secvenţială fişierului iniţial şi copierea înregistrărilor în

fişierul auxiliar până la înregistrareak 4. scrierea noii înregistrări în fişierul auxiliar 5. continuarea parcurgerii fişierului iniţial şi continuarea copierii

înregistrărilor în fişierul auxiliar 6. redenumirea fişierului auxiliar cu numele fişierului iniţial

Ştergerea înregistrăriik dintr-un fişier presupune de asemenea folosirea unuifişier auxiliar şi parcurgerea etapelor următoare:

1. crearea fişierului auxiliar şi deschidere sa în modul scriere2. parcurgerea şi copierea înregistrărilor fişierului iniţial în fişierul auxiliar

până la înregistrarea de pe poziţiak-13. citirea înregistrăriik fără a fi copiată în auxiliar 4. parcurgerea şi copierea înregistrărilor fişierului iniţial în fişierul auxiliar

de la înregistrareak+1până la sfârşit.

O variantă de inserare sau ştergere a unei înregistrări este aceea prin care serenunţă la folosirea unui fişier auxiliar şi se construieşte o structură liniară de tiptablou în care sunt salvate temporar înregistrările fişierului iniţial.

Afişarea conţinutului unui fişier. Etape:Deschide fişierulCâttimp nu s-a ajuns la sfârşitul fişierului

Citeşte linia curentaAfişare pe ecran linia citita

76

Page 78: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 78/166

Algoritmi şi structuri de date

SfcâttimpÎnchidere fişier

Copierea conţinutului unui fişier (fis1.dat) într-un alt fişier (fis2.dat). Etape:Creează fi ierul fis2.datșDeschide fişierul fis1.datCâttimp(nu s-a ajuns la sfârşitul fişierului fis1.dat)

Citeşte din fişierul fis1.datScrie în fişierul fis2.dat

SfcâttimpÎnchidere fişierele.

Probleme:6. Să se scrie un program C care citeşte de la tastatură un vector de

structuri Punct3Dşi le salvează într-un fişier puncte.dat.7. Să se scrie un program C care citeşte din fişierul puncte.dat unvector de structuri Punct3D şi afişează coordonatele punctelor peecran.

8. Scrieţi un program care gestionează într-un fişier structuri de tipulPersoana (CNP, nume, prenume, data nasterii, etc.). Operaţiileevidenţiate sunt cele de adăugare înregistrare, ştergere înregistrare,căutare persoană după valoarea câmpului CNP, ordonareaalfabetică a persoanelor memorate în fişier.

77

Page 79: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 79/166

Algoritmi şi structuri de date

VII. ALOCAREA DINAMICA A MEMORIEI

Una dintre cele mai costisitoare resurse ale unui program este estememoria

utilizată. Programarea este o activitate în care, în afara corectitudinii programelor elaborate, se urmăreşte şi eficienţa acestora, măsurată prin timpul de execuţie şimemoria utilizată. În scopul economiei resurselor, limbajele de programare oferă programatorului instrumentele necesare unei bune gestionări a memoriei.

Alocarea memoriei pentru variabilele locale declarate într-o funcţie se face înetapa de execuţie a programului, pe stivă, şi nu este permanentă. La ieşirea dinfuncţie, stiva se curăţă, fapt pentru care datele alocate sunt distruse. Acestmecanism de alocare este eficient şi se denumeştealocare dinamică . În schimb,datele declarate global au un comportament diferit. Pentru variabilele globale,memoria este alocată în faza premergătoare execuţiei şi zona de memorierespectivă rămâne alocată acestora până la terminarea programului. Spre exemplu,declararea globală a unui tablou unidimensional de lungime maximă 2000(<TipElement> tablou[2000];), face ca o zonă de memorie considerabilă să fie blocată pentru această structură, indiferent de numărul elementelor folosite efectiv,număr care în multe cazuri poate fi cu mult mai mic decât dimensiunea maximădeclarată. În astfel de situaţii este preferabilă o manieră de alocare dinamică învederea unei gestionări economice a memoriei. Alocarea dinamică a memoriei poate fi simplificat definită prin totalitatea mecanismelor prin care datelor le suntasignate zone specifice de memorie în faza de execuţie a programelor.

Dezavantajele alocării dinamice a memoriei constau în:1. sarcina suplimentară a programatorului de a asigura şi eliberareamemoriei când nu mai are nevoie de datele respective

2. efectul fragmentării memorieicare poate produce imposibilitateaalocării ulterioare a unei zone de memorie de dimensiune dorită.

Limbajul C/C++ oferă programatorului funcţii standard prin care se realizeazăalocarea, respectiv, dealocarea (eliberarea) memoriei. Funcţiilemalloc şi free au prototipurile în fişierul antet:alloc.h şi gestionează o zonă de memorie specială,denumită memoriaheap .

Funcţiamalloc:void *malloc(size_tdimensiune)

Argumentul funcţiei este dimensiunea exprimată în octeţi, semnificânddimensiunea zonei alocate. Funcţia returnează în caz de succes adresa de memoriea zonei alocate. Este posibil ca cererea de alocare să nu poată fi satisfăcută dacă numai există suficientă memorie în zona deheap sau nu există o zonă compactă dedimensiune cel puţin egală cudimensiune. În caz de insucces, funcţia mallocreturnează NULL.

Funcţia calloc:void *calloc(size_tnrElemente, size_tdimensiune)

Efectul funcţiei: se alocă un bloc de memorie de mărimenrElemente *dimensiune(această zonă nu trebuie să depăşească 64 Ko octeţi din heap) şiconţinutul blocului alocat este şters. În caz de succes, funcţia returnează adresa

78

Page 80: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 80/166

Algoritmi şi structuri de date

blocului de memorie alocat; returnează 0 dacă nu există spaţiu liber de mărimeasolicitată.

Funcţiarealloc:void *realloc(void*adrBloc, size_t Dimensiune)

Funcţia încearcă să mărească sau să micşoreze un bloc (alocat dinamic)la numărul de octeţi specificaţi de parametrul Dimensiune. ParametruladrBloc

indică un bloc de memorie obţinut prin apelarea anterioară a funcţieimalloc,calloc sau realloc. Dacă parametruladrBloc este 0, efectul este identic cu alfuncţieimalloc. Dacă Dimensiuneeste 0 efectul apelului este identic cu cel alfuncţiei free.

Funcţia ajustează mărimea blocului alocat la Dimensiuneşi returnează adresa blocului realocat sau 0 - dacă nu se poate face realocarea.

Funcţia free:void free(void * p)

Argumentul funcţiei este adresa zonei ce va fi eliberată. Efectul apeluluifuncţiei free este de a elibera memoria a cărei adresă este p.

Exemplu:tip *p; p= (tip*)malloc(sizeof(tip)) ;free(p);

Observaţie: operatorul sizeof returnează dimensiunea în octeţi a expresiei:sizeof(expresie). Construcţia (Tip*) realizează oconversie explicită de tip: din tipul pointer nedefinit (void *) spre tipul pointer laTip.

Utilizarea celor două funcţii standardmallocşi freedevine utilă şi în programeîn care se vor manipula tablouri de elemente: şiruri de caractere, vectori de datesimple, vectori de structuri, etc.

Programele următoare sunt exemple simple de gestionare eficientă a memoriei prin alocarea dinamică a structurilor de date:

Program – Exemplu de alocarea dinamică a tablourilor.

#include <stdio.h>#include <stdlib.h>

int *citire_vector(int *pDim){int * vector;int i;printf("\nDati n:");scanf("%d", pDim);if ((vector=(int *)calloc(*pDim,sizeof(int)))==NULL )

{printf("Insucces la alocarea dinamica");exit(1);}

for (i=0; i<*pDim; i++)

79

Page 81: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 81/166

Algoritmi şi structuri de date

{printf("vector[%d]=", i+1);scanf("%d", &vector[i]);// sau scanf("%d", vector+i);}

return vector; //se returneaza adresa vectorului

}

void afisare_vector(int *vector, int n){int i;for (i=0; i<n; i++)

{printf("\nvector[%d]=%d", i+1, vector[i]);}

}

void main(void){

int n;int *vector;vector=citire_vector(&n);afisare_vector(vector, n);

}

Program 2 - operaţii cu şiruri de caractere. Programul ca aloca dinamic memorie pentru un şir de caractere sir2 şi va efectua o copiere a şirului sir1 citit de latastatură în zona de memorie rezervată noului şir.

#include <stdio.h>#include <stdlib.h>#include <string.h>

void main(void){

char sir1[10];char *sir2;

printf("introduceti un sir de caractere: \n");scanf("%9s", sir1);// se retin primele 10 caractere introduseint dimCh=sizeof(char);

if ((sir2=(char *)malloc( (strlen(sir1)+1)* dimCh))==NULL){printf("Insucces la alocarea dinamica");exit(1);}strcpy(sir2, sir1);printf("Sirul sursa: %s \n", sir1);printf("Sirul destinatie: %s \n", sir2);

}

80

Page 82: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 82/166

Algoritmi şi structuri de date

VIII. LISTĂ SIMPLU ÎNLĂNŢUITĂ

Lista reprezintă o mulţime de dimensiune variabilă, formată din elemente deacelaşi tip. Înţelegem prin listă – omulţime dinamică şi omogenă , a căreidimensiune se modifică în timpul rulării programului.

Memorarea structurilor de date de tiplistă se poate face în două maniere:1. secvenţial - elementele listei sunt memorate la adrese consecutive2. înlănţuit – elementele listei nu ocupă adrese consecutive, fiecare

element conţine pe lângă informaţia propriu-zisă şi olegătură spreurmătorul element.

Memorarea secvenţială se poate produce prin folosirea structurilor de date de tiptablou. Dinamica listei secvenţiale se realizează în această situaţie prin reţinerea

unui parametru suplimentar cu semnificaţia dimensiunii curente a tabloului. Pentrulistele organizate static, sub formă de tablou, ordinea elementelor este cea implicităîn tablou.

În ciuda simplităţii acestei abordări se preferă varianta elementelor înlănţuite şialocate dinamice. Argumentul folosirii listelor înlănţuite rezidă din necesitateaeconomiei de memorie. Folosirea tablourilor forţează o declararea a număruluimaxim de elemente ceea ce rareori este cunoscut la momentul dezvoltării programului. În consecinţă, folosirea unui tablou de o dimensiune mult mai micădecât maximul declarat, permite manevrarea elementelor sale dar în acelaşi timp produce o risipă inutilă a unui bloc memorie alocat şi neutilizat.

În spiritul economiei de memorie, abordarea structurilor de date de tip listă prinliste înlănţuitealocatedinamiceste avantajoasă. Organizarea acestor structuri dedate în C se face prin folosirea unor legături care nu sunt altceva decât pointeri(adrese) spre următoarele elemente din listă. Pentru listele organizate dinamic, subformă înlănţuită, ordinea elementelor este dată de pointeri.Pointeriilegătură dincompunerea unui element al listei indică adresele unor alte elemente de acelaşi tip.Elementele unei liste se denumesc în mod uzualnoduri. Prin folosirea pointer-ilor (legături), structura unui nod al listei devinerecursivă.

Liste înlănţuite pot fi: simplu, dublu sau multiplu înlănţuite. Clasificarea listelor

se face în funcţie de numărul legăturilor din compunerea unui element.Operaţiile principale cu liste sunt următoarele:1. parcurgere2. creare3. distrugere (ştergere)4. adăugare nou element5. ştergere element

Lista simplu înlănţuită

Structura nodului listei simplu înlănţuite:Figura următoare prezintă în mod grafic structura unui nod al listei simplu

înlănţuite, punându-se în evidenţă cele două părţi ale nodului:1. zona de informaţii, formată din unul sau mai multe câmpuri

81

Page 83: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 83/166

Algoritmi şi structuri de date

2. legătura spre alt nod de acelaşi fel

adO structură care descrie compunerea unui element de acest gen este următoarea:struct nod

{//declaraţii de date – câmpuri ale informaţieistruct nod *adr; //adresa următorului nod

}Convenim că informaţia din noduri conţine un câmp special (cheie) ale cărui

valori sunt distincte pentru elementele aceleiaşi liste (cheie nu este un câmpobligatoriu). Pentru a simplifica exemplele următoare, vom introduce un nou tip dedată, tipul nodurilor, denumitTNod .

typedef struct nod{int cheie; //câmp cu valori unice pentru nodurile listei//alte câmpuristruct nod *urm; //adresa următorului nod}Tnod;

Gestionarea unei liste de astfel de noduri necesită cunaşterea adresei primului şieventual al ultimului nod din listă. Reţinându-se doar adresa primului nod, celelaltenoduri pot fi parcurse, accesate, prin urmărirea legăturilor urm conţinute în

nodurile curente.Adresa fiecărui nod este conţinută de nodul precedent, cu excepţia primului nodal listei, pentru care nu există un nod precedent. Ultimul nod nu va referi niciun altnod următor, fapt care se marchează prin pointerulurm care devine Null. Figuraurmătoare sugerează organizarea unei liste simplu înlănţuite:

prim

adr

Pentru implementarea operaţiilor specifice listelor înlănţuite este utilădeclararea a doi pointeri la tipul Tnod, cu semnificaţia adreselor primului şiultimului element din listă:

Tnod *prim, *ultim;

Parcurgerea listei

Parcurgerea listei presupune accesarea sau prelucrarea elementelor listei înordinarea stabilită de legăturile conţinute de noduri. Cunoscând primul element prim, acesta conţine adresa următorului element, care la rândul său conţine adresaurmătorului, etc. În acest mod, prin urmărirea adreselor de legătură pot fi accesaţitoţi membrii listei. Terminarea operaţiei de parcurgere a listei constă în accesareaultimului element, marcat prin adresă nulă a pointeruluiurm.

82

Page 84: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 84/166

Algoritmi şi structuri de date

Considerândp adresa nodului curent din listă, trecerea la nodul următor seobţine prin asignarea:p=p->urm;

Dacă nodul curent p este Null(p==0), se încheie parcurgerea.Paşii parcurgerii unei liste sunt următorii:

1. iniţializează pointer-ul curent cu adresa primului nod :p=prim2. câttimp (pointerul curent este diferit de 0:p!=0) executăa. prelucrare nodul referit de p (accesare, modificare conţinut) b. trecerere la următorul nodp=p->urm

Oferim în continuare o funcţie C prin care se parcurge lista simplu înlănţuităgestionată de primşi ultimşi sunt afişate informaţiile nodurilor traversate.

void tiparire_lista(){tnod *p; //p semnifică nodul curent

p=prim; //se porneşte traversarea listei de la primul nodwhile(p!=0) //câttimp nu s-a ajuns la sfîrşitul listei

{printf("\n%d ",p->cheie);// afişarea celorlalte câmpuri din nodul curentp=p->urm; //trecere la următorul element}

}

Crearea listei vide

Crearea unei liste înlănţuite care nu conţine niciun element presupuneiniţializarea celor doi pointeri prim şi ultim cu valoarea 0:prim=ultim=0;

Crearea unei liste cu mai mult de 0 noduri presupune adăugarea în mod repetata noilor noduri până la întâlnirea unei condiţii de terminare a procedeului. Noilenoduri pot fi adăugate sistematic după ultimul element al listei, sau înaintea primului nod. În procesul de adăugarea a unui nou nod se ţine cont de douăaspecte:

1. nodul nou trebuie alocat în memorie şi încărcat cu informaţie2. anumite legături din listă trebuie refăcute pentru a asigura consistenţa

organizăriiPrezentăm în continuare o funcţie C care are efectul alocării şi încărcării unui

nou nod de tipul Tnod. Utilitatea acestei funcţii o vom înţelege în construireafuncţiilor de inserare - adăugare noduri la listă:

tnod * incarca_nod(){

tnod *p;p=(tnod*)malloc(sizeof(tnod)); //alocare memorieprintf("\n dati cheia"); scanf("%d",&p->cheie);

//citire cheie… //citire alte informaţii conţinute de nod return p; //returnarea adresei nodului încărcat

}

83

Page 85: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 85/166

Algoritmi şi structuri de date

Inserarea unui nou element:

1. Înaintea primului nod

Etapele introducerii unui nou nod înaintea primului nod al listei gestionate prin pointerii primşi ultimsunt următoarele:1. alocarea şi încărcarea noului nod:2. stabilirea faptului că acest nou nod va adresa ca următor element

chiar pe nodul prim:nou->urm=prim3. stabilirea noului nod ca prim element al listei:prim=nou

Observaţie:dacă lista este vidă în momentul încercării de a adăuga un nod nou,efectul operaţiei constă în obţinerea unei liste cu un singur element, fapt pentrucare capetelor listei primşi ultimsunt confundate şi este necesară tratarea acestuicaz particular.

1

nou

prim

void adaugare_prim(){tnod *p;p=incarca_nod();if (prim= =0) //lista vida

{prim=p;ultim=p;ultim->urm=0;return;

}p->urm=prim;prim=p;}

2. După ultimul nodEtapele introducerii unui nou nod după ultimul nod al listei gestionate prin

pointerii primşi ultimsunt următoarele:1. alocarea şi încărcarea noului nod:2. stabilirea faptului că acest ultimul nod va adresa ca următor

element pe noul nod:ultim->urm=nou(1)

3. stabilirea noului nod ca ultim element al listei, şi marcarea acestuiaca ultim nod din listă:ultim=nou; nou->urm =0;(2)4. dacă lista este vidă în momentul încercării de a adăuga un nod nou,

se va trata distinct acest caz

84

Page 86: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 86/166

Algoritmi şi structuri de date

ultim

void adaugare_ultim(){ tnod *nou; nou=incarca_nod();if (prim==0) //lista vida

{prim=nou;ultim=nou;ultim->urm=0;return;}

ultim->urm=nou;ultim=nou; ultim->urm=0;}

3. Inserarea unui nod înaintea unui nod specificatAcest tip de operaţie se realizează în două etape:

1. căutarea nodului înaintea căruia se va insera un nou nod2. inserarea propriu-zisă a noului nod

Căutarea unui nod specificat prin cheiese realizează printr-un algoritmelementar de parcurgere sistematică a listei până la întâlnirea nodului ce conţinecheia căutată. În acest scop se poate construi o funcţie care returnează adresanodului căutat, şi 0 în caz de insucces (dacă nodul de cheie dată nu există în listă).Argumentul funcţiei este valoarea cheii căutate.

Căutarea nodului înaintea căruia se va insera noul nod poate fi realizată înaceiaşi funcţie în care se face inserarea. Procedura de inserare ţine cont de cazul particular în care nodul specificat prin cheie este primul nod.

Stabilirea legăturilor dintre noduri trebuie făcută corect pentru a nu genera pierderea unei sub-liste de noduri. În acest sens este necesară reţinerea în permanenţă a adresei nodului precedent nodului curent, pentru ca ulterior noul nodsă poate fi înlănţuit între nodurile precedent şi curent . Imaginea următoaresugerează etapele inserării noului nod, cunoscându-se adresa prev (nodul precedent= şi adresa nodului curentp:

1. nodul nou va conţine adresa nodul curent:nou->urm=p;2. precedentul nod va conţine adresa noului nodprev->urm=nou; -

atribuire prin care vechea înlănţuirea a nodurilor prev şi p se pierde.

85

Page 87: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 87/166

Algoritmi şi structuri de date

curent2

nou

prev

Funcţia următoare descrie operaţia de inserare înaintea unui nod căutat dupăvaloarea cheii:

void adaugare_inainte()

{int valoare;printf("\ndati cheia de cautat:");scanf("%d",&valoare);tnod *p,*prec, *nou;p=prim; //iniţializare nodul curent cu primwhile (p!=0)

{if (p->numar!=valoare)

{//NU s-a gasit încă nodulprec=p; //salvează adresa precedentului în prev p=p->urm; //trece la următorul element}

else{ //s-a găsit nodul de cheie datăif (p==prim)

{//caz particular, nodul căutat este primuladaugare_prim();return;}

else{nou=incarca_nod();

nou->urm=p; //reface legăturileprec->urm=nou;return;}

}}

}//sfârşit funcţie

4. După un nod stabilit de o cheie:Operaţia de inserare după un nod specificat este similară celei anterioare. Cazul

particular al procedeului constă în găsirea ca nod de referinţă chiar ultimul nod allistei, fapt pentru care operaţia se reduce la adăugarea după ultim (funcţie dejaconstruită).

86

Page 88: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 88/166

Algoritmi şi structuri de date

În plus, reţinerea unei adresa a precedentului nodului curent nu mai estenecesară. În fapt, nodul nou se va insera între nodul găsit (curent) şi următorul nodal nodului curent. Însă, prin maniera de înlănţuire, adresa următorului nod alnodului găsit este cunoscută, fiind memorată ca legătură chiar în nodul găsit:p->urm .

p->urm2

nou

p

Considerând nodul de cheie dată găsit:p, etapele inserării noului nod sunt:1. stabileşte adresaurma noduluinouca fiind adresa nodul următor al luip:

nou->urm=p->urm(1)2. stabile;te adresaurma lui p ca fiind adresa luinou: p->urm=nou. Prin

această asignare s-a pierdut automat înlănţuirea veche între p şi p->urmvoid adaugare_dupa(){int valoare; printf("\ndati cheia decautat:");scanf("%d",&valoare);tnod *p,*nou;p=prim;while (p!=0)

{if (p->numar!=valoare)

{//NU am gasitp=p->urm;

}else

{ //caz particularif (p==ultim)

{adaugare_ultim();return;}

else{//alocare memorie şi încărcare nod cu inf.nou=incarca_nod();nou->urm=p->urm; //stabilirea legăturilor

p->urm=nou;

return;}}

}

87

Page 89: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 89/166

Algoritmi şi structuri de date

}

Ştergerea unui element9. Ştergerea primuluielement al listei necesită eliberarea memoriei

dar şi actualizarea pointer-ului prim necesar în gestionareaulterioară a listei. Actualizarea prim-ului nod al listei se face prinasignareaprim=prim->urm, prin care următorul nodului prim(secundul) devine primal listei

void stergere_prim(){

tnod *primvechi;primvechi=prim; //salvare adresa primului elementif (primvechi==0)

{//lista este vidă, nu se va şterge nimicprintf("\nlista este vida");return;}

prim=prim->urm; //actualizare primfree(primvechi);//eliberarea memoriei adresata de prim

}

10.Ştergerea ultimuluipresupune refacerea legăturilor, eliberareaunei zone de memorie şi actualizarea pointer-ului ultim (util în

gestionarea listei). În contradicţie cu operaţia de ştergere a primului nod, ştergerea ultimului nod al listei necesită o parcurgereîn totalitate a listei, pentru a determina adresa precedentuluinodului ultim. Acest lucru este necesar pentru a realiza operaţia deactualizare a pointer-uluiultim. Adresa următorului nod după primse poate determina în mod elementar prin câmpulurm, însă, adresanodului anterior ultimului se determină printr-un procedeusuplimentar de traversare a listei, generând un cost suplimentar alalgoritmului.

Etapele ştergerii ultimului element al unei liste sunt:a. traversarea listei pentru a determina adresa penultimului element b. actualizarea ultimului nodc. eliberarea memoriei

void stergere_ultim(){tnod *ultimvechi,*prec,*p;p=prim;if (p==0)

{printf("\nlista este vida");return;}

while (p!=ultim)//traversarea listei şi reţinerea precedentului nodului//curent

88

Page 90: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 90/166

Algoritmi şi structuri de date

{prec=p; //salvare precedentp=p->urm; //trecere la următorul nod}

//în acest punct prec este adresa penultimului nod

ultimvechi=p; //salvare vechiul nod ultimultim=prec; ultim->urm=0; //actualizare şi marcare ultim free (ultimvechi); //eliberare memorie}

11. Ştergerea unui element precizatŞtergerea unui element precizat prin valoarea cheii se execută prin următorii

paşi:- căutarea noduluip ce va fi şters şi reţinerea adresei precedentului

acestuia:prev- refacerea legăturilor:prev->urm= p->urm(1)- eliberarea memoriei

Cazurile particulare ale procedurii sunt tratate distinct prin procedurile specificede ştergere a primului sau ultimului nod.

prev

void stergere_oarecare(){int valoare; printf("\ndati cheia decautat:");scanf("%d",&valoare);tnod *p,*prev,*pvechi;p=prim;while(p!=0)

{if (p->cheie==valoare)

{//s-a găsit nodul şi acesta va fi ştersif (p==prim)

{stergere_prim();return;} //caz particular

if (p==ultim){stergere_ultim();

return;} //caz particular//cazul general

pvechi=p; //salvare adresă nod curentprev->urm=p->urm; //refacere legături

89

Page 91: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 91/166

Algoritmi şi structuri de date

free(pvechi); //eliberare memoriereturn;}

else{//nu s-a găsit încă

prev=p; //salvarea adresei precedentuluip=p->urm; //trecere la următorul nod}

}}

12. Ştergerea listei

Ştergerea completă a listei se poate realiza prin apelul repetat al funcţiilor dejaconstruit de ştergere a primului, respectiv, a ultimului nod până când lista devinevidă (pointer-ul prim devine Null). Din punct de vedere al eficienţei, varianteştergerii listei prin apelul funcţiei ştergere_primeste preferată deoarece nu necesitătraversarea listei pentru fiecare operaţie de ştergere a unui nod.

O variantă simplă dar greşită de ştergere a listei constă în distrugerea capetelor listei prim şi ultim, fapt pentru care gestionarea ulterioară a listei ( accesarea şi prelucrarea nodurilor sale ) devine imposibilă. Cu toate acestea, memoria rămânealocată nodurilor intermediare. Prin aceasta s-a distrus doar mecanismul deaccesare a nodurilor, nu s-au distrus efectiv nodurile listei.

Funcţia următoare este o variantă de ştergere a listei, prin ştergerea repetată anodurilor din capătul listei.

void stergere_lista(){tnod*p,*primvechi;p=prim;while(p!=0) //cât timp mai sunt noduri în listă

{if (prim==0)

{printf("\nlista e complet stearsa");return;}

else{ //sterg primul nod şi actualizez primprimvechi=prim;prim=prim->urm;free(primvechi);}

}}

90

Page 92: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 92/166

Algoritmi şi structuri de date

IX. LISTA DUBLU ÎNLĂNŢUITĂ

Lista dublu înlănţuită este formată din noduri care conţin:- informaţie- adresa următorului nod- adresa precedentului nod

Avantajul utilizării listelor dublu înlănţuite rezultă din posibilitatea parcurgerii(traversării) listei în ambele sensuri: de la primul la ultimul, respectiv, de la ultimulla primul nod. Acest lucru permite o manipulare mai flexibilă a nodurilor listei

Structura unui nod al listei dublu înlănţuite este următoarea:struct nod{

//declaraţii de date – câmpuri ale informaţieistruct nod *urm; //adresa următorului nodstruct nod *prec; //adresa nodului precedent

}În exemplele următoare vom utiliza un tip de date utilizator prin care specificăm

tipul nodurilor listei:

typedef struct nod{int cheie;…..//alte câmpuristruct nod *pre;struct nod* urm;}tnod;

Ca şi la lista simplu înlănţuită, principalele operaţii sunt:- crearea;- accesul la un nod; parcurgerea listei- adăugarea unui nod;- ştergerea unui nod,- ştergerea listei.

Gestionarea unei liste dublu înlănţuite se face în maniera similară listelor simpluînlănţuite prin adresele nodurilor primşi ultim. În plus, nodul prim se marchează prin stabilirea adresei precedentului său la Null:prim->prec=0.

tnod *prim,*ultim;Figura următoare sugerează maniera de organizare a unei liste dublu înlănţuite

(alocate dinamic):

91

Page 93: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 93/166

Algoritmi şi structuri de date

prim

…….Crearea listei dublu înlănţuităCrearea listei vide presupune iniţializarea celor doi pointer de control prim

şi ultim cu valoarea 0 (Null):prim=ultim=0. Crearea unei liste cu mai mult de unnod se rezumă la apelul repetat al subrutinelor de adăugare a unui nou nod (înaintea primului sau după ultimul nod).

Funcţia următoare este un exemplu prin care se poate crea o listă dubluînlănţuită prin adăugarea noilor noduri după ultimul nod. Un caz particular al procedurii de adăugare a noului nod este tratat distinct: în situaţia în care lista estevidă, după adăugarea unui nod trebuie marcate nodurile prim şi ultim. Funcţiaincarca_nod este cea definită în capitolul dedicat listelor simplu înlănţuite.void creare()

{tnod *p;int rasp;//creare lista vidaprim=ultim=0;printf("\nIntroduceti? (1/0)");scanf("%d",&rasp);while (rasp==1)

{p=incarca_nod(); //alocare memorie şi încărcare nodif (prim==0)

{//creare primul nodprim=p;ultim=p;prim->pre=0; ultim->urm=0; //marcare capete listă}

else{ultim->urm=p;

p->pre=ultim;ultim=p;ultim->urm=0;}

printf("\nIntroduceti? (1/0)");scanf("%d",&rasp);}

}

Parcurgerea listei dublu înlănţuităSpre deosebire de listele simplu înlănţuite, listele dublu înlănţuite pot fi

parcurse în ambele sensuri. Prezentăm în continuare funcţii de afişare a informaţieinodurilor parcurse în două variante: prin folosirea legăturii următor (urm),respectiv, succesor ( prec).

92

Page 94: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 94/166

Algoritmi şi structuri de date

voidtiparireDirecta(){tnod *p;if (prim==0)

{printf("\nLista e vida!");return;}

p=prim;//iniţializare adresă nod curentwhile(p!=0){printf("\n %d",p->cheie);p=p->urm; //trece la următorul nod}

}

voidtiparireInversa(){tnod *p;if (prim==0)

{printf("\nLista e vida!");return;}

p=ultim;//iniţializare adresă nod curentwhile(p!=0){printf("\n %d",p->cheie);p=p->prec; //trece la precedentul nod}

}

ADĂUGAREA UNUI NOU NODSunt tratate în continuare diferite modalităţi de adăugare a unui nou nod într-o

listă dublu înlănţuită:

13.Adăugare înaintea primului nodAdăugarea unui nou nod înaintea primului nod ale listei presupune efectuarea

următoarelor operaţii:

1. alocarea şi încărcarea noului nod:2. stabilirea faptului că acest nou nod va adresa ca următor elementchiar pe nodul prim:nou->urm=prim(1)

3. stabilirea faptului că nodulprim va referi ca precedent element penodul nou:prim->prec=nou(2)

4. stabilirea noului nod ca prim element al listei:prim=nou(3)5. marcarea nodului prim:prim->prec=0(4)

3prim

1

Observaţie:În cazul în care lista este înaintea adăugării unui nod nou, efectuloperaţiei constă în obţinerea unei liste cu un singur element, fapt pentru carecapetelor listei prim şi ultimsunt confundate şi este necesară tratarea acestui caz particular.void adaugare_prim()

{tnod *nou; p=incarca_nod();

93

Page 95: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 95/166

Algoritmi şi structuri de date

if (prim==0){prim=nou;ultim=nou;prim->prec=0;ultim->urm=0;}

else {nou->urm=prim; //pasul 1prim->prec=nou; //pasul 2prim=nou; //pasul 3prim->prec=0; //pasul 4}

}

14.Adăugare după ultimul nodAdăugarea unui nou nod după ultimul nod al listei presupune efectuarea

următoarelor operaţii:- alocarea şi încărcarea noului nod:- stabilirea faptului că acest nou nod va adresa ca precedent element

chiar pe nodul ultim:nou->prec=ultim(1)- stabilirea faptului că nodulultimva referi ca următor element pe nodul

nou:ultim->urm=nou(2)- stabilirea noului nod ca ultim element al listei:ultim=nou(3)

- marcarea nodului ultim:ultim->urm=0(4)Cazul special al procedurii (lista este vidă) se tratează în mod diferit.

…………….void adaugare_ultim()

{tnod *nou;nou=incarca_nod();if (prim==0)

{prim=nou;ultim=nou;prim->prec=0;ultim->urm=0;}

else{

94

Page 96: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 96/166

Algoritmi şi structuri de date

nou->prec=ultim; // (1)

ultim->urm=nou; // (2)

ultim=nou; // (3)

ultim->urm=0; // (4)

}}

15.Adăugare înaintea uni nod specificat prin cheieAdăugarea unui nod înaintea unui nod specificat prin valoarea cheii, se

realizează prin două etape:- căutarea nodului înaintea căruia se va face inserarea- inserarea propriu-zisă

Reamintim că la operaţia similară pentru liste simplu înlănţuite era necesarădeterminarea nodului precedent nodului precizat de cheie li acest lucru se realiza printr-un pointer auxiliar în care se reţinea acea adresă. În cazul listelor dubluînlănţuite lucrurile sunt simplificate datorită adreselor precedent conţinute defiecare nod, adrese utile în accesarea vecinilor (nodurile anterioare).

Dacă nodul căutat este chiar primul, problema se reduce la un caz particular tratat prin funcţiaadaugare_prim. Dacă lista este vidă sau nodul căutat nu s-a găsit,nu se va adăuga un nou nod.

3

nou

2p->prec

void adaugare_inainte(int valoare){tnod *p,*nou; //p contine adresa nodului curent inparcurgerea listeip=prim;while(p!=0)

{ //se parcurge direct lista, de la primul spre ultimul nodif (p->cheie!=valoare)

{//nu s-a gasit inca nodul de cheie datap=p->urm; //trecere la urmatorul nod}

else {//am gasit nodul p inaintea caruia se insereaza nou;if (p!=prim)

{

95

Page 97: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 97/166

Algoritmi şi structuri de date

nou=incarca_nod();nou->urm=p; // (1)(p->pre)->urm=nou; // (2)nou->pre=p->pre; // (3)p->pre=nou; // (4)

return;}else

{adaugare_prim();

return;}

}}

}//sfarsit functie

Observaţie: Pentru manevrarea legăturii următoare a nodului precedent celuicurent (notăm nodul curentp) este valabilă construcţia:(p->pre)->urm, unde(p->pre)este adresa precedentului noduluip.

16.Adăugare după un nod specificat prin cheieProcedura de adăugare a unui nou nod după un nod precizat prin valoarea cheii

este simalră celei prezentate la punctul3. Cazul particular este cel în care nodulcăutat este ultimul nod al listei, în această situaţie se va apela funcţiaadăugare_ultim. Dacă lista este vidă sau nu s-a găsit nodul căutat, nu are sens săse opereze adăugarea unui nou nod.

Inserarea propriu-zisă a noduluinou înaintea nodului p presupune refacerealegăturilor în aşa fel încât consistenţa listei să fie asigurată (să nu se piardăsecvenţe de noduri prin distrugerea accesului la ele ):

- nodulnouva avea ca legăturăurmpe următorul nod al nodului p:nou->urm=p->urm;(1)

- nodulp va fi urmat denou

p->urm=nou;(2)- precedentul noduluinouva fi nodulpnou->pre=p;(3)

- nodul precedent al nodului următorul luip devinenou:(p->urm)->pre=nou;(4)

void adaugare_dupa(int valoare){tnod *p,*nou;//caut p si inserez nod

p=prim;while(p!=0)

{if (p->cheie!=valoare)

96

Page 98: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 98/166

Algoritmi şi structuri de date

{p=p->urm;}

else{

if (p==ultim){adaugare_ultim();return;}else

{nou=incarca_nod();nou->urm=p->urm;p->urm=nou;nou->pre=p;(p->urm)->pre=nou;return;}

}}

}

ŞTERGEREA UNUI NODŞtergerea capetelor prim şi ultimale unei liste dublu înlănţuite nu diferă prin

costul de calcul precum la listele simplu înlănţuite. Am văzul că în cazul listelor simplu înlănţuite ştergerea ultimului nod necesita un efort computaţional mai mare.Prin legătura prec a nodurilor unei liste dublu înlănţuite putem accesa nodurile

precedent, fapt pentru care, la ştergerea ultimului nod nu este necesară traversareacompletă a listei.Ştergerea unui capăt al listei presupune:

- salvarea temporară a adresei capătului respectiv într-un pointer auxiliar - actualizarea şi marcarea noului capăt- eliberarea memoriei

Oferim în continuare două variante pentru funcţiile de ştergere a capetelor primşi ultim:

/*ştergere prim nod*/ /*ştergere ultim nod*/void stergere_prim(){tnod*primvechi;if (prim==0) //lista vidă

return;else{//mai sunt noduri

if(prim!=ultim){//salvare primprimvechi=prim;//actualizare primprim=prim->urm;//marcare primprim->pre=0;//eliberare memorie

void stergere_ultim(){tnod*ultimvechi;if (ultim==0) //lista vidă

return;else{if (prim!=ultim)

{ //salvare ultimultimvechi=ultim;//actualizare ultimultim=ultim->pre;//marcare ultimultim->urm=0;//eliberare memorie

97

Page 99: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 99/166

Algoritmi şi structuri de date

free(primvechi);}

elseprim=ultim=0;

}

}//sfarsit functie

free(ultimvechi);}else

prim=ultim=0;}

}//sfarsit functie

Ştergerea unui nod oarecareŞtergerea unui nod oarecare precizat prin valoarea cheii presupune:

- căutarea nodului- ştergerea propriu-zisă a nodului

Căutarea nodului se face prin parcurgerea într-un sens a listei şi comparareavalorii cheii nodurilor curente cu valoarea dată. Dacă se găseşte un nod careverifică condiţie, se va opera etapa de ştergere propriu-zisă a nodului prin:

o salvarea adresei nodului de şterso refacerea legăturilor pentru a asigura consistenţa listei şi

posibilitatea parcurgerii ulterioare în ambele sensurio eliberarea memoriei alocate nodului de şters

2

1

p

p->prec

Refacerea legăturilor constă din următoarele asignări:- precedentul următorului lui p devine precedentul lui p

p->urm->pre=p->pre;(1)- următorul precedentului lui p devine următorul lui p:

p->pre->urm=p->urm;(2)

Cazurile particulare se tratează separat: lista este deja vidă sau lista devine vidădupă ştergerea nodului.

void stergere_nod(int valoare){tnod *p,*pvechi;if (prim==0) return; //lista este deja vidaif (prim==ultim && prim->cheie==valoare)

{//lista devine vidaprim=ultim=0;return;}

p=prim;

98

Page 100: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 100/166

Algoritmi şi structuri de date

while(p!=0){if (p->cheie==valoare) //gasit

{if (p==prim)

{ stergere_prim ();return;}if (p==ultim){ stergere_ultim ();return;}

pvechi=p; //salvare adresă nod curent p->urm->pre=p->pre; (1) p->pre->urm=p->urm; (2)

free(pvechi); //eliberare memoriei- adresa pvechireturn;}

else //nu s-a gasit încăp=p->urm; //trecere la următorul nod

}}

Ştergerea listeiŞtergerea completă listei dublu înlănţuită se poate face cu acelaşi efort de calcul

prin apelarea repetată a funcţiei stergere_prim sau stergere_ultim. Ştergereacapetelor listei nu asigură eliberarea memoriei ocupate de nodurile intermediare.

Exemplu:ştergerea listei prin apelul repetat al funcţiei de ştergere a primului nod.

void stergere_lista(){

while(prim!=0)stergere_prim();

}

99

Page 101: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 101/166

Algoritmi şi structuri de date

X. LISTE CIRCULARE. STIVE. COZI

Lista circularăeste o listă (simplu sau dublu) înlănţuită cu proprietatea că toatenodurile sunt echivalente, respectiv, nu există noduri speciale care nu conţin adresanodurilor succesoare sau predecesoare. Aceste noduri speciale - denumite capetelelistei au fost utilizate în gestionarea listelor simplu şi dublu înlănţuite. O listăcirculară va fi gestionată prin alte mecanisme decât cele bazate pe menţinereaadreselor speciale primşi ultim.

LISTA SIMPLU ÎNLĂNŢUITĂ CIRCULARĂ

Într-o listă circulară simplu înlănţuită toate nodurile conţin adresa următoruluinod. Structura nodului este similară celei prezentate la capitolul dedicat listelor simplu înlănţuite:

typedef struct nod{int cheie; //câmp cu valori unice pentru nodurile listei//alte câmpuristruct nod *urm;//adresa următorului nod}Tnod;

Organizarea unei liste circulare cu noduri de acest tip este sugerată de figuraalăturată.

Orice listă simplu înlănţuită gestionată prin pointer-ii prim şi ultim se poate

transforma în listă circulară printr-o operaţie elementară de asignare:

ultim->urm=primPrin operaţia anterioară s-a stabilit faptul că ultimul nod al listei iniţiale vaconţine adresa primului nod al listei, ceea ce conduce la o structură de listăcirculară a cărei gestionare poate fi efectuată prin adresa pointer-ului prim, însăfără ca acesta să semnifice adresa unui capăt al listei, ci doar adresa unui nodoarecare.

Spre deosebire de listele simplu înlănţuite la care este suficientă cunoaştereaadresei primului nod şi, eventual, pentru simplificarea prelucrărilor, şi a adreseiultimului nod, într-o listă circulară, cunoaşterea adresei oricărui nod dincompunerea listei este suficientă pentru a putea gestiona această structură. Astfel,gestionarea unei liste circulare se face prin unui pointer care referă oricare nod allistei:

Tnod *pLC;//pointer lalista circulară

100

Page 102: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 102/166

Algoritmi şi structuri de date

....

pLC

Operaţiile posibile cu listele circulare sunt aceleaşi ca cele specifice listelor simplu înlănţuite:

- parcurgere- creare- distrugere (ştergere)- adăugare nou element- ştergere element

Crearea listei circulare simplu înlănţuiteCrearea listei vide se realizează prin iniţializarea pointer-ului pLC cu valoarea

Null:pLC=0;

Crearea unei liste circulare care conţine cel puţin un element presupune ooperaţie repetitivă de adăugare a unui nou nod. Pentru nodul care se adaugă se vaaloca memorie în prealabil şi se acesta va încărca cu informaţii. Funcţiaincarca_nod prezentată în capitolele precedente poate fi utilizată în acest sens.

Adăugarea nodului nou se poate efectua în două maniere:1. adăugarea înaintea nodului referit de pLC 2. adăugarea după nodul referit de pLC

Adăugarea unui nou nod înaintea nodului pLC necesită un efort computaţionalsuplimentar prin parcurgerea listei circulare. Această parcurgere este necesară pentru a determina adresa nodului precedent al nodului pLC în vederea refaceriilegăturilor şi asigurării consistenţei listei.

Acest aspect a fost evidenţiat în cazul listelor simplu înlănţuite, pentru careoperaţiile de inserare înaintea unui nod oarecare, respectiv, inserare după un nod

oarecare diferă semnificativ prin necesitatea parcurgerii complete a listei în primulcaz.

Funcţia următoare adaugă noi noduri la lista circulară gestionată prin pLC învarianta 2.

void creare_LCSI(){

Tnod *nou; int rasp;pLC=0; //lista este initial vida

printf("\nIntroduceti? (1/0)");scanf("%d",&rasp);while (rasp==1){nou=incarca_nod();//alocare memorie şi încărcare nodif (pLC==0)

101

Page 103: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 103/166

Algoritmi şi structuri de date

{//creare primul nod// nodul pLC contine adresa sa;

pLC=nou;//lista devine circulara

pLC->urm=pLC;

}else{ //adaugare nou dupa pLCnou->urm=pLC->urm;

pLC->urm=nou;pLC=nou; //pLC va contine adresa noului nod}

printf("\nIntroduceti? (1/0)");scanf("%d",&rasp);}

}

Parcurgerea listei circulare simplu înlănţuiteParcurgerea listei circulare se va face prin urmărirea legăturilor (adreselor)

conţinute de noduri, în aceiaşi manieră ca la listele simplu înlănţuite, printr-un pointer auxiliar. Specificul listelor circulare implică o altă condiţie de oprire atraversării listelor. Dacă pentru listele gestionate prin primşi ultimaceastă condiţieera evidentă (pointer-ul auxiliar prin care se parcurge lista a ajuns laultim), încazul listelor circulare condiţia se referă la revenirea în punctul de plecare. Iniţial, pointer-ul conţine adresa cunoscută a unui nod oarecare: pLC. Nodurile următoarese parcurg cât timp pointer-ul auxiliar nu va avea aceiaşi adresă de început: pLC(nu a revenit la poziţia iniţială ):

p=pLC;do{

//prelucrare nod referit de p p=p->urm; //trecere la urmatorul nod

}while ( p!=pLC );

Funcţia următoare afişează cheile nodurilor unei liste circulare:void Tiparire()

{tnod *p; //pointer-ul auxiliarp=pLC; //iniţializare pif (p==0) //lista este vida

return; // nu are sens continuarea parcurgeriido{

printf(“\n %d”,p->cheie);p=p->urm; //trecere la urmatorul nod}while (p!=pLC);

}

102

Page 104: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 104/166

Algoritmi şi structuri de date

Operaţia de căutare a unui nod specificat prin valoarea cheii presupune parcurgerea listei circulare şi verificarea dacă nodurile conţin pentru câmpulcheievaloarea dată. Funcţia prin care se realizează această operaţie va returna adresanodului găsit sau 0 în caz de insucces:

tnod* cauta(int valoare){

tnod *p; //pointer-ul auxiliarp=pLC; //iniţializare pif (p==0) return 0; //lista este vidado{

if (p->cheie==valoare)return p; //s-a gasit nodul cautat

p=p->urm; //trecere la urmatorul nod

}while (p!=pLC);return 0; //s-a incheiat cautarea si nodul nu s-a gasit

} Inserarea nodurilor într-o listă circulară simplu înlănţuită

1. Inserarea înaintea unui nod specificat prin valoarea cheii2. Inserarea după un nod specificat prin valoarea cheii

1. Inserarea unui nou nod înaintea unui nod specificat prin valoarea cheii presupune parcurgerea următoarelor etape:

- căutarea nodului de cheie dată- inserarea propriu-zisă dacă etapa anterioară s-a încheiat cu succes

Observaţie:În etapa de căutare a nodului de cheie dată se va reţine adresanodului precedent a nodului curent, pentru a face posibilă refacerea legăturilor înfaza de inserare. În caz contrar ar fi necesară o reparcurgere a listei circulare pentrua determina precedentul nodului înaintea căruia va fi inserat noul nod.

Cunoscând adresa nodului de cheie dată şi adresa precedentului său, inserarea propriu-zisă a unui nou nod se reduce la: alocarea memoriei, încărcarea nodului

nou cu informaţie şi refacerea legăturilor într-o manieră similară celei prezentate înoperaţia omonimă pentru liste simplu înlănţuite:

void inserareInainte(int valoare){

tnod *nou;tnod *prev; //precedentul nodului curenttnod *p; //pointer care refera nodul curentif (pLC==0)

return; //lista este vida, nu are sens continuare operatiei

p=pLC;do //cautarea nodului p{prev=p; //retine precedentul nodului curentp=p->urm; //trece la urmatorul nod

103

Page 105: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 105/166

Algoritmi şi structuri de date

if (p->cheie==valoare) //s-a gasit nodulbreak;//iesire din instructuinea repetitiva// p este adresa nodului gasit

}while(p!=pLC);

if (p->cheie!=valoare) //cautarea s-a incheiat cu Insuccesreturn;

if (p->cheie==valoare) //cautarea s-a incheiat cu Succes{ //etapa de inserarenou=incarca_nod(); //alocare memorie si incarcare nounou->urm=p;

prev->urm=nou;}

}

Observaţii :- nodul referit de pLC este ultimul nod verificat în etapa de căutare- instrucţiunea decizionalăif (p->cheie==valoare) …este redundantă, datfiind faptul că o condiţie precedentă verificat situaţia opusă şi provoacărevenirea din funcţie. Din motive de lizibilitate şi nu de optimizare acodului am convenit să furnizăm o variantă explicită a funcţiei pentru ourmărire uşoară a etapelor descrise.

2. Inserarea unui nod nou după un nod precizat de cheie presupune:- căutarea nodului de cheie dată- inserarea propriu-zisă

Dacă prima etapă s-a încheiat cu succes, se cunoaşte adresa nodului de cheiedatăp, dar şi adresa următorului nod (datorită legăturiiurm) p->urm. Nodulnouva fi inserat între cele două noduri de adrese cunoscute. Nu mai este necesarădeterminare altei adrese decât cea a nodului căutat după valoarea cheii.

Funcţia următoare este o posibilă implementare a operaţiei discutate:void inserareDupa(int valoare){tnod *nou;

tnod *p; //pointer care refera nodul curentif (pLC==0) return; //lista este vida, nu are sens continuareoperatieip=pLC;do //cautarea nodului p{

if (p->cheie==valoare) //s-a gasit nodulbreak; //iesire din instructuinea repetitiva// p este adresa nodului gasit

p=p->urm; //trece la urmatorul nod}while(p!=pLC);if (p->cheie!=valoare) //cautarea s-a incheiat cu Insucces

return;//dacă s-a ajuns în acest punct, cautarea s-a incheiat cu//Succes

104

Page 106: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 106/166

Algoritmi şi structuri de date

//etapa de inserarenou=incarca_nod(); //alocare memorie si incarcare nounou->urm=p->urm;

p->urm=nou;}

Observaţie : nodul referit de pLC este primul nod verificat în etapa de căutare.

Ştergerea unui nod precizat de valoarea cheii

Operaţia de ştergere a nodului precizat printr-o cheie presupune:- căutarea nodului şi reţinerea adresei precedentului său ()- ştergerea nodului: refacerea legăturilor şi eliberarea memoriei

Cazurile particulare ale operaţiei se tratează diferit:

a. lista este vidă înainte ştergerii b. lista devine vidă după ştergerec. nodul de şters este chiar pLC

Convenim că în cazul particular c. (nodul ce se va şterge este chiar nodul referitde pointer-ul pLC şi lista nu devine vidă), pLC va referi nodul precedent celuişters.

O funcţie C care descrie operaţia de ştergere este următoarea:void steregereNod(int valoare)

{tnod *p,*prev;//p - adresa nodului curent//prev - adresa precedentului nodului curent

if (pLC==0) return; //lista este vida, cazul particular (a.)p=pLC;do //cautarea nodului p{

prev=p; //retine precedentul nodului curent p=p->urm; //trece la urmatorul nod if (p->cheie==valoare) //s-a gasit nodul

break; //iesire din instructuinea repetitiva, p este adresanodului gasit }while(p!=pLC);

if (p->cheie!=valoare) return; //nu s-a gasit nodul

//nodul gasit este referit de p, urmeaza etapa de stergere

if (p->urm==p) //lista are un singur nod - nodul care se va sterge (b.){

pLC=0; //lista devine vidafree(p); //eliberare memorie}

else

105

Page 107: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 107/166

Algoritmi şi structuri de date

{if (p==pLC) //nodul de sters este referit de pLC, cazul (c.)

{pLC=prev; //actualizare pLC free(p); //eliberare memorie}

else //cazul general {

prev->urm=p->urm; //refacere legaturifree(p); //eliberare memorie}

} }//sfarsit functie steregereNod

Observaţie: în situaţia în care informaţia din noduri conţine adrese alocatedinamic (prin apelul funcţieimalloc), eliberarea memoriei alocate unui nodptrebuie să ţină cont şi de acest aspect, fapt pentru care, apelul funcţiei free(p) nueste suficient. Din aceste considerente, o funcţie specială de eliberare a memorieialocate unui nod poate fi concepută. Spre exemplu:

typedef struct nod{int CNP; //câmp cu valori unice pentru nodurile listeichar *numestruct nod *urm;//adresa următorului nod}Persoana;

Alocarea memoriei pentru un nod de tipul Persoana (Persoana *p) necesită unapel malloc pentru câmpulnume. Eliberarea memoriei alocate nodului p se vaexecuta corect prin funcţia următoare:

void eliberare_nod(Persoana *p){

free(p->nume);free(p);

}

Ştergerea liste circulare simplu înlănţuite

Operaţia de distrugere a unei liste circulare se realizează prin ştergerea tuturor nodurilor sale şi nu prin distrugerea adresei speciale pLC prin care se gestioneazălista.

Dacă nu este deja vidă, lista se parcurge şi noduri precedente nodului curent seşterg până când lista devine vidă. O funcţie de ştergere a listei circulare gestionate prin pLC este următoarea:

void stergere(){tnod *p; //nodul curenttnod *prev; //precedentul nodului curentif (pLC==0) return; //lista este deja vida

106

Page 108: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 108/166

Algoritmi şi structuri de date

p=pLC;do

{prev=p;p=p->urm;

eliberare_nod(prev);}while(p!=pLC)pLC=0; //marcare listă vidă}

Observaţie:primul nod eliberat este cel referit de pLC, fapt pentru care cândcondiţia p==pLC devine adevărată se indică revenirea în punctul de plecare a pointer-ului p ceea ce semnifică faptul că toate nodurile au fost şterse (inclusivnodul referit de pointer-ul special pLC) şi lista este vidă.

LISTA DUBLU ÎNLĂNŢUITĂ CIRCULARĂ

Lista circulară dublu înlănţuită este gestionată printr-un pointer la un nodoarecare. Structura nodului este cea prezentată la listele dublu înlănţuite şi conţine:zona de informaţii, adresa precedentului şi adresa nodului următor.

Operaţiile specifice: creare, inserare nod, ştergere nod, ştergere listă, parcurgere, căutare, sunt similare operaţiilor descrise cu liste circulare simpluînlănţuite. Diferenţele semnificative apar la procedurile de inserare înaintea unuinod precizat şi ştergerea unui nod oarecare, care se simplifică prin existenţa unei

legături spre nodurile precedente.Transformarea unei liste dublu înlănţuite în listă circulară se realizează prinlegarea capetelor primşi ultim, în ambele sensuri:

ultim->urm=prim;prim->prec=ultim;

STIVE. COZI.

Stivareprezintă un caz special de lista liniara în care intrările si ieşirile se fac laun singur capăt al ei. Organizarea structurilor de date de tip stivă se poate face îndouă maniere:

- secvenţial - elementele stivei sunt memorate la adreseconsecutive

- înlănţuit – elementele stivei nu ocupă adrese consecutive,fiecare element conţine olegătură spre următorul element.

Prin organizarea secvenţială nu se poate face economie de memorie, fapt pentrucare în general se practică organizarea înlănţuită cu alocare dinamică a stivelor.

Structura de stivă se remarcă prin operaţiile specifice: push şi pop,

corespunzătoare adăugării unui element, respectiv, ştergerii unui element în/dinvârful stivei. Principiul de funcţionare al stivei este cel cunoscut sub denumirea deLIFO (Last In FirstOut – ultimul intrat, primul ieşit).

107

Page 109: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 109/166

Algoritmi şi structuri de date

vârful

baza info

info

info

info

I Structura de date STIVĂ cualocare statică

vârful

baza

II. Structura de date STIVĂ cu alocaredinamică

Practic, stiva este o listă simplu înlănţuită pentru care operaţiile specifice selimitează la următoarele:- creare stivă vidă- adăugare element (push)- ştergere element (pop)- şterge lista (clear)- accesare – fără eliminare - a elementului din vârful stivei

În plus faţă de operaţiile enumerate anterior sunt posibile implementate operaţiide verificare:

- verifică dacă stiva este plină- verifică dacă stiva este goală

Gestionarea stivei se face în mod similar listei înlănţuite prin capetele prim şiultim. La nivel abstract, o stivă are o bază a sa şi un vârf, ceea ce convine uneiasocieri a nodurilor referite de primşi ultimicu cele două elemente specifice:

- baza stivei corespunde nodului prim şi vârful stivei corespundenodului ultim

În această abordare, operaţiile push şi pop se traduc prin operaţiile de:- adăugare a unui nou nod dupăultim(adăugare în vârful stivei)- ştergereultim(ştergere din vârful stivei)

Privitor la eficienţa operaţiilor descrise într-un capitol anterior, ne reamintim căoperaţia de adăugare a unui nou element după cel referit de pointer-ul ultimnecesita o parcurgere prealabilă a listei. În schimb, adăugarea unui nou nodînaintea celui referit de prim este mai puţin costisitoare. Din aceste considerente, se practică o inversare a rolurilor celor două capete ale stivei, pentru a obţine operaţiimai eficiente:

- baza stivei corespunde noduluiultim şi vârful stiveicorespunde nodului prim

Astfel, operaţiile push şi pop se vor traduce prin:

- adăugare a unui nou nod înainte de prim (adăugare în vârfulstivei)- ştergere prim(ştergere din vârful stivei)

108

Page 110: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 110/166

Algoritmi şi structuri de date

Coadaeste un alt caz special de listă înlănţuită bazat pe principiul FIFO (FirstIn First Out – primul intrat, primul ieşit). Acest principiu arată că primul elementintrodus în listă este şi primul care va fi şters. O structură de acest gen are douăcapete, denumite sugestiv:cap şi coadă .

Operaţiile primare cu cozi sunt:- creare stivă vidă- adăugare element încoadă - ştergere element dincap- şterge lista (clear)

Spre deosebire de stivă, adăugarea şi ştergerea unui element se execută încapetele diferite ale cozii.

Ca şi în cazul stivelor, organizarea unei cozi poate fi făcută în mod secvenţial(static) – prin intermediul tablourilor unidimensionale sau dinamic – prin listesimplu înlănţuite. Cea de-a doua variantă este de preferat din raţiuni economice.

primCoada este astfel o listă înlănţuită ale cărei capete referite prin prim şi ultim

semnificăcapul şi coada structurii, ceea ce permite organizarea în două maniere:- primreferă capul listei şiultimreferăcoada listei- ultimreferă capul listei şi primreferăcoada listei

Conform celor două abordări enumerate anterior, operaţiile de adăugare şiscoatere elemente în/din lista FIFO se traduc prin:

- adăugare după nodul ultim şi ştergere nod prim- adăugare înainte de prim şi ştergere nod ultim

Constatăm că spre deosebire de stive, ambele abordări sunt eficiente, astfel încâtalegerea oricărei variante este posibilă. Printr-o convenţie, adăugarea unui nod seface după ultimul nod (coada) al listei, iar scoaterea din listă a unui nod esteimplementată prin ştergerea nodului prim(cap).

109

Page 111: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 111/166

Page 112: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 112/166

Algoritmi şi structuri de date

- Nivelul nodului: reprezintă o valoarea naturală prin care seidentifică numărul de strămoşi până la nodul rădăcină.

o Nodul rădăcină este considerat pe nivelul 1o Fiii nodului rădăcină sunt pe nivelul 2

o Fiii fiilor nodului rădăcină sunt pe nivelul 3o etc.- Ordinul nodului: este un număr natural şi reprezintă numărulde descendenţi direcţi (fii) pe care îi are nodul respectiv. Nodurileterminale au ordinul 0.

5

9

4

87

6

Nivelele nodurilor în arbore

Nodul Ordinul nodului1 O(1)=22 O(2)=33 O(3)=04 O(4)=25 O(5)=06 O(6)=17 O(7)=0

8 O(8)=09 O(9)=0Ordinul fiecărui nod din arborele prezentat ca exemplu

Fiecare subarbore al arborelui este caracterizat prinînălţimeasa, mărime carereprezintă numărul de nivele pe care le conţine subarborele respectiv.

Un nod al arborelui conţine:d. zona de datee. 1 sau mai multe legături spre fii săi

Dacă între fiii oricărui nod există o relaţie de ordine, spunem că arborelerespectiv estearbore ordonat .

111

Page 113: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 113/166

Algoritmi şi structuri de date

Dacă numărul de fii ai fiecărui nod din compunerea unui arbore este 0,1 sau 2,atunci arborele respectiv este numitarbore binar . Structura unui nod al arborelui binare conţine:

- zona de informaţii

- legătură spre fiul stâng - legătură spre fiuldrept Într-un arbore binar, există posibilitatea ca una sau ambele legături ale unui

părinte spre fiii săi să fie nule. Nodurile terminale au ambele legăturile nule.Anumite noduri interne pot să aibă doar un fiu, astfel încât legătura spre celălalt fiueste nulă.

Importanţa studierii arborilor binari este dată de multitudinea de aplicaţii practice în care se face uz de această structură de date. În plus, un arbore poate fitransformat şi reprezentat prin arbore binar. Transformarea presupune etapeleurmătoare:

1. se stabileşte legătură între fraţii de acelaşi părinte2. se suprimă legăturile dinspre părinte, cu excepţia legăturii cu

primului fiu Exemplu:Fie arborele oarecare din figura următoare:

2

5 6

Figura 1 Arbore oarecare

După transformare, arborele devine binar:

112

Page 114: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 114/166

Algoritmi şi structuri de date

1

2

5

67

Figura 2 Arbore binar

Parcurgerea arborilor

Parcurgerea (traversarea) arborilor presupune obţinerea unei liste a nodurilor arborelui. În funcţie de ordinea în care sunt considerate nodurile arborelui, avemmai multe tipuri de traversare a arborilor.

- Parcurgerea în adâncime (in depth): se vizitează subarborii descendenţiai nodului rădăcină, în aceiaşi manieră, apoi se vizitează nodul rădăcină.

Parcurgerea în adâncime a arborelui considerat ca şi exemplu în figura 1 produce următoarea listă a nodurilor: 7 5 6 2 3 4 1.- Parcurgerea în lăţime (in breadth): se vizitează nodurile pe nivele,

pornindu-se de la nivelele cele mai de sus (nivelul 1 – rădăcina) sprenivelele mai mari, şi pe fiecare nivel se vizitează nodurile într-o anumităordine, spre ex. de la stânga la dreapta. Parcurgerea în lăţime a arboreluidin figura 1 produce lista: 1 2 3 4 5 6 7.

ARBORI BINARI

Structura unui nod al arborelui binar este următoarea:typedef struct nod

{//informaţiistruct nod * st;//legătura spre subarborele stângstruct nod * dr;//legătura spre subarborele drept}Tnod;

unde:st – este un pointer, a cărei valoare este adresa fiului stâng a nodului curentdr – este un pointer, a cărei valoare este adresa fiului drept a noduluicurent

113

Page 115: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 115/166

Algoritmi şi structuri de date

Absenţa unui fiu (stâng sau drept) se marchează prin valoarea Null (0) a pointer-ului corespunzător.

Gestionarea unui arbore binare este posibilă prin adresa nodului rădăcină:Tnod *rad;

Operaţiilespecifice arborilor binari sunt:1. crearea arborelui2. inserarea unui nod3. ştergerea unui nod4. ştergerea arborelui5. accesarea unui nod (căutarea)6. parcurgerea unui arbore

Operaţia de creare a arborelui binar necesită iniţializarea nodului rădăcină:rad=0 şi adăugarea (inserarea) ulterioară a noilor noduri după o anumită regulă.Operaţiile de inserare şi accesare a nodurilor dintr-un arbore binar presupunexistenţa unui criteriu care se desprinde din specificaţiile problemei concrete derezolvat. Aceste criterii fiind variate, rezolvarea problemelor cu arbori binare se poate simplifica prin considerarea unei funcţiiverifică care are doi parametri: pnod1 şi pnod2 – adresele a două noduri şi returnează valoare -1,0 sau 1 cusemnificaţia:

A) -1 dacă pnod2este adresa unui nod care poate fi accesat sau inserat în stânganodului adresat de pnod1

B) +1 dacă pnod2este adresa unui nod care poate fi accesat sau inserat îndreaptanodului adresat de pnod1C) 0 dacă pnod2 referă un nod care NU poate fi accesat sau inserat în

subarborii stâng sau drept ai nodului referit de pnod2.Prototipul acestei funcţii ajutătoare este:

int verifica(Tnod * pnod1 , Tnod * pnod2 );Inserarea unui nou nod presupune:

- determinarea locului în care va fi inserat noul nod- alocarea de memorie şi încărcarea cu informaţii a nodului nou- stabilirea legăturilor în arbore

În privinţa locaţiei în care poate fi inserat nodul, aceasta este dată de criteriulspecificat de problema concretă şi se disting următoarele cazuri:

- în poziţia rădăcinii- ca nod terminal- ca nod intern

Ştergerea unui nod oarecare presupune:- determinarea locaţiei sale- refacerea legăturilor în arbore- eliberarea memoriei alocate nodului şters

Ştergerea întregului arbore necesită ştergeri repetate ale nodurilor sale pânăcând rădăcina devine vidă.

Parcurgereaunui arbore binare poate fi făcută în trei moduri:

114

Page 116: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 116/166

Algoritmi şi structuri de date

1. parcurgerea în preordine: pentru fiecare nod curent se vaaccesa/prelucra informaţia conţinută, subarborele stâng şi în finalsubarborele drept. (fiecare subarbore va fi parcurs în aceiaşi manieră).

- Simplificat, parcurgerea în preordine a unui arbore presupune parcurgerea în ordinea:R (rădăcină),S(subarbore stâng),S (subarbore stâng).R S D

2. parcurgerea în postordine: pentru fiecare nod curent se va parcurge subarborele stâng, subarborele drept şi în final se vaaccesa/prelucra informaţia conţinută în nodul curent (fiecare subarboreva fi parcurs în aceiaşi manieră).

- Simplificat parcurgerea în postordine înseamnătraversarea arborelui în ordinea:S (stâng)D(drept)R (rădăcină)

3. parcurgerea în inordine: pentru fiecare nod curent se va parcurgesubarborele stâng, nodul curent şi în final subarborele drept (fiecaresubarbore va fi parcurs în aceiaşi manieră).

- Simplificat: ordinea de traversare a arborelui esteS (stânga)R (rădăcină)D (dreapta).

Exemplu:

La parcurgerea în preordinea arborelui din figura anterioară se vor accesanodurile în ordinea:J H E A B F I G C DLaparcurgerea în postordinese vor accesa nodurile în ordinea:

A B E F H C G D I JLaparcurgerea în inordinese vor accesa nodurile în ordinea:

A E B H F J I C G DFuncţiile de parcurgere a unui arbore binar în cele trei variante (preordine,

postordine, inordine) sunt date mai jos:

void preordine(tnod *p){if p!=0

{//vizitarea nodului curent ( tipărirea cheii )

115

Page 117: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 117/166

Algoritmi şi structuri de date

printf(“\t%d”, p->cheie);//parcurgere subarbore stâng//autoapelare funcţie preordine

preordine(p->st);//parcurgere subarbore stâng

//autoapelare funcţie preordine preordine(p->dr);}

}

void inordine(tnod *p){if (p!=0)

{inordine(p->st);

printf(" %d",p->cheie); //vizitare nodinordine(p->dr);}

}

void postordine(tnod *p){if (p!=0)

{ postordine(p->st); postordine(p->dr);

printf(" %d",p->cheie);}

}

Căutarea unui nod

Fiind dat uncriteriu de căutare, căutarea într-un arbore binar presupune parcurgerea nodurilor şi verificarea criteriului pentru fiecare nod vizitat. În cazulîn care s-a găsit un nod care respectă criteriul, procesul de parcurgere a arborelui seva încheia. Dacă nu se găseşte niciun nod care verifică criteriul, acest lucru trebuie

semnalat.În scopul definirii unei funcţii de căutare în arborele binar, se consideră funcţiaauxiliară prin care se verifică îndeplinirea sau neîndeplinirea criteriului de căutareşi continuare căutării într-unul din subarborii stâng sau drept ai nodului curent. Înmod frecvent, criteriul se referă la îndeplinirea condiţiei de egalitate între o valoaredată şi valoarea unui câmp din informaţia memorată în noduri. Pentru a generaliza,considerăm funcţiaverificaredescrisă anterior prin care se decide dacă un nodcăutat pnod2 este găsit în arbore la adresa pnod1, sau se va continua căutarea însubarborele stâng sau drept a nodului adresat de pnod1.

O funcţie de căutare se poate descrie ca mai jos. Funcţia returnează adresanodului găsit sau 0 în cazul în care nu se găseşte un nod care verifică criteriulstabilit.

tnod *rad; //variabilă globală

116

Page 118: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 118/166

Algoritmi şi structuri de date

tnod *cautare(tnod *pnod2){ // caută nodul din arbore care este echivalent cu pnod2tnod *p;if rad==0 return 0; //arborele este vidwhile (p!=0)

{if (verificare(p,pnod2)==0)

return p; //s-a găsit nodulelse

if (verificare(p,pnod2)==-1)p= p->st; //continuare cautare la stanga

elsep= p->dr; //continuare cautare la stanga

}return 0; //nu s-a gasit nodul cautat}

Crearea unui arbore binarOperaţia de creare a unui arbore binar presupune operaţii repetate de inserare a

unui nou nod ca nod terminat. Pentru fiecare nod care urmează să fie inserat estenecesară în prealabil determinarea poziţiei în care acesta va fi adăugat, respectiv, părintele de care acesta se va lega. Nodul părinte se va determina printr-o

parcurgere parţială a arborelui. În realizarea acestei operaţii ne putem folosi defuncţia auxiliarăverificasau o altă funcţie prin care se decide în care din subarboreva fi continuată căutarea posibilului părinte.

ARBORI BINARI DE CĂUTARE

Un caz particular de arbori binari suntarborii binari de căutare . În plus faţă deaspectele menţionate la prezentarea arborilor binari, un arbore de căutare prezintă ocaracteristică suplimentară: fiecare nod al său conţine ocheie(câmp cu valori unice pentru nodurile arborelui) şi:

- toate nodurile din stânganodului respectiv au valorile cheilor mai mici decât cheia nodului curent

- toate nodurile dindreaptanodului respectiv au valorile cheilor mai maridecât cheia nodului curent

Exemplu:Figura alăturată ilustrează reprezentarea grafică a unui arbore binar decăutare (valoarea cheii este precizată în fiecare nod):

117

Page 119: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 119/166

Algoritmi şi structuri de date

4

5

2

31

6

Se poate observa o proprietate importantă a arborilor binari de căutare: la parcurgerea îninordinese obţinelista nodurilor ordonate după valoarea cheii.În plus, operaţia de căutare a unui nod specificat de valoarea cheii este simplificată(de aici şi denumirea arborilor de căutare).

Căutarea unui nod după o cheie dată nu necesită parcurgerea întregului arbore.Datorită specificului acestor arbori, valoarea cheii este comparată cu cheiaconţinută în rădăcină şi în funcţie de rezultatul comparaţiei, căutarea se va continuadoar într-unul dintre cei doi subarbori, celălalt subarbore fiind exclus din căutare.Procedeul se va continua în mod similar pentru subarborele curent: se comparăvaloarea cheii căutate cu cheia rădăcinii subarborelui şi în funcţie de rezultatulcomparaţiei se va continua căutarea doar într-unul dintre subarborii subarboreluicurent. Căutarea se va încheia în momentul în care un nod rădăcină a subarboreluicurent conţine cheia căutată sau dacă nu mai sunt noduri de parcurs şi cheia nu afost găsită.

Căutarea unei informaţii într-o structură de arbore binar de căutare esteeficientă, deoarece numărul nodurilor accesate se reduce prin excluderea acelor subarbori a căror parcurgere ar fi inutilă.

Operaţiile de inserare şi ştergere executate asupra unui arbore binar de căutarevor produce de asemenea un arbore binar de căutare. Astfel, în definirea unor funcţii specifice care operează asupra arborilor de căutare se va ţine cont decriteriul de ordine între cheile nodurilor ce formează arborele.

1. Creare arbore binar de căutare. Inserarea nodurilor.

Fiind dată o mulţime de informaţii ce trebuie organizate sub forma unui arbore binar de căutare, crearea arborelui se realizează în următoarele etape:

- creare arbore vid- creare arbore cu un singur nod (rădăcină)- inserarenoduri cât timp mai există informaţie de organizatLa fiecare pas de inserare unui nod în arborele deja format se va ţine cont de

criteriul de ordonare şi arborele rezultat va fi tot un arbore binar de căutare.Dacă rădăcina este vidă înainte de inserare, nodul de inserat va deveni rădăcinaarborelui:

rad=nou; rad->st=rad->dr=0;

118

Page 120: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 120/166

Algoritmi şi structuri de date

Dacă există cel puţin un nod în arbore, se va căuta un părinte al nodului deinserat. Acest părinte îndeplinească condiţiile:

- dacă cheia conţinută de părinte este mai mare decât cheia nodului nou,atunci, părintele trebuie să aibă legătura stângă vidă, pentru a reuşi legarea noduluinou în stânga sa (prin aceasta ne asigurăm că subarborele construit, al căreirădăcină este nodul părinte, este ordonat)

- dacă cheia conţinută de părinte este mai mică decât cheia nodului nou,atunci, părintele trebuie să aibă legătura dreapă vidă

int inserare(tnod *nou)

{ tnod *p;nou->st=nou->dr=0;if (rad==0)

{//creare radacina

rad=nou;rad->st=rad->dr=0;return 1;}

p=rad;while(1){

if (nou->cheie<p->cheie)if (p->st!=0)

p=p->st;else

{p->st=nou;nou->st=nou->dr=0;return 1;}else

if (p->dr!=0)p=p->dr;

else{p->dr=nou;nou->st=nou->dr=0;return 1;}

}return 0; //nu s-a realizat operaţia, cod de eroare}

Arborele binar de căutare se poate construi printr-o secvenţă:printf("\ncate noduri introduceţi?"); scanf("%d",&n);tnod *nou;rad=0; //arbore vidfor (int i=0;i<n-1;i++){nou=incarca_nod();if (nou!=0) //s-a reu it încărcareaș

{j=inserare(nou);

if (j==0) //nu s-a reuşit inserareaeliberare_nod(nou);//eliberare memorie alocată pt. nou}

}

119

Page 121: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 121/166

Algoritmi şi structuri de date

2. Căutarea unui nod de cheie precizatăCăutarea după valoarea cheii este operaţia specifică în arborele binar de căutare

prin care se determină adresa nodului a cărei cheie este egală cu o valoare dată.Dacă nu se găseşte un astfel de nod, operaţia se încheie cuinsucces.

Construim mai jos o funcţie care primeşte ca parametru valoarea cheii căutateşi returnează:- adresa nodului găsit, sau- 0, în caz de insucces

tnod * cautare(int val){tnod *p;p=rad;while(p!=0) //câttimp mai sunt noduri de vizitat

{ if (p->cheie==val)return p; //s-a gasit nodul

if (val<p->cheie){ //continuare căutare în subarbore stângp=p->st; }

if (p->cheie<val){//continuare căutare în subarbore dreptp=p->dr; }

}return p; //nu s-a găsit nodul, p este Null

}

3. Ştergere nod de cheie precizată

Ştergerea unui nod de cheie precizată, precum şi celelalte operaţii specificearborilor de căutare, va produce un arbore cu aceleaşi caracteristici (cheilenodurilor rămân ordonate după ştergere).

Prima etapă a operaţiei de ştergere constă în determinarea nodului de cheie precizată (nodul ce se va şterge). În acest scop este utilă o funcţie care caută cheiaîn arbore, însă faţă de operaţia de căutare descrisă anterior, este nevoiedeterminarea unui element suplimentar: adresa părintelui nodului ce va fi şters.

În funcţie de poziţia nodului de şters:p şi a părintelui său în arbore:parinte,întâlnim următoarele cazuri:

a. nodul găsit este nod frunză (nod terminal) şi este situat îndreapta părintelui său:- se eliberează nodul- se stabileşte legătura dreaptă a părintelui ca fiind nulă:

parinte->dr=0 b. nodul găsit este nod frunză (nod terminal) şi este situat în stângapărintelui

său:- se eliberează nodul- se stabileşte legătura stângă a părintelui ca fiind nulă:

parinte->st=0

120

Page 122: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 122/166

Algoritmi şi structuri de date

c. nodul căutat nu este nod terminal, dar are doar un subarborestâng- leagă părintele de subarborele stâng al nodului de şters:

o dacă nodul este legat înstângapărintelui, atunciparinte->st=p->st – cazul c.1

o dacă nodul este legat îndreapta parintelui, atunciparinte->dr = p->st – cazul c.2- eliberează nodul

d. nodul căutatp nu este nod terminal, dar are doar un subarboredrept- leagă părintele de subarborele drept al noduluip:

o dacă nodul este legat înstângapărintelui, atunciparinte->st=p->dr– cazul d.1

o dacă nodul este legat îndreapta parintelui, atunciparinte->dr = p->dr – cazul d.2

- eliberează nodule. nodul căutatp nu este terminal şi are ambii subarbori (legăturile stânga şidreapta sunt nenule).

O altă manieră de stabilire a cazurilor de ştergere în arborele binar este dată deordinul nodului ce va fi şters:

Dacă nodul are ordinul 0 sau 1 (are maxim un subarbore) este util să grupămcazurile descrise mai susa,b,c,d într-o singură tratare: părintele noduluip vaconţine adresa subarborelui luip (stâng sau drept), chiar dacă acest subarbore estevid (nodul p este terminal ).

Dacă ordinul nodului p este 2, se va trata cazule.

Cazule este cel mai complex caz de ştergere a unui nod. Numim predecesor alnodului p, cel mai din dreapta nod din subarborelui stâng al lui p. Numim succesor al nodului p, cel mai din stânga nod din subarborelui drept al lui p. Atât predecesorul cât şi succesorul unui nod oarecare, sunt noduri terminale în arboreledat.

Exemplu:

4

7

4

121

Page 123: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 123/166

Algoritmi şi structuri de date

Nodurile predecesor şi succesor au proprietate că sunt nodurile de cheieimediat mai mică, respectiv, imediat mai mare decât cheia nodului p, şi sunt noduricu un singur subarbore, fapt pentru care ştergerea nodului p se realizează prin:

- copierea informaţiei din predecesor/succesor în nodul p

- ştergerea predecesorului/succesorului nodului p- cazul ştergerii unuinod cu un subarborePractic, ştergerea unui nod cu doi subarbori se transformă într-o căutare a altui

nod care are maxim un subarbore, urmată de ştergerea acestuia. Exemplu:

4

5

2

31

6

7

Predecesor

Figura 3 Înainte de ştergerea nodului

3

2

1

Figura 4 După ştergerea nodului

Observaţii: Dacă nodul p ce va fi şters este părintele direct al predecesoruluisău, atunci predecesorul esteîn stângapărintelui său (în stânga nodului p).Dacă nodul p ce va fi şters nu este părintele direct al predecesorului său, atunci,

predecesorul este legat de părintele său direct prinlegătura dreaptă . Exemplu: În figura anterioară, nodul 4 nu este părintele direct al predecesorului

(nodul 3), astfel încât, predecesorul este legat în dreapta părintelui său direct – nodul 2.

Ne imaginăm următoarea situaţie:

3 Nodul

de sters

În acest caz, pentru nodul de şters se va actualiza legătura stângă. După operaţiade ştergere, arborele devine:

122

Page 124: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 124/166

Algoritmi şi structuri de date

4

1 5

6

Funcţia de mai jos este o variantă de implementare a algoritmului de ştergere aunui nod dintr-un arbore de căutare. Se acordă atenţie nodului rădăcină, acesta fiindun nod important prin care se gestionează arborele. Dacă acest nod trebuie şters,tratarea cazului se face în mod diferit pentru protejarea adresei de acces la arbore.void stergere()//stergere nod de cheie data{tnod *p,*tatap,*predecesor,*tatapredecesor;int cheie;printf("\ndati cheia");scanf("%d",&cheie);p=rad;//caut nodul p;while(p!=0)

{if (p->cheie==cheie)break;if (cheie<p->cheie) {tatap=p;p=p->st;}if (cheie>p->cheie) {tatap=p;p=p->dr;}}// caut p si retine parintele sau

if (p==0) {printf("\n Nu exista cheia cautata!!!");return;}

//cazul I________________________nod frunzaif ((p->st==0)&&(p->dr==0)){

if (p==rad) rad=0; //arborele devine vidif (tatap->st==p) // cazul a

{ tatap->st=0;eliberare_nod(p);return;}

if (tatap->dr==p) // cazul b{ tatap->dr=0;eliberare_nod(p);return;}

}//cazul II________________________nod cu un subarbore

// cazul c , p are doar subarbore stangif (p->dr==0)

{

123

Page 125: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 125/166

Page 126: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 126/166

Algoritmi şi structuri de date

}//sfîrşit functie stergere

4. Ştergere arbore binar de căutare

Ştergerea completă a arborelui binar constă în ştergerea tuturor nodurilor sale.În acest scop se poate defini o funcţie recursivă prin care se parcurge arborele în post ordine şi vizitarea nodului constă în eliberarea sa. Ultimul nod eliberat estenodul rădăcină.void stergere_arbore(tnod *p)

{if (p!=0){stergere_arbore(p->st);stergere_arbore(p->dt);

eliberare_nod(p);}}

Apelul funcţiei este:stergere_arbore(rad);

ARBORI BINARI ECHILIBRAŢI (AVL)

Un caz special de arbori binari ordonaţi (arbori de căutare) sunt arborii AVL(descrişi deAdelson,Velski,Landis). Aceştia au în plus proprietatea de echilibru ,formulată prin:

Pentru orice nod al arborelui diferenţa dintre înălţimea subarborelui stâng al nodului şi înălţimea subarborelui drept al nodului este maxim1.

Fiecărui nod într-un arbore AVL îi este asociată o mărime denumită factor deechilibru. Factorul de echilibru se defineşte prin diferenţa dintre înălţimilesubarborelui drept şi înălţimea subarborelui stâng, şi pentru arborii echilibraţi poatefi una dintre valorile -1, 0, +1. Dacă factorul de echilibru pentru un nod are altă

valoare decât cele enumerate, arborele nu este arbore AVL.Operaţiile posibile asupra arborilor AVL sunt aceleaşi operaţii ca în cazularborilor binari ordonaţi simpli: creare, inserare, ştergere, parcurgere, căutare. Înschimb, în operaţiile asupra arborilor AVL trebuie ţinut cont de proprietatea deechilibru din moment ce o operaţie de inserare a unui nod nou sau de ştergere aunui nod poate conduce la arbori binari dezechilibraţi.

Practica este următoarea: operaţiile definite pentru arborii de căutare se aplică şiasupra arborilor AVL, însă, ulterior, este verificată îndeplinirea proprietăţii deechilibrare. În cazul în care arborele a devenit dezechilibrat, prin operaţiisuplimentare se va reorganiza arborele pentru obţine un arbore echilibrat.

Probleme propuse spre rezolvare

125

Page 127: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 127/166

Algoritmi şi structuri de date

1. Se citeşte de la tastatură o expresie matematică în formă prefixata, sub formaunui şir de caractere (operatorul este plasat în faţa operanzilor). Să seconstruiască arborele corespunzător acestei expresii. Fiecare nod conţine unoperator sau un operand. Să se evalueze expresia.

2. Să se scrie o funcţie care numără într-un arbore binar ordonat câte noduriconţin chei cu valori cuprinse în intervalul [a,b].3. Scrieţi o funcţie care calculeazănivelul şi factorul de echilibrarepentru oricare

nod al unui arbore binar.

126

Page 128: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 128/166

Algoritmi şi structuri de date

XII. ELEMENTE DE GRAFURI. ALGORITMI.

Definiţie: Graf este o pereche ordonată de mulţimiG =(X, Γ ), unde X este omulţime de vârfuri, iar Γ = X×X este o mulţime demuchii sau arce (pentru grafuri orientate).

Exemplu:

1

3

4

5

O muchie de la vârful x la vârful y este notata cu perechea ordonata (x, y), dacăgraful esteorientat şi în mod uzual este folosit termenul dearc, si cu mulţimea{ x, y}, dacă graful esteneorientat . În reprezentarea grafică, arcele (x,y) suntmarcate prin săgeţi de la extremitatea iniţială x la cea finală y, iar muchiile prinsegmente.

Într-un graf orientat, existenţa unui arc de la vârful x la vârful y nu presupune şiexistenţa arcului de la y la x. În grafurile neorientate, dacă există muchie între x şiy, atunci aceasta este şi muchie între vârfurile y şi x. Vârfurilor unui graf li se potataşa informaţii numite uneorivalori, iar muchiilor li se pot ataşa informaţii numitecosturi.

Următoarele noţiuni sunt specifice grafurilor:Două vârfuri unite printr-o muchie se numescadiacente.Undrumeste o succesiune de muchii de forma:(x1, x2), (x2, x3), ..., (xn-1, xn) – în graf neorientatsau de forma

{ x1, x2}, { x2, x3}, ..., { xn-1, xn} – în graf neorientatUn lanţ se defineşte ca o succesiune de vârfuri x1, x2, x3, … xn în care oricaredouă vârfuri sunt adiacente.

Într-undrum simplumuchiile care îl compun sunt distincte.Într-undrum elementar vârfurile care îl compun sunt distincte. Lungimeadrumului este egala cu numărul muchiilor care îl constituie.Un lanţ elementar al grafuluiG care conţine toate vârfurile grafului se numeşte

lanţ hamiltonian.Determinarea unui lanţ hamiltonian al grafului este o problemăfoarte populară cunoscută ca Problema Comis Voiajorului rezolvată prin metodaGreedy.

Unciclueste un drum care este simplu şi care are drept capete un acelaşi vârf.Un graf fără cicluri se numeşte graf aciclic.Un subgraf al luiG este un graf G’=(X',Γ '), unde X' × X, iar Γ ' este formata

din muchiile dinΓ care unesc vârfuri din X'.

127

Page 129: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 129/166

Algoritmi şi structuri de date

Un graf parţial este un graf (X,Γ "), undeΓ " ⊆ Γ .Un graf neorientat esteconex, dacă între oricare doua vârfuri exista un drum.

Pentru grafuri orientate, aceasta noţiune esteîntărită : un graf orientat estetareconex, dacă între oricare două vârfuri x si y exista un drum de la x la y si un drum

de la y la x.

Reprezentarea grafurilor

1. Prin matricea de adiacenta A, în care A[i, j] =1 dacă vârfurilei si j suntadiacente, iar A[i, j] =0 în caz contrar.

2. Prin liste de adiacenta: fiecare vârf i are ataşată lista de vârfuri adiacentelui (pentru grafuri orientate, este necesar ca muchia sa plece dini).

3. Prin lista de muchii. Aceasta reprezentare este eficienta atunci când sedoreşte examinarea tuturor muchiilor grafului.

4. Prinmatricea costurilor (grafuri neorientate etichetate)C în care C[i, j] ≠0este costul asociat muchiei, iar C[i, j] =0 semnifică faptul că nu existămuchie {i,j}.

Parcurgerea grafurilor

Parcurgerea unui graf presupune vizitarea intr-o anumita ordine nodurilor grafului, o singura dată fiecare. În functie de ordinea de parcurgere a vârfurilor

exista 2 metode de parcurgere:1. Metoda parcurgerii în lăţime -Breadth First2. Metoda parcurgerii în adâncime -Depth First

1. Parcurgerea în lăţime Breadth First : se vizitează vârful stabilit iniţialxs,apoi vecinii acestuia (vârfurile adiacente) apoivecinii vecinilor lui xs, etc.Procedura de parcurgere în lăţime funcţionează după următorul principiu: atuncicând s-a ajuns într-un vârf oarecare x nevizitat, îl marcăm si vizităm apoi toatevârfurile adiacente lui x rămase nevizitate, apoi toate vârfurile nevizitate adiacentevârfurilor adiacente lui x, etc. La parcurgerea în lăţime se foloseşte o structură decoadă pentru a putea vizita toţi vecinii unui nod dat înainte de a-l marca dreptvizitat .

Subalgoritm BreadthFirst (x)este //x reprezintă vârful curentC=Φ // iniţializarecoadavidă*Marchează x cavizitat Inserare(C,x) //inserare vârfului x în coada CCâttimp(C≠Φ)

Scoate(C,y) //scoate din coadă vârful yPentru fiecare vârf z, adiacent lui yDacăz estenevizitat atunci

*Marchează z cavizitat

128

Page 130: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 130/166

Page 131: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 131/166

Algoritmi şi structuri de date

În cazul unui graf neconex, se pune problema determinării componentelor saleconexe:

O componenta conexaa grafului G=(X, M), este un subgraf G’=(X', M'), conexşi maximal. Maximalitatea se referă la faptul că nu exista lanţ în grafulG care saaibă o extremitate în X’ şi pe cealaltă în X\X’.

Un arbore este un graf neorientat, aciclic şi conex. Într-un arbore exista exactun drum între oricare doua vârfuri.

Un graf parţial care este arbore se numestearbore partial . Un arbore parţial este un graf parţial fără cicluri.

Arborele parţial de cost minim(suma costurilor muchiilor este minimă) sedetermină printr-un algoritm de tip Greedy: Algoritmul lui Kruskal .

Algoritmul de determinare a Arborele parţial de cost minim (APM).

Problema APM:Se dă un graf G=(X,Γ ) cu muchiile etichetate princosturi(datele de intarre sunt reprezentate prin matricea costurilor).Se cere determinareaarborelui parţial de cost minim a grafului dat. (datele de ieşire sunt muchiile care formează arborele parţial de cost minim)

Rezolvare: Algoritmul lui Kruskal este un algoritm cunoscut de rezolvare a problemei enunţate şi este un algoritm de tip Greedy. Principiul acestui algoritmeste următorul:

Considerând graful G=(X,Γ

), A=(X,Γ

’) – arborele ce se determină(reprezentat prinlista de muchii) şi n – numărul de vârfuri n=|X|:- se porneşte cu arborele vid:Γ ’=Φ- în mod repetat se alege muchia de cost minim a grafului G care nu

formează ciclu în arborele A şi se adaugă laΓ ’- algoritmul se termină când au fost alese n-1 muchii

AlgoritmKruskaleste:Date de intrare: G=(X,Γ )

FieΓ

’=ΦCâttimp(|Γ ’|<n-1)*Alege {i,j} de cost minim dinΓ

Dacă Γ ’∪{i,j} nu conţine cicluriΓ ’=Γ ’∪{i,j}Γ =Γ \ {i,j}

SfDacăSfCâttimpDate de ieşire: A=(X,Γ ’)

SfAlgoritm

130

Page 132: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 132/166

Algoritmi şi structuri de date

Observaţie:Mulţimea muchiilor grafului dat se poate ordona descrescător dupăcosturi şi se va parcurge în mod secvenţial, fără a mai fi necesară procedura dealegere a muchiei de cost minim din graful G.

131

Page 133: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 133/166

Algoritmi şi structuri de date

XIII. METODE DE ELABORARE A ALGORITMILOR. DIVIDE ET IMPERA.

Metode Divide et Impera este o metodă de rezolvare a unor probleme şi esteinspirată de principiul “Împarte şi stăpâneşte”. În conformitate cu principiulamintit, o problemă de complexitate mare se va împărţi în subprobleme de acelaşitip însă de dimensiuni mai mici ale căror rezolvare se va dovedi mai simplă. Deasemenea, subproblemele obţinute prin descompunerea problemei pot fi la rândullor împărţite în subprobleme mai mici. Etapa de împărţirea se consideră încheiatăcând subproblemele devin elementare - rezolvabile imediat. Soluţiilesubproblemelor se vor combina pentru a alcătui soluţia globală a problemei.

Metoda descrisă poate fi aplicată în condiţiile în care problemele admit oîmpărţire în subprobleme de acelaşi fel. Putem vorbi de un specific al problemelor rezolvabile cu Divide et Impera. Acest specific este dat de următoarele afirmaţii:

- problema globală se poate împărţi în 2 sau mai multe subproblemeasemănătoare de dimensiuni mai mici

- subproblemele obţinute prin împărţire sunt independente, ceea ce permiteca soluţiile parţiale ale acestora să nu depindă unele de altele

- contextul problemei ne permite să identificăm condiţia ca o subproblemăsă fie considerată elementară şi să nu mai fie supusă unei împărţiriulterioare

- subproblemele obţinute prin împărţire admit aceiaşi metodă de rezolvarefiind probleme de acelaşi fel.

Exemple de probleme celebre rezolvabile cu metoda Divide et Impera sunt: problema Turnurilor din Hanoi, Sortarea rapidă, etc.

Fie P – problema globală,n – dimensiunea ei şiS – soluţia dorită. Fien0 –

dimensiunea minimă a unei probleme pentru care aceasta devine elementară şiadmite o rezolvare imediată.Deoarece toate subproblemele sunt tratate prin aplicarea aceluiaşi algoritm,

diferenţa făcându-se doar prin datele de intrare-ieşire şi dimensiuneasubproblemelor, precum şi datorită faptului că soluţiile obţinute sunt soluţii parţialeale problemei globale, descrierea potrivită a metodei este dată printr-unsubalgoritm autoapelabil. De altfel, implementarea în limbaj de programare se face prin proceduri (funcţii) recursive.

Subalgoritm DivideEtImpera(P _formal , n _ formal ; S _ formal ) este:Dacă n _formal < n0atunci

#rezolvă imediat subproblemaP _formal şi obţine soluţiaS _formal Altfel

#împarte problemaP _formal de dimensiunen _formal în:

132

Page 134: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 134/166

Page 135: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 135/166

Page 136: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 136/166

Algoritmi şi structuri de date

elsereturn max2;

}

void main()

{int a[NMAX],dim;citire(a,&dim);int max;max=maxim(a,0,dim-1);printf("Maximul este: %d",max);}

Problema 2: Problema turnurilor din Hanoi. Se dau3 tije simbolizate prinA,B,C.Pe tijaA se găsescn discuri de diametre diferite, aşezate de jos în sus în ordine

crescătoare a diametrelor. Se cere sa se mute toate discurile de pe tijaA pe tijaB,utilizând ca tija intermediara tijaC, respectând următoarele reguli:- la fiecare pas se muta un singur disc ;- nu este permis sa se aşeze un disc cu diametrul mai mare peste un disc cudiametrul mai mic.

A B C

Analiza problemei:Cazul elementar al problemei constă în existenţa unui singur disc pe tija A,

ceea ce reduce rezolvarea la o mutare a discului de pe tija A pe tija B.Pentru n=2 (două discuri), rezolvarea problemei constă în 3 mutări,

folosind tija intermediară C:- mută discul mai mic de pe tija A pe tija C- mută discul mai mare de pe tija A pe tija B- mută discul mic de pe tija C pe tija B

Generalizând, pentru un număr oarecaren de discuri situate pe tija A,rezolvarea problemei se reduce la parcurgerea următoarelor etape:- mută primele n-1 discuri de pe A pe C, utilizând tija B ca intermediară- mută discul rămas de pe tija A pe tija B

135

Page 137: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 137/166

Algoritmi şi structuri de date

- mută cele n-1 discuri de pe C pe B, utilizând tija A ca intermediară

Observăm că problema s-a redus la două probleme de dimensiuni mai mici,respectiv, de a efectua mutarea an-1 discuri. Aceiaşi manieră de abordare a

problemei de dimensiunen-1va reduce problema la mutarea an-2discuri, ş.a.m.d.În cele din urmă, pentru cazul elementar al unui singur disc ce trebuie mutat, se vaaplica rezolvarea directă.

Subalgoritmul Hanoiva trata problema transferului a k discuri de pe tija X, petija Y, folosind tija rămasă Z ca intermediară:

Subalgoritm Hanoi(k,X,Y,Z) este:Dacăk=1atunci

Mută discul de pe tija X pe tija Y //rezolvare directă, problemăelementară

Altfel Cheamă Hanoi(k-1,X,Z,Y)Mută discul rămas de pe X pe Y //problemă elementarăCheamăHanoi(k-1,Z,Y,X)

SfDacăSfSubalgoritm

Apelul subalgoritmului pentru rezolvarea problemei globale este:Cheamă Hanoi(n,A,B,C)

Program:#include <stdio.h>void Hanoi (int n, int A, int B, int C)

{if (n>0){

Hanoi (n - 1, A, C, B);printf("\nMuta discul de pe tija %c pe tija %c",A,C);Hanoi( n-1, B, A, C);

}

}//sfarsit Hanoivoid main (){

int n;printf("\nDati numarul de discuri:"); scanf("%d",&n);Hanoi (n, ‘A’, ‘B’, ‘C’); //apel hanoi

}

Problema 3:Căutare Binară . Fiind dat un vector ordonat den valori numerice, săse determine poziţia pe care se regăseşte o valoare datăcheie.

Analiza problemei:Căutarea unei valoricheieîntr-un vector ordonat den valori se poate reduce la o problemă mai simplă (de dimensiune mai mică) dacă ne folosim de informaţia căvectorul este ordonat. Acest lucru ne permite să împărţim vectorul în două părţi

136

Page 138: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 138/166

Algoritmi şi structuri de date

relativ egale, să comparăm cheia cu valoarea elementului de pe poziţia tăieturii şisă decidem continuarea căutării într-unul dintre subvectorii rezultaţi, ignorând acea parte care nu poate conţine cheia căutată. Subvectorul în care se continuă căutarea poate fi la rândul său împărţit în două părţi pentru a obţine probleme mai mici.Împărţirea se termină în condiţiile în care cheia a fost găsită sau subvectorul pecare îl manevrăm nu poate fi împărţit (este format din maxim un element).

Decizia continuării căutării într-unui dintre subvectorii rezultaţi printr-oîmpărţire precedentă se face pe baza unei comparaţii simple a elementului de pe poziţia tăieturii, notat xmij, cu cheia căutată. Rezultatul comparaţiei poate fiurmătorul:

- cheie egală cu valoarea elementului xmij – rezultă că am găsit poziţiamijacheii

- cheie mai mică decât xmij - rezultă că vom continua căutarea în prima partea vectorului, între elementele situate la stânga poziţieimij

- cheie mai mare decât xmij – rezultă că vom continua căutarea întreelementele din dreapta poziţieimij

Subalgoritmul de rezolvare a problemei de căutare binară se descrie astfel:Subalgoritm CăutareBinară (xinf , …, xsup ,cheie;poz) este:

Dacăsup-inf <= 0 atunci// vectorul curent conţine un singur element

Dacăxinf = cheie atunci

poz=inf Altfelpoz= -1// semnificaţia faptului că nu s-a găsit cheia

SfDacăAltfel

// vectorul curent conţine mai mult de un elementmij= (sup+inf)/2Dacăcheie=xmij atunci

poz=mij //am găsit poziţia cheiiAltfel

Dacăcheie<xmij atunci Cheamă CăutareBinară (xinf , …, xmij ,cheie;poz)Altfel Cheamă CăutareBinară (xmij+1, …, xsup ,cheie;poz)SfDacă

SfDacăSfSubalgoritm

Apelul Cheamă CăutareBinară (x1 , …, xn ,cheie;poz) rezolvă problema

globală. Dacă valoareapozeste egală cu -1 la terminarea apelului, cheia nu a fostgăsită în vectorul dat, în caz contrar, valoareapoz reprezintă poziţia pe care a fostgăsită cheia căutată.

137

Page 139: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 139/166

Algoritmi şi structuri de date

Problema 4. Sortare rapidă (QuickSort).Algoritmul de sortare rapidă esteun exemplu tipic de algoritm Divide et Impera. Fiind dat un vector oarecare denelemente se cere ordonarea crescătoare a vectorului după valorile elementelor.

Ideea de bază a sortării rapide constă în împărţirea vectorului în doisubvectori cu proprietatea că toate elementele primului sunt mai mici decât unelement pivot şi elementele celui de-al doilea subvector sunt mai mari decât pivotul. Alegerea pivotului rămâne în sarcina programatorului, existând treivariante plauzibile: pivotul este elementul median al subvectorului manevrat, pivotul este elementul de pe prima poziţie, respectiv, pivotul este ales ca elementulde pe ultima poziţie din subvector. În descrierea următoare, pivotul este ales cafiind elementul de pe poziţia mediană.

Împărţirea vectorului în două părţi care verifică proprietatea enunţatănecesită operaţii de interschimbare a valorilor elementelor de pe poziţii diferite.Odată ce etapa de împărţire a fost parcursă, cei doi subvectori rezultaţi vor fi supuşiaceluiaşi procedeu de împărţire. Problema devine elementară implicit dacăsubvectorul corespunzător are dimensiunea 1, fiind considerat ordonat. Combinareasoluţiilor nu necesită o etapă distinctă, făcându-se în mod implicit, prininterschimbările elementelor vectorului dat în apelurile recursive alesubalgoritmului.

Împărţirea unui şir de elemente xinf , …,xsup se face parcurgând paşii:1. iniţializează doi indici de parcurgere a subşirului în două sensuri:i –

indicele de parcurgere a şirului de la stânga la dreapta, respectiv, j – indicele de parcurgere de la dreapta la stânga; iniţial,i=inf , j=sup.

2. stabileşte pivotul (elementul de pe poziţie mediană din şir)3. câttimp pivotul este mai mare decât elementele de pe poziţiile parcurse dela stânga la dreapta, efectuează avans la dreapta al indicelui i

4. cât timp pivotul este mai mare decât elementele de pe poziţiile parcurse dela stânga la dreapta, efectuează avans la dreapta al indicelui i

5. dacă i<j interschimbă valorile de pe poziţiile i şi j şi actualizează indicii prin avans la dreapta, respectiv la stânga

6. repetă paşii 3, 4 şi 5 până când valoarea indiceluii devine mai mare decâtvaloarea lui j

După parcurgerea paşilor 1-6 se consideră subşirul xinf , …,xsup împărţit în douăsubşiruri: xi, …,xsup şi xinf , …,x j. Dacă subşirurile obţinute conţin mai mult de 1element, acestea se vor supune aceluiaşi procedeu descris.

Subalgoritmul corespunzător metodei descrise anterior este următorul:

Subalgoritm QuickSort (xinf , …,xsup)este:Fie i=inf şi j=supmij=(inf+sup)/2 //mij – reprezintă poziţia pivotului xmij

Repetă Câttimp( i<sup şi xi<xmij)//avans la dreaptai=i+1

138

Page 140: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 140/166

Algoritmi şi structuri de date

SfCâttimpCâttimp( j>inf şi x j>xmij)

//avans la stânga j=j-1

SfCâttimpDacăi<jatunci

Cheamă Interschimbare(xi,x j)SfDacă

Pânăcând (i>j)Dacă (i<sup)atunci

CheamăQuickSort (xi, …,xsup)SfDacăDacă (j>inf)

CheamăQuickSort (xinf , …,x j)SfDacăSfSubalgoritm

Pentru rezolvare problemei globale se va efectua apelul:Cheamă QuickSort (x1, …,xn)

Program C:#include <stdio.h>void citireSir(int x[10],int *n)

{int i;printf("\ndati n=");scanf("%d",n);for(i=0;i<*n;i++)

{printf("\nX[%d]=",i+1);scanf("%d",&x[i]);}

}void tiparireSir(int x[10],int n){int i;for(i=0;i<n;i++)

printf("%d ",x[i]);}void SQuick(int x[10],int st, int dr){int i,j,k,M;i=st; j=dr;M=x[(st+dr)/2];

do{

//avans la stangawhile ((i<dr) && (x[i]<M)) i++;//avans spre dreaptawhile ((j>st) && (x[j]>M)) j--;if (i<j)

139

Page 141: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 141/166

Algoritmi şi structuri de date

{//interschimb x[i] cu x[j]k=x[i];x[i]=x[j];x[j]=k;}

if (i<=j) {i++; j--;}}while(i<=j);if (i<dr) SQuick(x,i,dr); //daca subsirul 1 mai are cel putin1 elem ..if (j>st) SQuick(x,st,j); //daca subsirul 2 mai are cel putin1 elem ..}

void main(){int a[10],n;

citireSir(a,&n);SQuick(a,0,n-1);tiparireSir(a,n);

}

Problema 4. Sortarea prin interclasareeste o tehnică de ordonare a unuivector. Principiul de bază este acela al împărţirii vectorului iniţial în două părţiegale (subvectori), prin sortarea părţilor rezultate şi ulterior interclasarea celor doisubvectori ordonaţi, rezultând vectorul global ordonat. Fiecare dintre cei doi

subvectori obţinuţi la o împărţire precedentă, la rândul lor pot fi împărţiţi fiecare îndouă părţi, urmând ca subvectorii de dimensiune mai mică să fie supuşi aceluiaşimecanism de ordonare prin interclasarea şi să obţinem subvectori ordonaţi, dedimensiuni mai mari.

Operaţia de interclasare a doi vectori a fost discutată într-un capitol precedent.Această operaţie presupune parcurgerea secvenţială a celor doi vectori ordonaţi şiconstruirea celui de-al treilea vector prin copierea elementelor din cei doi vectoricu restricţia de a păstra relaţia de ordine între elementele vectorului rezultat. Înalgoritmul de sortare prin interclasare,vectorii ce vor fi interclasaţi sunt de faptsubvectori ai aceluiaşi vector, ceea ce conduce la o procedură de interclasare uşor diferită faţă de cea prezentată în capitolulIII.Observăm că problema generală permite o împărţire în subproblemeindependente mai mici rezolvabile prin aceiaşi tehnică, ceea ce ne permite oabordare prin metoda Divide et Impera. Subproblemele se consideră elementaredacă dimensiunea subvectorilor devine 1, ceea ce este echivalent afirmaţiei“subvector ordonat”.

Subalgoritmul prin care se realizează sortarea prin interclasareeste descris încontinuare:

140

Page 142: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 142/166

Algoritmi şi structuri de date

Subalgoritm MergeSort (xinf , …, xsup) este:Dacăsup-inf<1atunci // nu se efectuează nimic, se revine din apelul subalgoritmului (condiţia// de terminare a recursivităţii), considerând că subvectorul curent de// dimensiune 1 este ordonatAltfel

Fie mij=(inf+sup)/2Cheamă MergeSort (xinf , …, xmij)Cheamă MergeSort (xmij+1, …, xsup)//interclasarea subvectorilor xinf , …, xmij şi xmij+1, …, xsup i=inf // i – indicele de parcurgere a subvectorului xinf , …, xmij

j=mij+1 // j – indicele de parcurgere a subvectorului xmij+1, …, xsup

k=1 // k –parcurgerea vectorului rezultat y1 ,…, ydim

Câttimp (i<=mij şi j<=sup)Dacă(xi<x j) atunciyk =xi // se copiază din primul subvector i=i+1k=k+1

Altfelyk =x j // se copiază din al doilea subvector j=j+1k=k+1

SfDacăSfCâttimpCâttimp(i<=mij) //au mai rămas elemente în primul subcvector

yk =xi // se copiază din primul subvector i=i+1k=k+1

SfCâttimpCâttimp(j<=sup) //au mai rămas elemente în primul subcvector

yk =x j // se copiază din al doilea subvector j=j+1k=k+1SfCâttimp

// copierea vectorului y în vectorul xinf , …, xsup

Pentru i de la1 la k-1xi+inf-1=yi

SfPentruSfDacă

SfSubalgoritm

ApelulCheamă MergeSort (x1 , …, xn) va produce ordonarea vectorului global

Interclasare

141

Page 143: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 143/166

Algoritmi şi structuri de date

Program C:Ordonarea unui vector prin metoda sortării prin interclasare.

#include <stdio.h>void citireSir(int x[10],int *n)

{int i;printf("\ndati n=");scanf("%d",n);for(i=1;i<=*n;i++){printf("\nX[%d]=",i+1);scanf("%d",&x[i]);}}

void tiparireSir(int x[10],int n){int i;

for(i=1;i<=n;i++) printf("%d ",x[i]);}

void MergeSort(int x[], int inf, int sup){int mij,k,i,j;int y[20];if(inf<sup){

mij=(inf+sup)/2;mergesort(x,inf,mij);mergesort(x,mij+1,sup);//merge(x,inf,sup,mij);i=inf;j=mij+1;k=inf;while((i<=mij)&&(j<=sup)){

if(x[i]<x[j]){ y[k]=x[i];

k++;i++;}

else{ y[k]=x[j];

k++;j++;}

}

while(i<=mij){ y[k]=x[i]; k++; i++; }while(j<=sup)

{ y[k]=x[j]; k++; j++; }for(i=inf;i<k;i++)

x[i]=y[i];

}}

void main(void){int a[10],n;citireSir( a,&n);MergeSort(a,1,n);tiparireSir(a,n);}

142

Page 144: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 144/166

Algoritmi şi structuri de date

XIV. METODE DE ELABORARE A ALGORITMILOR.GREEDY

Metoda Greedy (greedy = (en.)lacom) este o tehnică de rezolvare problemelor de optimizare bazată pe principiul alegerii “lacome” a optimului local în vedereadeterminării optimului global. Soluţia unei probleme abordată cu metoda Greedy seconstruieşte treptat, prin alegeri corecte, optimale şi irevocabile ale soluţiilor parţiale. Dezavantajul major al metodei constă în incapacitatea determinării soluţieioptime globale pentru orice problemă.

Pentru a aplica metoda Greedy, problema abordată trebuie reformulată într-omaniera şablonprin care se pot identifica datele de intrare sub forma unei mulţimiA, datele de ieşire sub forma unei submulţimiB a mulţimii de intrareA şi anumitecondiţii specifice problemei care ne permit alegerea unei soluţii parţiale optimale:

FieAo mulţime den elemente:A={a1,a2,…,an}.Se cere determinarea submulţimiiB, AB ⊆ astfel încâtB este maximală şiverifică anumitecondiţii.

Principiul de rezolvare:- Se porneşte cu mulţimea vidăB={}, care ulterior va fi completată cu

elemente ale mulţimiiA- Se parcurge mulţimeaA, element cu element, şi se verifică pentru fiecare

membru al mulţimiiA condiţiileidentificate din contextul problemei.Dacă aceste condiţii sunt verificate, elementul respectiv va fi „înghiţit” demulţimeaB

- Procedeul se încheie în două situaţii:o S-a determinat mulţimea maximalăBo Nu mai sunt elemente de parcurs în mulţimeaA

Există două variante ale algoritmului Greedy:- cu ordonarea în prealabil a mulţimii A- fără ordonarea mulţimii ADescrierea algoritmică a metodei generale este prezentată în continuare, cu

menţiunea că propoziţiile nestandard (introduse prin prefixarea cu simbolul*) nu pot fi rafinate decât pentru problema concretă de rezolvat:

Algoritm Greedy este: //varianta fără ordonarea mulţimii ADate de intrare:ADate de ieşire:BFieB={}Câttimp(A≠Φ) şi (*B nu este optimă)

*Alege ai din ADacă B ∪{ai} *este soluţie posibilăatunci

B = B ∪{ai} sau * ai înlocuieşte un element dinBA=A \{ ai }SfDacă

SfCâttimp

143

Page 145: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 145/166

Algoritmi şi structuri de date

SfAlgoritm

Algoritm Greedy2 este: //varianta cu ordonarea mulţimii A după uncriteriuDate de intrare:ADate de ieşire:BFieB={}*Ordonează mulţimeaAPentru i de la1 la n

Dacă B ∪{ai} este soluţie posibilăatunciB = B ∪{ai} sau ai înlocuieşte un element dinB

SfDacăSfPentru

SfAlgoritm

Problema 1. Problema monedelor.Se consideră o mulţime infinită de monede de valori 1,k 1,k 2,...,k n-1 şi S o sumăexprimabilă prin aceste monede. Se cere determinarea unei scheme de exprimare asumei S utilizând un număr optim (minim) de monede.

Analiza problemei:Din problema formulată mai sus putem deduce mulţimea de intrareA ca fiind

mulţimea monedelor de valori 1,k 1,k 2,...,k n-1, considerând că numărul de monede deaceiaşi valoare este nelimitat. Soluţia problemei este reprezentată dintr-o

submulţimeB de monede, nu neapărat de valori diferite, astfel încât dimensiuneasubmulţimii este minimă şi suma valorilor monedelor conţinute deB nu depăşeştesuma dată S.

Rezolvarea logică a problemei constă în parcurgerea paşilor:- iniţializează mulţimea B cu mulţimea vidă- se alege cea mai mare unitate monetară k j care este mai mică valoric decât

suma S- Cât timp suma S rămâne pozitivă adaugă moneda k j la mulţimeaB şi scade

valoarea monedei din suma S- alege monede de valoare imediat mai mică decât k j, respectiv, k j-1

- Cât timp suma S rămâne pozitivă adaugă moneda k j-1 la mulţimeaB şiscade valoarea monedei k j-1din suma S

- alege monede de valoare imediat mai mică decât k j-1, respectiv, k j-2

- ...- Procesul se continuă până când nu mai există valori monetare mai mici

care ar putea fi adăugate mulţimiiB

Procedeul descris anterior corespunde unui algoritm Greedy: soluţia globală seconstruieşte treptat prin alegeri succesive şi irevocabile ale unităţilor monetare ceintră în alcătuirea schemei de exprimare a sumei S. Lăcomiaprocedeului este datăde maniera de parcurgere a valorilor monetare, de la cele mai mari înspre cele maimici, ceea ce permite formarea unei mulţimiB de dimensiune minimă (cu cât

144

Page 146: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 146/166

Algoritmi şi structuri de date

valorile monetare sunt mai mari, cu atât numărul monedelor prin care se exprima Seste mai mic).

Algoritmul GreedyUnităţiMonetare este:Date de intrare: S,k,nDate de ieşire: BFieB={}*Caută cel mai mare j pentru care k j<=SCâttimp(j≥0)

Câttimp(S- k j≥ 0)S=S- k j B=B ∪{ k j }

SfCâttimp j=j-1 //alege următoarea valoare monetară, mai mică

SfCâttimpDatele de intrare ale algoritmului descris sunt suficiente pentru a defini

mulţimeaA: cunoscând k, n şi faptul că numărul de monede de acelaşi tip estenelimitat, mulţimea A se subînţelege ca fiind:A= {1,1,… , k,k,…,k 2, k 2,… … k n-

1,k n-1,…..}

Problema 2. Problema Rucsacului.Se consideră o mulţimeA de n obiectecaracterizate fiecare princapacitateşi importanţă : A= {a1,a2,…,an}:

ni ,...,1=∀

, wi – importanţa obiectului ai ni ,...,1=∀ , ci – importanţa obiectului ai Se cere determinarea unei scheme de încărcare optimă a unui rucsac de

capacitate maxim permisăC cu obiecte din mulţimea A: suma importanţelor obiectelor selectate trebuie să fie maximă şi suma capacităţilor obiectelor selectatenu trebuie să depăşească capacitatea maximăC .

Observaţie:Varianta fracţionară a problemei rucsacului permite ca anumiteobiecte să fie încărcate în fracţiuni, soluţia finală oferită de metoda Greedy fiindoptimul global. Pentru problema discretă a rucsacului (obiectele nu pot fi împărţite pe fracţiuni), metoda Greedy nu determină întotdeauna optimul global.

Analiza problemei (varianta discretă ): Strategia de încărcare a rucsacului(iniţial gol) este de a introduce treptat în rucsac acel obiect din mulţimea obiectelor disponibile, pentru care raportul capacitate – importanţă este minim, ceea cecorespunde construirii unei soluţii parţiale optime. Practic, la fiecare pas deconstruire a soluţiei vom prefera un obiect de importanţă mare şi capacitate mică.Alegerea “lacomă” a obiectelor garantează obţinerea unei soluţii finale bune.Faptul că asupra alegerilor efectuate nu se revine determină ca în multe situaţiisoluţia optimă globală să nu poată fi găsită.

Se observă că mulţimea obiectelor A se parcurge în ordine crescătoare dupăraportul capacitate – importanţă, ceea ce ne conduce la construirea unui algoritmGreedy în varianta a doua, cu ordonarea elementelor mulţimiiA.

145

Page 147: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 147/166

Algoritmi şi structuri de date

Algoritmul de rezolvare a problemei rucsacului, varianta discretă, este descris încontinuare:

Algoritm Rucsac este:Date de intrare:A= {a1,a2,…,an}//pentru care se cunosc wi şi ci , ni ,...,1=∀

Date de intrare:C –capacitatea rucsaculuiDate de ieşireB //mulţimea obiectelor selectate în rucsac

OrdoneazăA ,crescător după valorile rapoartelor wi/ci

FieC B=0 //suma capacităţilor obiectelor selectateFieB={}Pentru i de la1 la n

Dacă ( C B + ci ≤ C ) atunciB=B∪ {ai}C B =C B + ci

SfDacăSfPentru

SfAlgoritm

Problema 3. Planificarea spectacolelor.Se consideră o mulţime den activităţi(spectacole)A= {a1,a2,…,an}, fiecare activitate ai fiind caracterizată prin ora dedebut si şi ora de terminare ti. Într-o sală de spectacole, se doreşte o selecţie aactivităţilor disponibile astfel încât să fie derulate, într-o singură zi cât mai multe

spectacole şi acestea să nu se intercaleze.Se cere un orar al spectacolelor astfel încât numărul lor să fie maxim posibil şisă nu existe suprapuneri.

Analiza problemei:Din analiza specificaţiilor problemei se deduce imediatformularea specifică unei probleme rezolvabile prin metoda Greedy:

Se dă A= {a1,a2,…,an}Se cere AB ⊆ astfel încâtB este maximală şi verifică anumitecondiţii.

Condiţiile se referă la ne-suprapunerea oricăror două activităţi planificate.Ceea ce este dificil de stabilit, este maniera de alegere, la fiecare pas, a

următoarei activităţi din mulţimea activităţilor disponibile (neplanificate deja), pentru a obţine în final o planificare optimă.Identificăm trei variante de alegere a următoarei activităţi pe care o planificăm :- în ordine crescătoare, după timpul de start si - în ordine crescătoare, după durata activităţii: di = ti-si - în ordine crescătoare, după timpul de terminare ti

Dintre cele trei variante enunţate, doar cea de-a treia se dovedeşte plauzibilă.Pentru primele două cazuri vom demonstra ineficienţa prin contraexemple:

Contraexemplu 1.

146

Page 148: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 148/166

Algoritmi şi structuri de date

Considerăm cazul particular descris în imaginea alăturată. Fiecare activitate estereprezentată printr-un segment ale cărui capete marchează timpul de start şi determinare. Prin alegerea spectacolelor în ordinea crescătoare a timpului de debut, seva alege ca primă activitate planificată: a1 şi se constată imposibilitatea selectăriiunei alte activităţi fără să existe suprapuneri. Algoritmul ar furniza în acest cazsoluţiaB={a1}cu toate că există o soluţie mai bună:B={a2,a3}.

Contraexemplu 2.

Prin alegerea în ordinea crescătoare a duratei activităţilor disponibile, în cazul particular figurat în imaginea alăturată, prima activitate selectată este a1. Aceastăalegere se dovedeşte neinspirată deoarece nicio altă activitate nu va mai putea fi planificată ulterior, datorită suprapunerilor. Soluţia ar fi în acest cazB={a1} cutoate că există o soluţie mai bună:B={a2,a3}.

Algoritmul de rezolvare a problemei planificării spectacolelor implicăordonarea mulţimii de intrare, crescător, după timpul de terminare a activităţilor:

Algoritm GreedySpectacole este:

Date de intrare:A= {a1,a2,…,an}// pentru care se cunosc si şi ti ,ni ,...,1=∀

Date de ieşireBFieB={}*Ordonează crescător Adupă valorile ti Pentru i de la1 la n

Dacă*(nu există a j ∈ B,astfel încât ai se suprapune lui a j) atunciB=B∪ {ai}

SfDacăSfPentru

SfAlgoritm

Observaţie: Două activităţi ai şi a j se consideră că nu se suprapun ddacă esteverificată condiţia:si>t j sau s j>ti.

t4

t3s3t2s2

t1s1

s4

t4

t3s3t2s2

t1s1

s4

147

Page 149: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 149/166

Algoritmi şi structuri de date

XV. METODE DE ELABORARE A ALGORITMILOR. BACKTRACKING.

Metoda Backtracking (căutare cu revenire) este o metodă generală de rezolvarea unei clase de probleme de optimizare bazată pe principiul construirii soluţiilor, înmod treptat, prin alegeri succesive ale soluţiilor parţiale. Spre deosebire de metodaGreedy, bazată pe acelaşi principiu, Backtracking oferă posibilitatea reveniriiasupra unor decizii anterioare, fapt care conduce la obţinerea soluţiilor optimeglobale în orice situaţie. În plus, dacă sunt mai multe soluţii, metoda le determină pe toate.

Metoda căutării cu revenire realizează o explorare sistematică a spaţiuluisoluţiilor posibile, construieşte soluţiile finale, fără a genera însă toate soluţiilor

posibile din care s-ar putea extrage doar acele soluţii ce îndeplinesc condiţiispecifice problemei. Un dezavantaj major al metodei este acela că este o metodărelativ costisitoare în privinţa timpului de execuţie.

Problemele rezolvabile cu metoda Backtracking sunt probleme în care soluţiaeste reprezentată sub forma unui vector:

S x x x x n∈= },...,,{ 21 ,

ni ,...,1=∀ , ii A x ∈

unde n A A AS ×××= ..21 , şi i A sunt mulţimi finite nu neapărat distincte.Cerinţa problemei este determinarea tuturor soluţiilor posibile, care satisfac

anumitecondiţii specifice problemei(denumitecondiţii interne).O abordare simplistă ar genera toate soluţiile posibile - elementele produsuluicartezian n A A AS ×××= ..21 , şi ulterior s-ar verifica aceste soluţii în vedereaidentificării acelora care verifică condiţiile interne. Abordarea aceasta esteneeficientă. Generarea tuturor soluţiilor implică memorie şi timp suplimentar.Backtracking este o alternativă inspirată de rezolvare a problemelor de acest gen.Metoda evită generarea tuturor soluţiilor posibile, soluţiile finale se obţin prinalegerea succesivă de elemente din mulţimile1 A , 2 A , …, n A cu posibilitatearevenirii asupra unei alegeri dacă aceasta nu a condus la obţinerea unei soluţii

finale.Algoritmii Backtracking pornesc cu o soluţie iniţială reprezentată de vectorulvid. Ulterior acesta va fi mărit prin adăugarea elementelor k x din mulţimeacorespunzătoare k A , treptat pentru k=1,2,…. Dacă vectorul parţial

},...,,{ 21 k x x x verifică anumite condiţii de validare, deduse din condiţiileinterne, se va continua cu augmentarea vectorului curent prin adăugarea unui nouelement 1+k x din mulţimea corespunzătoare 1+k A . Dacă vectorul nuîndeplineşte condiţiile de validare se încearcă un nou element din mulţimeak A şi

se reverifică condiţiile de validare. Există posiblitatea cak A să nu mai conţinăalte elemente care au rămas neverificate, ceea ce produce orevenirela o decizieanterioară şi încercarea unui alt element pe poziţia anterioarăk-1din vector.

148

Page 150: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 150/166

Algoritmi şi structuri de date

Asupra vectorului soluţie se acţionează prin doar două operaţii: adăugare nouelement după ultimul adăugat, respectiv, eliminare ultim element adăugat. Acesteoperaţii corespund unor operaţii cunoscute: push şi pop; astfel, vectorul soluţiefuncţionează pe principiul unei stive.

O problemă se identifică ca o problemă rezolvabilă prin metoda Backtrackingdacă putem identifica următoarele aspecte din specificaţiile sale:

1. spaţiul soluţiilor este unprodus cartezian n A A AS ×××= ..21

2. soluţia probleme poate fi reprezentată ca unvectorS x x x x n

∈= },...,,{ 21

3. există un set de condiţii prin care putem decide dacă o soluţie parţialădată de vectorul },...,,{ 21 k x x x , nk ≤ este validă →condiţiile devaliditate

4. există un set de condiţii prin care putem decide dacă o soluţie parţialăeste finală →condiţiile de finalitate5. soluţia (vectorul) se poate construi pas cu pas, astfel încât dacă

},...,,{ 21 k x x x este valid, are sens completarea vectorului cu unelement pe poziţiak+1.

Considerăm soluţia parţială },...,,{ 21 k x x x reprezentată ca stivă în imaginilealăturate:

Cazul 1… … … …

Nivelul k+1 xk+1 Nivelul k+1 x k+1

Nivelul k x k Nivelul k x k

Nivelul k-1 x k-1 Nivelul k-1 x k-1

… … … …

Nivelul 2 x 2 Nivelul 2 x 2

Nivelul 1 x 1 Nivelul 1 x 1

Cazl 2.1… … … …

Nivelul k+1 xk+1 Nivelul k+1 xk+1

Nivelul k x k Nivelul k *k x

Nivelul k-1 x k-1 Nivelul k-1 x k-1

… … … …

Nivelul 2 x 2 Nivelul 2 x 2

Nivelul 1 x 1 Nivelul 1 x 1

149

Page 151: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 151/166

Algoritmi şi structuri de date

Cazul 2.2… … … …

Nivelul k+1 xk+1 Nivelul k+1 xk+1

Nivelul k x k Nivelul k xk

Nivelul k-1 x k-1 Nivelul k-1 x k-1

… … … …

Nivelul 2 x 2 Nivelul 2 x 2

Nivelul 1 x 1 Nivelul 1 x 1

Tratarea niveluluik se face diferenţiat pentru cazurile următoare:

Cazul 1. },...,,{ 21 k x x x

verifică condiţiiile de validitate: în acest caz se vatrece la completarea nivelului următor al stivei cu un element1+k x din 1+k A .(operaţie push). Dacă vectorul parţial verifică şi condiţiile de finalitate se vafurniza soluţia.

Cazul 2. },...,,{ 21 k x x x NU verifică condiţiile de validitate şi:Cazul 2.1. mai există elemente dink A care nu au fost încercate, atunci:

- se alege alt element *k x neîncercat din k A şi se reverifică

condiţiile de validitate.

Cazul 2.2 Nu mai există elemente dink A

rămase neîncercate, atunci:- se revine pe nivelul anterior k-1(operaţie pop).

Procesul este unul repetitiv, pentru fiecare nivel curent al stivei se va procedasimilar. Descrierea algoritmului se poate face în două variante: iterativ şi recursiv,şi în ambele situaţii vom considera subalgoritmii de tip funcţie prin care se verificăcondiţiile de validitate respectiv de finalitate pentru o soluţie parţială oarecare

},...,,{ 21 k x x x .

Funcţie Valid (k ) este://verifică dacă soluţia parţială },...,,{ 21 k x x x din stivă este validă sau

nu//întoarce Adevarat sau Fals în funcţie de rezultatul testului

SfFuncţie

Funcţie Final (k ) este://verifică dacă soluţia parţială },...,,{ 21 k x x x este finală sau nu//întoarce Adevarat sau Fals în funcţie de rezultatul testului

SfFuncţie

Varianta Iterativă:

Algoritm BackTrackingIterativ este:

150

Page 152: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 152/166

Algoritmi şi structuri de date

k=1 //iniţializarea nivelului stivei Câttimp(k≥1) Dacă( ∃ k k A x ∈ “neîncercat” ) atunci

[ ] k xk Stiva ← //operaţia push

Dacă Valid (k )=AdevaratatunciDacă Final (k )=AdevaratatunciTipăreşte “Soluţie:”Stiva [ ] [ ]k StivaStiva ,..,1

Altfelk=k+1 //trece la alt nivel

SfDacăSfDacă

Altfel[ ] Null k Stiva = //operaţia pop

k=k-1 //revine la nivelul precedent SfDacăSfCâttimp

SfAlgoritm

Varianta recursivă:

Subalgoritm Backtracking ( k ) este: //tratează nivelul k Pentru fiecare k k A x ∈

[ ] k xk Stiva

← //operaţia pushDacă Valid (k )=AdevaratatunciDacă Final (k )=Adevaratatunci

Tipăreşte “Soluţie:”Stiva [ ] [ ]k StivaStiva ,..,1 Altfel

Cheamă Backtracking ( k+1) //autoapel SfDacă

SfDacăSfPentru

SfSubalgoritmObservaţie: În varianta recursivă, operaţiile pop (revenirea pe un nivel inferior alstivei soluţie) se execută automat la revenirile din apelurile subalgoritmului.

Pentru furnizarea soluţiilor, se va apela:Cheamă Backtracking (1) .

Problema 1. Problema damelor.Se dă o tablă de şah de n linii şi n coloane.Având n regine, se cer toate soluţiile de aranjare a reginelor pe tabla de şah, astfelîncât oricare două piese de acest tip să nu se atace.Analiza problemei:

Pornind de la observaţia că două dame se atacă în condiţiile în care ambele sesituează: fie pe aceiaşi linie, fie pe aceiaşi coloană, fie pe o diagonală a tablei de

151

Page 153: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 153/166

Algoritmi şi structuri de date

şah, putem deduce o variantă simplificată de reprezentare a unei soluţii prinîmpiedicarea oricăror dame de a fi situate pe aceiaşi coloană. Considerăm astfel cădamak este blocată să ocupe coloanak a tablei de şah. Astfel, oricare două damesunt poziţionate pe coloane distincte şi soluţia finală poate fi reprezentată printr-un

vector den elemente[ ] [ ]nStivak StivaStiva ],...,[,..,1

astfel încât:k – reprezintă indicele coloanei pe care se află damak Stiva[k] – elementul din stivă este indicele liniei ocupate de damak Practic, poziţia în stivă:k - corespunde atât indicelui de coloană cât şi

identificatorului damei, iar valoare de pe nivelulk din stivă coincide cu numărulliniei ocupate de damak .

1. Spaţiul soluţiilor posibile este produsul cartezian: A A A ××× ... ,unde A={1,2,…,n}.

2. Soluţia este reprezentată printr-un vector ( stivă ).3. Condiţiile ca o soluţie parţială [ ] ][,..,1 k StivaStiva să fievalidăse

reduc la a verifica dacă ak -a damă nu atacă oricare din damele poziţionate pe primelek-1coloane.

4. O soluţie estefinală dacă s-a reuşit poziţionarea tuturor damelor,respectiv, dimensiunea vectorului construit esten (s-a completatniveluln al stivei)

5. Dacă pe tabla de şah sunt dispusek-1dame astfel încât acestea nu seatacă (soluţie parţială validă), se poate trece la poziţionarea celei de-ak -a piesă.

Pe baza consideraţiilor 1-5problema 1se poate rezolva printr-un algoritmBacktracking. Algoritmul general descris anterior nu se modifică, în schimb vor fidetaliate funcţiile Valid şi Final:

Funcţie Valid (k)este//verifică dacă a k-a damă atacă damele 1,2,…,k-1Valid=Adevărat Pentru i de la 1 lak-1

Dacă ( [ ] [ ]iStivak Stiva=

) SAU ( (k-i)=( [ ] [ ]iStivak Stiva−

) )atunci / damele k şi i sunt situate pe aceiaşi linie sau pe aceiaşi diagonală

Valid=Fals SfDacăSfPentru

SfFuncţie

Funcţie Final (k ) este:Dacă k=natunci// am ajuns la nivelul n al stivei – s-au poziţionat toate cele n regine

Final=Adevărat Altfel

Final=Fals

152

Page 154: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 154/166

Algoritmi şi structuri de date

SfDacăSfFuncţie

Rezolvare1: Programul C pentru rezolvarea problemei damelor (variantanerecursivă)

#include <stdio.h>#include <math.h>

int stiva[100]; //solutia se construieste in stivaint nrsolutii;int n;

int valid(int k){int i;int cod=1;for(i=1;i<=k-1;i++)

if ((stiva[k]==stiva[i]) ||(abs(k-i)==abs(stiva[k]-stiva[i]) ) )cod=0;

return cod;}

int final(int k){if (k==n)

return 1;else

return 0;}

void tipareste(){int i;printf("\n");for(i=1;i<=n;i++)

printf("%d ",stiva[i]);

}

void main(){nrsolutii=0;int i;int gasit;printf("dati n:"); scanf("%d",&n);int k=1; //incepem de la primul nivel;while(k>=1)

{gasit=0;for(i=stiva[k]+1;(i<=n) ;i++)

{stiva[k]=i;

153

Page 155: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 155/166

Page 156: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 156/166

Algoritmi şi structuri de date

void dame(int k){for(int i=1;i<=n;i++)

{

stiva[k]=i;if (valid(k)==1)if (final(k)==1)

tipareste();else

dame(k+1);}

}

void main(){printf("\n dati n:");scanf("%d",&n);dame(1);}

Problema 2.Se dă un labirint reprezentat sub forma de matrice cum linii sincoloane, ale cărei elemente sunt valori 1 sau 0. Fiecare element al matriceireprezintă o camera a labirintului (1 pentru zid si 0 pentru drum liber). Intr-una dincamere, de coordonate Xstart si Zstart se afla o persoană. Determinaţi toatedrumurile prin care persoana va putea ieşi din labirint,dacă aceasta va putea efectua

doar mişcări spre Nord, Sud, Est şi Vest.Analiza problemei:

FieL – matricea de reprezentare a labirintului:( ) ( ) ( )( ) ( )

( ) ( ) ( )

=

nm,am,2am,1a

2,2a2,1a

n,1a2,1a1,1a

L , ( ) { }0,1 ji,a ∈

O soluţie finală a problemei poate fi reprezentată printr-un şir al mişcărilor efectuate în labirint, însă configuraţia stivei în care sunt salvate camerele traversateeste uşor modificată faţă de problema damelor. Astfel, fiecare poziţie nouă pe careo încearcă persoana în labirint este identificată prin două elemente: linia şi coloanamatricei prin care este reprezentat labirintul. Această observaţie ne este utilă înmodul de construire a stivei: fiecare nivel al stivei necesită memorarea a douăelemente ( spre deosebire de rezolvarea problemei 1): linia şi coloana poziţiei înmatrice.

Acest gen de probleme pentru care fiecare nivel al stivei reţine mai multeelemente se rezolvă cu unalgoritm Backtracking generalizat . Principul aplicat esteacelaşi ca şi la Backtracking-ul simplu: soluţia/soluţiile se construiesc treptat.Soluţiile finale ale problemei labirintului sunt vectori de perechi (i,j) cusemnificaţia poziţiei camerelor prin care a trecut persoana pentru a ieşi din labirint.Lungimile acestor vectori soluţie sunt diferite. Anumite drumuri parcurse pot fi mai

155

Page 157: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 157/166

Algoritmi şi structuri de date

scurte decât altele. Condiţia ca un vector de perechi (i,j) să fie soluţie finală a problemei este adevărată dacă ultima cameră (poziţie) parcursă se află la marginealabirintului: pe prima sau ultima coloană, sau, pe prima sau ultima linie a matriceide reprezentare.

Condiţiile de validitate se deduc din specificaţiile problemei. Drumul persoanei poate continua într-o nouă poziţie (i,j) dacă valoarea elementului de pe liniai şicoloana j din matriceaL este 0 (drum liber). Mai mult, pentru a evita parcurgereaaceloraşi camere de mai multe ori, se impune restricţia ca poziţiile prin care trece persoana să fie distincte. Astfel, persoana poate trece într-o cameră vecină dacă: nueste zid (cameră liberă) şi nu a mai fost traversată.

De asemenea, tot specificaţiile problemei ne indică faptul că mutarea într-onouă cameră se va face doar prin 4 mişcări posibile în poziţiile vecine: stânga,dreapta, sus şi jos

În continuare este descris algoritmulbacktracking de rezolvare a problemeilabirintului (varianta recursivă), punând în evidenţă condiţiile de validitate şifinalitate prin subalgoritmi corespunzători:

Funcţie Valid (k) // k-nivelul stiveiFie (i,j) –poziţia memorată înStiva[k]

Dacă(a(i,j)=0)atunci //cameră liberă Valid=Adevărat

Pentru l de la 1 lak-1Dacă ][),( l Stiva ji = atunci //camera a mai fost traversată în drumul memorat în stivă

Valid=FalsSfDacă

SfPentruAltfel //camera ocupată - zid

Valid=FalsSfDacă

SfFuncţie

Funcţie Final (k)Fie (i,j) –poziţia memorată înStiva[k]Dacăi=1 sau j=1 sau i=m sau j=natunci Final = Adevarat

Altfel Final=Fals

SfDacă

SfFuncţieSubalgoritm Labirint(k) este:Pentru fiecare vecin posibil (i,j) al camerei salvate înStiva[k-1]

Stiva[k]=(i,j) //operaţia push

156

Page 158: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 158/166

Algoritmi şi structuri de date

Dacă Valid (k)= Adevărat atunciDacă Final (k)= Adevărat atunci

Tipăreşte “Soluţie:”Stiva [ ] [ ]k StivaStiva ,..,1 Altfel

Cheamă Labirint(k+1)SfDacăSfDacă

SfPentruSfSubalgoritm

Rezolvarea problemei labirintului se face prin iniţializarea stivei cu poziţia destart: [ ] ( )Ystart Xstart Stiva ,0 = şi apelul:CheamăLabirint(1).

Problemă rezolvată PERMUTĂRI:Programul următor geneează permutările den prin metoda Backtracking - varianta recursivă.

#include <stdio.h>int n, stiva[200];void TiparesteSolutia() {

printf("\n");for (int i = 1; i <= n; i++)

printf("%d",stiva[i]);}

int valid(int k) {

for (int i = 1; i < k; i++)if(stiva[i] == stiva[k])

return 0;return 1;

}void permutari(int k) {

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

stiva[k] = i;if (valid(k))

if (k == n)TiparesteSolutia();elsepermutari(k+1);

}}

void main() {printf("dati n");scanf("%d",&n);permutari(1);

}

157

Page 159: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 159/166

Algoritmi şi structuri de date

XVI. METODE DE ELABORARE A ALGORITMILOR. PROGRAMARE DINAMICA.

Metoda Programării dinamice se poate considera ca o îmbunătăţire a tehnicii

Greedy. În cazul metodei Greedy, alegerea unui element se face pe baza unuicriteriu de admisibilitate, însă la Programarea dinamică, acest criteriu este cel aloptimalităţii; folosind-se de un criteriu mai puternic, rezultatul final oferit demetoda programării dinamice este întotdeauna optimul global.

Ca şi metoda Divide et impera, programarea dinamică presupune împărţirea problemei în subprobleme, rezolvarea şi combinarea soluţiilor acestora pentru aobţine rezultatul final. În situaţia în care subproblemele obţinute prindescompunere conţin subprobleme comune, este preferabilă aplicarea metodeiProgramării dinamice.

O particularitate a metodei constă în construirea si utilizarea unor tabele cuinformaţii. Tabelele sunt construite prin completarea unui element folosindelemente completate anterior. Denumirea metodei provine din maniera decompletaredinamică a tabelei de informaţii intermediare.

Metoda programării dinamice se caracterizează prin principiile fundamentale:- sunt evitate calculele repetate ale aceluiaşi subcaz, rezultatele intermediare

obţinute fiind memorate- soluţia este construită în manieră bottom-up (de jos în sus): pornind de la

soluţiile celor mai mici subprobleme, prin combinarea acestora se vaajunge treptat la soluţia globală

- problema abordată respectă principiul optimalităţii Programarea dinamică este o metodă de rezolvare a problemelor de optimizare

pentru care soluţia este rezultatul unui şir de decizii optime. Problema deoptimizare rezolvabilă prin metoda programării dinamice este formulată astfel:

Fie un sistem care se poate afla într-una din stările:S0, S1, S2 , …, Sn-1, Sn

şi fie şirul de deciziiD1, D2 , …, Dn-1, Dn

prin care sistemul este trecut prin stările date:n

nD

1n22D

11D

0SS...SSS → →→ → → −

Problema verifică unul dintre principiile optimalităţii:Varianta 1: Dacă şirul de deciziiD1, D2 , …, Dn-1, Dn duce sistemul din starea

iniţialăS0 în starea finalăSn în mod optim, atunci:{ }nk ,...,2,1∈∀ , secvenţa de deciziiDk , …, Dn-1, Dn duce sistemul din starea

Sk-1 în starea finalăSn în mod optim.

Varianta 2: Dacă şirul de deciziiD1, D2 , …, Dn-1, Dn duce sistemul din stareainiţialăS0 în starea finalăSn în mod optim, atunci:

158

Page 160: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 160/166

Algoritmi şi structuri de date

{ }nk ,...,2,1∈∀ , secvenţa de deciziiD1 , …, Dk-1, Dk duce sistemul din stareainiţialăS0 în stareaSk în mod optim.

În funcţie de varianta principiului optimalităţii identificată din analiza problemei, metoda de abordare a poate fi:

Metoda înainte– aplicată în cazul verificării principiului optimalităţii înforma 1.Metoda înapoi– aplicată în cazul verificării principiului optimalităţii înforma 2.

Esenţa celor două variante (înainte sau înapoi) este aceiaşi şi constă înidentificarea şi rezolvarea relaţiilor de recurenţă referitoare la criteriul de optimizatsau la valoarea ce se calculează.

Metoda înainteoperează în următoarele 4 faze:1. prin relaţiile de recurenţă se vor calcula optimele corespunzătoare stărilor

îndepărtate de starea finală în funcţie de optimele corespunzătoare stărilor apropiate de starea finală (practic în această fază se completează tabela deinformaţii intermediare)

2. se determină deciziile care leagă optimele determinate în faza anterioară3. se află optimul total4. se determină soluţia problemei reprezentată de un şir de decizii constituit

prin compunerea deciziilor de la etapa 2, în mod directe, de la începutspre sfârşit (înainte)

Metoda înapoieste duală metodei descrise anterior şi operează în următoarele 4faze:

1. prin relaţiile de recurenţă se vor calcula optimele corespunzătoare stărilor apropiate de starea finală în funcţie de optimele corespunzătoare stărilor depărtate de starea finală

2. se determină deciziile care leagă optimele determinate în faza anterioară3. se află optimul total4. se determină soluţia problemei reprezentată de un şir de decizii constituit

prin compunerea deciziilor de la etapa 2, în mod invers, de la sfârşit spreînceput (înapoi)

Deşi pare o metodă generală de rezolvare a problemelor de optim,aplicabilitatea programării dinamice este restrânsă doar la acele probleme pentrucare se poate demonstra principiul optimalităţii.

Problema 1 Subşir crescător de lungime maximă (metoda înainte )Se dă { }n X X X A ,...,, 21= o mulţime (şir) neordonată de elemente.Se cere determinarea lui B, A B ⊆ , şir ordonat crescător, de lungime maximă. Exemplu: în şirul 7 1 4 2 5 3, cel mai lung subşir crescător este 1,2,3

159

Page 161: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 161/166

Algoritmi şi structuri de date

Rezolvarea naivă a acestei probleme ar aceea prin care se vor determina toatesubşirurile crescătoare urmând ca ulterior să se extragă acela care are lungimemaximă. Rezolvarea aceasta este corectă, însă neeficientă prin necesitatea de aconstrui şi reţine toate subşirurile lui şirului dat.

O soluţie ingenioasă are fi să se calculeze şi să se reţină într-otabelă doar lungimile tuturor subşirurilor crescătoare, fără a le genera şi pe acestea.

În exemplul anterior, subşirurile crescătoare şi lungimile acestora sunt:

Subşirul

Lungimea

71 2 34 52 353

132211

Se poate observa că dacă subşirul 3 are lungime 1, subşirul care îl conţine arelungimea mai mare cu 1, respectiv 2 (1+1) şi subşirul maximal1 2 3 are lungime 3(2+1).

Astfel: Dacă subşirul1 2 3 este subşirul optimal crescător de lungime maximă(3), care începe cu1, atunci:

2 3 este subşirul optimal crescător de lungime maximă (2) care începe cu2 şi

3 este subşirul optimal crescător de lungime maximă (1) care începe cu3Generalizând, dacă n21 i,...,i,i este subşirul optimal crescător de lungimen

care începe cu 1i : atunci:- n32 i,...,i,i este subşirul optimal optimal de lungimen-1 care începe cu

i2

- n3 i,...,,i este optimal de lungimen-2 care începe cu i3

- …..- n1k k i,...,i,i + este subşirul optimal de lungime maximă care începe cu

ik , 1>∀ k Prin reformularea observaţiilor anterioare se identifică principiul optimalităţii în

varianta 1, fapt pentru care se va aplica metoda înainte:

Etapa_1&2: se vor calcula pe baza relaţiilor de recurenţă, pentru fiecareelement al şirului iniţial lungimea celui mai mare subşir crescător care se poateforma începând de la el.

Notăm L(k) lungimea celui mai mare subşir crescător care se poate forma

începând elementul de pe poziţiak din şirul dat. Relaţia de recurenţă esteurmătoarea:

L(k):={1+maxL(i) , astfel încât Xi >=Xk , i={1, 2, …, n}} şi k ∈{1, 2, …, n} }

160

Page 162: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 162/166

Algoritmi şi structuri de date

Algoritm Determinare_Lungimi este:L(n)=1

Pentru k=n-1 la 1 cu pas -1L(k)=1Caută i>k astfel încât ni ≤ şi k i XX ≥

Dacăs-a găsit (i)atunciL(k)=L(i)+1

SfDacăSfPentru

SfAlgoritm

Etapa3: Se determină maximul din tabela lungimilor L. Fie acesta L(imax). Înacest caz:

- L(imax) – reprezintă lungimea subşirului crescător de lungime maximă (lungimea soluţiei)

- imax – reprezintă indicele din şirul iniţial de la care începe subşirul soluţie

Etapa4: Se determină soluţia problemei (subşirul crescător de lungimemaximă), prin construire, pornind de la elementul de pe poziţia imax până laelementul de pe poziţia n, reţinându-se doar elementele care verifică relaţia deordine.

Problema 2: Problema Robotului(metoda înapoi)

Se dă o tablă împărţită înm linii şin coloane:

=

mnmm

n

n

aaa

aaa

aaa

A

...............

...

...

21

22221

11211

Fiecare căsuţă a tablei conţine obiecte de valori diferite (numere naturale): N a ij ∈ .

Unrobot situat în căsuţa de start 11a va traversa tabla pentru a ajunge la căsuţafinală mna realizând doar mişcările posibile:

- la dreapta cu o căsuţă: ( )1(, +→

jiij aa )- în jos cu o căsuţă: ( jiij aa ),1( +

→ )şi colectează obiectele din căsuţele traversate.

Să se determine secvenţa de mişcări (drumul) a robotului astfel încât suma

valorilor colectate la ieşire să fie maximă. Exemplu:Pentru următorul caz:

161

Page 163: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 163/166

Algoritmi şi structuri de date

2 0 7 1

4 0 3 0

0 5 1 0

2 4 1 2

Soluţia imediată este parcurgerea căsuţelor: (1,1)-(2,1)-(2,2)-(3,2)-(4,2)-(4,3)-(4,4), robotul colectează obiecte de valoare totală: 18 reprezentând suma maximă asumelor colectate prin parcurgerea oricăror drumuri de la căsuţa iniţială la căsuţafinală.

Se observă că suma maximă cu care ajunge robotul în căsuţa finală poate fiobţinută fie prin mutarea anterioară de pe coloana din stânga (n-1), fie prin mutarea

anterioară din celula de pe linia (m-1). Astfel, dacă suma finală a valorilor estemaximă, atunci prin scăderea valorii comune conţinută înmna , înseamnă că şidrumurile parţiale efectuate până în celula nma ,1− sau 1, −mna sunt de sumămaximă parţială.

Generalizând:- Dacă în celula jia , robotul a ajuns cu transport maxim de la celula

iniţială 11a , efectuând ultima mutaredreapta (robotul ajunge în celula jia , din celula 1, − jia ) atunci în celula 1, − jia robotul a ajuns cu sumă

maximă posibilă de la 11a la 1, − jia .- Dacă în celula jia , robotul a ajuns cu transport maxim de la celulainiţială 11a , efectuând ultima mutare jos (robotul ajunge în celula jia , din celula jia ,1− ) atunci în celula jia ,1− robotul a ajuns cu sumămaximă posibilă de la 11a la jia ,1− .

Observaţie: Ultima formulare este chiar Principiul optimalităţiiexprimat învarianta 2:

Dacă secvenţa de celule parcurse de la celula :(1,1)la celula(m,n)este de transport maxim: 11a , …,, 1,11 −− k jk ia , k jk ia , , … , nma ,

Atunci nk <∀ , secvenţa de celule parcurse de la(1,1) la ( k i ,k j ) este de transport maxim:11a , …,, 1,11 −− k jk ia , k jk ia ,

Din observaţiile anterioare, se poate deduce o relaţie de recurenţă prin care potfi determinate sumele maxime cu care robotul poate ajunge în oricare celulă atablei A:

) ij ji jiij aS S S += −− 1,,1 ,max , { }mii ,...,1, ∈∀ şi { }n j j ,...,1, ∈∀

162

Page 164: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 164/166

Algoritmi şi structuri de date

Pe baza relaţiei de recurenţă se va construi o tabelă suplimentară care reţinevalorile sumelor maxime pe care le poate colecta robotul până în fiecare celulă atablei iniţiale:

=

mnmm

n

n

S S S

S S S

S S S

S

...............

...

...

21

22221

11211

Algoritm DeterminareSumeMaxime este:S(0,1):=0S(1,0):=0

Pentru i de la 1 la mPentru j de la 1 la nDacă S(i-1,j)> S(i,j-1)atunci

S(i,j):= S(i-1,j)+ ai,j

AltfelS(i,j):= S(i,j-1)+ ai,j

SfDacăSfPentru

SfPentruSfAlgoritm

Se constată că ultima valoare determinată, nmS , reprezintă chiar sumamaximă a drumului complet al robotului, iar soluţia problemei–vectorul format dincăsuţele (i,j) traversate cu transport maxim, poate fi determinată printr-o parcurgereainversă a matriceiS :

Algoritm RefacereDrum este:Vector(1)⇐ (m,n) // Reţine căsuţa finală(m,n) Fie i=m, j=n, k=2

Câttimp((i,j)≠(1,1))Dacă jiS ,1− > 1, − jiS atunciVector(k)⇐ (i-1,j) // Reţine căsuţa (i-1,j),i=i-1k=k+1

AltfelVector(k)⇐ (i,j-1)//Reţine căsuţa (i,j-1) j=j-1k=k+1

SfDacăSfCâttimp//Vectorul de căsuţe parcurs invers este soluţia problemei.

Pentru i de lak la 1 cu pas -1

163

Page 165: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 165/166

Algoritmi şi structuri de date

TipăreşteVector(i)SfPentru

SfAlgoritm

Observaţie: Tehnica descrisă pentru rezolvarea problemei robotului esteProgramarea dinamică, varianta metodeiînapoi.

Probleme:

1. Scrieţi un program de rezolvare a problemei robotului.2. Scrieţi programul de rezolvare a problemei 1:Subşir crescător de lungime

maximă .

3. Scrieţi un program care determină cel mai lung subşir comun al două şiruridate.

164

Page 166: Curs ASD Format B5

8/8/2019 Curs ASD Format B5

http://slidepdf.com/reader/full/curs-asd-format-b5 166/166

Algoritmi şi structuri de date

BIBLIOGRAFIE:

1. Liviu Negrescu, Limbajele C si C++ pentru incepatori Vol. I (p.1 si 2) -

Limbajul C , Editura Albastră, Cluj-Napoca, 2002.2. Brian Kernighan, Dennis Ritchie, The C Programming

Language , Second Edition, Prentice Hall, 1988.

3. Bazil Pârv, Alexandru Vancea, Fundamentele limbajelor de

programare , Editura Albastră, Cluj Napoca, 1996.

4. Knuth, Donald E., Arta programarii calculatoarelor: Algoritmi

fundamentali. vol.1 , Editura Teora, Bucureşti, 1999.5. Doina Logofătu, Algoritmi fundamentali în C++. Aplicaţii , Editura

Polirom, Iaşi, 2007.6. Frenţiu M, Pârv B., Elaborarea programelor. Metode şi tehnici

moderne , Editura PROMEDIA, Cluj-Napoca, 1994.7. Petrovici V., Goicea F., Programare în limbajul C , Editura Tehnică,