proiectarea algoritmilor

16
UNIVERSITATEA DIN PETROŞANI FACULTATEA DE INGINERIE MECANICĂ ŞI ELECTRICĂ CURS POSTUNIVERSITAR INFORMATICĂ REFERAT PROIECTAREA ALGORITMILOR Programare dinamică Student: Gheorghe (Istratie) Aurora

Upload: auroraistratie

Post on 16-Jan-2016

212 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: proiectarea algoritmilor

UNIVERSITATEA DIN PETROŞANIFACULTATEA DE INGINERIE MECANICĂ ŞI

ELECTRICĂCURS POSTUNIVERSITAR INFORMATICĂ

REFERAT

PROIECTAREA ALGORITMILOR

Programare dinamică

Student: Gheorghe (Istratie) AuroraAn universitar 2011-2012

An I CPUI

Page 2: proiectarea algoritmilor

PROGRAMARE DINAMICĂ

În multe cazuri algoritmul Divide-et-impera realizează calculul unui număr foarte mare de termeni (cum este cazul determinării celui de al n-lea termen din şirul lui Fibonacci). Aceasta deoarece, algoritmul divide-et-impera rezolvă o problemă prin împărţirea ei în probleme mai mici şi apoi rezolvarea acestora. Aceasta este o abordare de tip top-down (de sus în jos). Această metodă funcţionează foarte bine în cazul problemelor de tip mergesort, în care problemele mai mici nu sunt legate între ele, deoarece fiecare conţine un şir de elemente care trebuie sortate independent. Însă o problemă ca cea de calcul al n-lea termen din şirul lui Fibonacci, împărţirea se face în probleme mai mici legate între ele. De exemplu, pentru a calcula al cincilea termen din şirul lui Fibonacci trebuie să calculăm al patrulea şi al treilea termen din şir. Dar determinările celor doi termeni (al patrulea şi al treilea) sunt legate între ele prin aceea că amândouă au nevoie de al doilea termen al şirului. Deoarece algoritmul divide-et-impera realizează aceste două calcule în mod independent, se ajunge la a calcula de mai multe ori termenul al doilea. În problemele în care împărţirea se face în probleme mai mici legate între ele, algoritmul divide-et-impera ajunge să rezolve în mod repetat aceleaşi subprobleme, ceea ce conduce la un algoritm ineficient.

În continuare vom prezenta algoritmul divide-et-impera pentru determinarea celui de al n-lea termen al şirului lui Fibonacci, pentru a putea face o comparaţie între metodele divide-et-impera şi programarea dinamică. Şirul lui Fibonacci este definit în mod recursiv după cum urmează:

De exemplu, primii 5 termeni ai şirului lui Fibonacci ar fi:

Intrări: numărul întreg pozitiv n.Ieşiri: fib, al n-lea termen al şirului lui Fibonacci.

sirul_Fibonacci;function fib(n:int):int;begin

if n<=1 then return nelse return fib(n-1)+fib(n-2);

end;

BEGINvar n:int;read n;write fib(n);ENDProgramarea dinamică are o abordare complet diferită. Singura asemănare dintre

programarea dinamică şi metoda divide-et-impera este faptul că o problemă este împărţită în probleme mai mici. Însă, în cazul programării dinamice se rezolvă problemele mai mici, se

2

Page 3: proiectarea algoritmilor

stochează rezultatele şi, mai târziu, ori de câte ori este necesar un rezultat, acesta se preia şi nu se recalculează. Termenul de programare dinamică vine din teoria sistemelor şi aici prin programare se înţelege utilizarea unui tablou în care se construieşte soluţia.

Un exemplu de calcul a celui de al n-lea termen al şirului lui Fibonacci prin metoda programării dinamice este prezentat în continuare. Pentru calculul termenului al n-lea al şirului se construieşte un şir f cu primii n+1 termeni ai şirului indexaţi de la 0 la n.

Intrări: numărul întreg pozitiv n.Ieşiri: fib2, al n-lea termen al şirului lui Fibonacci.

sirul_Fibonacci;function fib2(n:int):int;begin

var i,f(0..n):int;f(0):=0;if n>0 then begin

f(1):=1;for i:=2 to n

f(i):=f(i-1)+f(i-2);end;return f(n)

end;

BEGINvar n:int;read n;write fib2(n);END

Într-un algoritm realizat prin programare dinamică, construim într-o matrice (sau succesiune de matrici) o soluţie de jos în sus. Programarea dinamică realizează aşadar o abordare bottom-up. Uneori, după ce realizăm algoritmul utilizând o matrice (sau secvenţă de matrici) îl putem optimiza deoarece mare parte din spaţiul de memorie alocat iniţial nu este necesar.

Paşii în dezvoltarea unui algoritm prin programare dinamică sunt următorii:1. Stabilirea unei proprietăţi recursive care dă soluţia pentru problemă.2. Rezolvarea problemei prin metoda bottom-up, rezolvând mai întâi

subproblemele mai mici.

1. Algoritmul lui Floyd pentru determinarea celui mai scurt drumO problemă foarte des întâlnită de cei care călătoresc mult cu avionul este

determinarea celui mai scurt traseu pentru a ajunge dintr-un oraş în altul atunci când nu există un zbor direct. Vom prezenta în continuare un algoritm care rezolvă această problemă precum şi altele similare.

Pentru început vom aminti câteva noţiuni din teoria grafurilor. În fig.1 se prezintă un graf orientat şi marcat.

3

Page 4: proiectarea algoritmilor

Fig.1. Un graf orientat şi marcat

În reprezentarea grafică a unui graf se folosesc cercuri pentru noduri şi linii de la un cerc la altul pentru arcuri. Dacă fiecărui arc îi este asociată o direcţie, graful este denumit un graf orientat sau digraf. Când se reprezintă grafic un graf orientat, se vor folosi pentru arcuri săgeţi care arată direcţia. Într-un digraf pot exista două arcuri între oricare două noduri, câte unul pentru fiecare direcţie. În exemplul din fig.4.1 există un arc de la v1 la v2 şi alt arc de la v2 la v1. Dacă arcurilor le sunt asociate valori, aceste valori se numesc marcaje şi graful este numit marcat. Vom presupune în continuare că aceste marcaje sunt numere pozitive. Deşi aceste valori se numesc în general marcaje, în multe aplicaţii acestea reprezintă distanţe. Aşadar, vom vorbi de o cale de la un nod la altul. Într-un graf orientat, o cale este o secvenţă de noduri astfel încţt să existe un arc de la fiecare nod la succesorul său. De exemplu, în fig.4.1, secvenţa [v1, v4, v3] este o cale deoarece există un arc de la v1 la v4 şi un arc de la v4 la v3. Secvenţa [v3, v4, v1] nu este o cale, deoarece nu există arc de la v4 la v1. O cale de un nod la el însuşi se numeşte o buclă. Calea [v1, v4, v5, v1] din fig.4.1 este o buclă. Dacă un graf conţine o buclă acesta este ciclic, altfel este aciclic. O cale este simplă dacă nu trece de două ori prin acelaşi nod. Calea [v1, v2, v3] din fig.4.1 este simplă, dar calea [v1, v4, v5, v1, v2] nu este simplă. Se observă că o cale simplă nu conţine niciodată o subcale care să fie o buclă. Lungimea unei căi dintr-un graf marcat este suma marcajelor din cale, iar într-un graf nemarcat este numărul de arcuri din cale.

O problemă care are multe aplicaţii este găsirea celor mai scurte căi de la fiecare nod la toate celelalte. Evident, cea mai scurtă cale trebuie să fie o cale simplă. În fig.4.1 există trei căi simple de la v1 la v3, şi anume: [v1, v2, v3], [v1, v4, v3] şi [v1, v2, v4, v3]. Deoarece:

lungime[v1, v2, v3]=1+3=4lungime[v1, v4, v3]=1+2=3lungime[v1, v2, v4, v3]=1+2+2=5

[v1, v4, v3] este cea mai scurtă cale de la v1 la v3. Aşa cum am mai spus, o aplicaţie uzuală a celor mai scurte căi este găsirea celor mai scurte drumuri între două oraşe.

Problema celor mai scurte căi este o problemă de optimizare. Într-o problemă de optimizare pot exista mai multe soluţii candidat. Fiecare soluţie candidat are asociată o valoare şi o soluţie a problemei este orice soluţie candidat care are o valoare optimă. În funcţie de problemă, valoarea optimă este fie cea minimă fie cea maximă. În cazul problemi celor mai scurte căi, o soluţie candidat este o cale de la un nod la altul, valoarea este lungimea căii şi valoarea optimă este minimul acestor lungimi.

Deoarece pot exista mai multe căi de la un nod la altul care să fie cele mai scurte, problema este să se găsească oricare dintre cele mai scurte căi. Un algoritm evident pentru această problemă ar fi să se determine, pentru fiecare nod, lungimile tuturor căilor de la acel nod la toate celelalte şi să se calculeze apoi minimul acestor lungimi. Dar acest algoritm este foarte mare consumator de timp. Daca ar exista câte un arc de la fiecare nod la toate celelalte, am obţine un număr foarte mare de căi posibile. Această metodă de soluţionare nu este acceptabilă. Trebuie să găsim un algoritm mai eficient.

4

Page 5: proiectarea algoritmilor

Folosind programarea dinamică, vom crea un algoritm pentru problema celor mai scurte drumuri. Mai întâi dezvoltăm un algoritm care determină numai lungimile celor mai scurte drumuri. După aceasta îl modificăm pentru a produce şi cele mai scurte căi. Vom reprezenta un graf marcat având n noduri printr-o matrice W după cum urmează:

Deoarece se spune că nodul vi este adiacent nodului vj dacă există un arc de la vi la vj, această matrice se numeşte matricea adiacenţelor. Graful din fig.4.1 este reprezentat prin matricea adiacenţelor după cum urmează:

Vom defini acum o matrice D, de forma de mai jos, care conţine lungimile celor mai scurte căi din graf.

De exemplu, D(3,5)=7 deoarece 7 este lungimea unei celei mai scurte căi de la v3 la v5. Dacă putem găsi o modalitate de calcul a valorilor din D pe baza celor din W, vom avea un algoritm pentru probleme celor mai scurte drumuri. Vom realiza aceasta prin calculul unei serii de n+1 matrici D(k), unde 0<k<n şi unde:

Înainte de a demonstra corectitudinea acestui algoritm, vom determina câteva valori prin D(k)(i,j) pentru graful din fig.4.1.

Pentru orice graf acestea sunt egale deoarece o cea mai scurtă cale care porneşte din v2 nu poate trece tot prin v2.Pentru acest graf acestea sunt egale deoarece incluzându-l pe v3 nu se produce nici o cale nouă de la v2 la v5.

Ultima valoare care se calculează, D(5)(2,5) este lungimea celui mai scurt drum de la v2

la v5 care poate terce prin oricare alte noduri. Adică aceasta este cea mai scurtă cale.

Deoarece D(n)(i,j) este lungimea celei mai scurte căi de la v i la vj care poate trece prin oricare alte noduri, aceasta va fi lungimea celei mai scurte căi de la v i la vj. Deoarece D(0)(i,j) este lungimea unei cele mai scurte căi de la v i la vj care nu poate trece prin nici un alt nod, aceasta este de fapt lungimea arcului de la vi la vj. Prin aceste două afirmaţii am stabilit că:

şi .

5

Page 6: proiectarea algoritmilor

Aşadar, pentru a determina pe D din W trebuie doar să obţinem D(n) din D(0). Paşii necesari în programarea dinamică pentru aceasta sunt:

1. Stabilirea unei prorietăţi (proces) recursive cu care putem calcula D(k) din D(k-1).2. Rezolvarea unei subprobleme în stilul bottom-up (de jos în sus) prin repetarea

procesului (stabilit în pasul 1) pentru k=1 .. n. Aceasta va conduce la secvenţa:

Vom realiza pasul 1 considerând două cazuri:Cazul 1. Cel puţin o cale dintre cele mai scurte de la vi la vj, care foloseşte ca noduri

intermediare numai cele din mulţimea , nu foloseşte nodul vk. Atunci:

Ca exemplu pentru acest caz, în fig.4.1 avem:,

deoarece când includem nodul v5, cea mai scurtă cale de la v1 la v3 este tot (v1,v4,v3).Cazul 2. Toate căile care sunt cele mai scurte de la v i la vj, care folosesc ca noduri

intermediare numai cele din mulţimea , utilizează nodul vk. În acest caz toate cele mai scurte căi sunt ca în fig.2.

Fig.2. Cea mai scurtă cale foloseşte nodul vk

Deoarece vk nu poate fi nod intermediar în subcalea de la vi la vk, acea subcale utilizează numai nodurile din ca noduri intermediare. Aceasta înseamnă că

lungimea subcăii trebuie să fie egală cu din următoarele motive: Mai întâi,

lungimea subcăii nu poate fi mai mică deoarece este lungimea celei mai scurte căi de la v1 la vk care foloseşte ca noduri intermediare numai nodurile din mulţimea

. Apoi, lungimea subcăii nu poate fi mai mare deoarece dacă ar fi, am putea-o înlocui în fig.2 printr-o altă cale mai scurtă, ceea ce ar contrazice faptul că întreaga cale din fig.2 este o cea mai scurtă cale. Similar, lungimea subcăii de la vk la vj din fig.2 trebuie să fie egală cu . Aşadar, în cel de al doilea caz:

Un exemplu pentru cel de al doilea caz în fig.4.1 este:

Deoarece singurele cazuri posibile sunt cele două descrise mai sus, înseamnă că valoarea lui este minimul valorilor din cele două cazuri. Aceasta înseamnă că putem determina pe D(k) din D(k-1) după cum urmează:

6

Page 7: proiectarea algoritmilor

Am realizat astfel pasul 1 din algoritmul dezvoltat prin programare dinamică. Pentru pasul 2 folosim recursivitarea din pasul 1 pentru a crea secvenţa de matrici. În continuare vom prezenta cum se calculează fiecare din aceste matrici din precedentele pentru cazul grafului din fig.1.

După ce se calculează întreaga matrice D(1), se poate calcula şi matricea D(2). De exemplu, pentru matricea D(2) un element este:

După calcularea tuturor elementelor din D(2) vom continua pe acelaşi principiu până la D(5). Această matrice este matricea D, care conţine lungimile celor mai scurte căi.

În continuare vom prezenta algoritmul lui Floyd, care datează din anul 1962. Problema: Să se calculeze cele mai scurte căi între oricare două noduri dintr-un graf

marcat. Marcajele sunt numere pozitive.Intrări: Un graf orientat şi marcat şi n=numărul de noduri din graf. Graful este

reprezentat prin matricea adiacenţelor W, pătratică bidimensională de dimensiune n.Ieşiri: O matrice pătratică bidimensională D, de dimensiunea n, în care D(i,j)

reprezintă cea mai scurtă cale de la nodul i la nodul j.

Floyd;procedure Floyd(n:int, W(n,n):const, D(n,n):real);beginvar i,j,k:int;D=W;for k=1 to n

for i=1 to nfor j=1 to n

D(i,j):=min(D(i,j),D(i,k)+D(k,j));end;

BEGINvar n:int, W(n,n),D(n,n):real;read n,W(n,n);Floyd(n,W,D);write D(n,n);END

Putem realiza calculele utilizând numai o matrice D deoarece valorile din linia k şi cele din coloana k nu se modifică în timpul celei de a k-a iteraţie din buclă. Adică, în iteraţia k din algoritm se atribuie valorile:

care este egală cu D(i,k) şi:

care este egală cu D(k,j). În timpul celei de a k-a iteraţie, D(i,j) se calculează numai din propria sa valoare şi din valorile din linia k şi din coloana k. Deoarece acestea şi-au păstrat

7

Page 8: proiectarea algoritmilor

aceleaşi valori ca în iteraţia k-1, acestea pot fi folosite fără griji. Aşa cum am mai spus, după dezvoltarea unui algoritm prin programarea dinamică, este posibil să se revizuiască acesta pentru a-l face mai eficient.

În continuare vom face o modificare a algoritmului, care va produce şi drumurile (succesiunea de noduri) cele mai scurte.

Problema şi intrările sunt aceleaşi. Apar în plus ieşiri, şi anume, o matrice P, pătratică de dimensiune n, în care:

Floyd_2;procedure Floyd2(n:int, W(n,n):const, D(n,n):real, P(n,n):int);beginvar i,j,k:int;for i=1 to n

for j=1 to nP(i,j):=0;

D=W;for k=1 to n

for i=1 to nfor j=1 to n

if D(i,k)+D(k,j)<D(i,j) thenbegin

P(i,j):=k;D(i,j):=D(i,k)+D(k,j);

endend;

BEGINvar n:int, P(n,n):int, W(n,n),D(n,n):real;read n,W(n,n);Floyd(n,W,D,P);write D(n,n), P(n,n);END

Pentru graful din fig.1 matricea P rezultată prin algoritmul de mai sus este:

Pentru a găsi cel mai scurt drum de la nodul vq la nodul vr folosind matricea P, utilizăm algoritmul următor:

Problema: să se afişeze cel mai scurt drum de la un nod la alt nod dintr-un graf marcat.Intrări: matricea P produsă prin algoritmul Floyd2 şi cei doi indici q şi r ai nodurilor

din graf între care se va afişa cel mai scurt drum.

8

Page 9: proiectarea algoritmilor

Ieşiri: nodurile intermediare de pe cel mai scurt drum între vq şi vr.

procedure cale(q,r:int);beginif P(q,r)!=0 thenbegin

cale(q,P(q,r));write ”v”&P(q,r);cale(P(q,r),r);

end;end

Apelarea procedurii de mai sus se va face prin:cale(q,r);

Având exemplul din fig.1, care are matricea P calculată mai sus, pentru valorile q=5 şi r=3 ieşirea va fi:

v1 v4Acestea sunt nodurile intermediare de pe cel mai scurt drum de la v5 la v3.

4.2. Programarea dinamică şi problemele de optimAşa cum s-a prezentat în paragraful anterior, algoritmul lui Floyd determină nu numai

lungimile celor mai scurte căi ci le şi construieşte. Constuirea soluţiei optime este al treilea pas în dezvoltarea unui algoritm prin metoda programării dimanice. Aceasta înseamnă că paşii dezvoltării unui asemenea algoritm sunt:

1. Stabilirea unei recursivităţi care dă soluţia optimă la o problemă.2. Calculul valorii unei soluţii optime în stilul de jos în sus.3. Construirea unei soluţii optime în stilul de jos în sus.

Paşii 2 şi 3 se realizează de obicei împreună în cadrul algoritmului. Algoritmii care nu sunt pentru probleme de optim nu conţin pasul 3.

Deşi ar putea părea că orice problemă de optimizare poate fi rezolvată utilizând programarea dinamică, nu este aşa. Trebuie ca în problemă să se aplice principiul de optim. Acest principiu se enunţă prin:

DefiniţieSe spune că într-o problemă se aplică principiul de optim dacă o soluţie optimă la un

caz al unei probleme este soluţie optimă pentru toate subproblemele.Acest enunţ al principiului de optim poate fi înţeles mai uşor dacă analizăm un

exemplu. În cazul probelemei celor mai scurte căi am arătat că dacă vk este un vârf dintr-o cale optimă de la vk la vj, atunci subcăile de la ui la uk şi de la vk la vj trebuie să fie şi ele optime. Aşadar, soluţia optimă a unei probleme conţine soluţii optime pentru toate subproblemele şi se aplică principiul de optim.

Dacă într-o anumită problemă se aplică principiul de optim, putem dezvolta o recursivitate care dă o soluţie optimă pentru un caz al problemei prin soluţii optime ale subproblemelor. Motivul cel mai important pentru care putem folosi programarea dinamică în construirea unei soluţii optime pentru un caz al problemei este că soluţiile optime la subprobleme pot fi printre soluţiile optime. De exemplu, în cazul problemei celui mai scurt drum, dacă subcăile sunt cele mai scurte, atunci calea obţinută prin combinarea acestora va fi optimă. Vom putea aşadar folosi recursivitatea pentru a construi soluţii optime la probleme tot mai complexe pe principiul de jos în sus. Fiecare soluţie determinată pe această cale va fi întotdeauna optimă.

9

Page 10: proiectarea algoritmilor

Deşi principiul optimului ar putea părea evident, în practică este necesar să demonstrăm că acest principiu se poate aplica, înainte de a presupune că prin programare dinamică vom obţine soluţia optimă. Următorul exemplu arată că acest principiu nu se aplică în toate problemele de optimizare.

Exemplu:Să considerăm problema celui mai lung drum care presupune găsirea celei mai lungi

căi simple de la orice vârf la toate celelalte ale unui graf. Restricţionăm problema la căi simple deoarece utilizând un ciclu putem crea o cale oricât de lungă, trecând repetat prin ciclul respectiv. În fig.4.3 calea simplă cea mai lungă de la v1 la v4 este [v1, v3, v2, v4]. Însă subcalea [v1, v3] nu este calea optimă (cea mai lungă) de la v1 la v3 deoarece:

lungime[v1, v3]=1 şi lungime[v1, v2, v3]=4.

Fig.3. Un graf orientat, marcat având un ciclu

Aşadar, principiul optimului nu se aplică în acest caz. Motivul este că nu pot fi combinate căile optime dintre v1 şi v3 respectiv v3 şi v4 pentru a obţine o cale optimă de la v1 la v4. Dacă le-am combina am obţine un ciclu şi nu o cale optimă.

În continuare vom prezenta probleme de optim rezolvate prin programare dinamică.

3. Arbori binari de căutare optimalăÎn acest paragraf vom realiza un algoritm de determinare a modului optim de

organizare a articolelor dintr-un arbore binar de căutare. Înainte de a defini ce înseamnă organizare optimă, vom prezenat pe scurt noţiunile legate de aceşti arbori. Pentru orice nod dintr-un arbore binar, subarborele a cărui rădăcină este fiul stâng al nodului respectiv se numeşte subarborele stâng al nodului. Subarborele stâng al rădăcinii arborelui este denumit subarborele stâng al arborelui. Subarborele drept este definit în mod analog.

Definiţie:Un arbore de căutare binară este un arbore binar de articole (denumite uzual chei),

care provin dintr-o mulţime ordonată, astfel încât:1. Fiecare nod conţine o cheie.2. Cheile din subarborele stâng al unui nod dat sunt mai mici sau egale cu cheia

din acel nod.3. Cheile din subarborele drept al unui nod dat sunt mai mari sau egale cu cheia

din acel nod.În fig.4 se prezintă doi arbori de căutare binară, fiecare cu aceleaşi chei. În arborele

din fig.4.a, dacă analizăm subarborele drept al nodului conţinând articolul „Radu” vedem că acesta conţine articolele „Toma”, „Ursu” şi „Willy” şi toate aceste articole sunt mai mari decât „Radu” atunci când sunt ordonate alfabetic. Deşi, în general, o cheie poate apare de mai multe ori într-un arbore de căutare binară, pentru simplificare vom presupune că toate cheile sunt distincte.

10

Page 11: proiectarea algoritmilor

Fig.4. Doi arbori de căutare binară

Adâncimea unui nod dintr-un arbore este numărul de arcuri din calea unică de la rădăcină la nod. Acesta se mai numeşte şi nivelul nodului în arbore. De obicei spunem că un nod are o adâncime şi că nodul este la un nivel. De exemplu, în arborele din fig.4.a, nodul cu cheia „Ursu” are o adâncime de 2. Am putea spune şi că acel nod este la nivelul 2. Rădăcina are o adâncime de 0 şi este la nivelul 0. Adâncimea unui arbore este maximul adâncimilor tuturor nodurilor acelui arbore. Arborele din fig.4.a are adâncimea 3, în timp ce cel din fig.4.b are adâncimea 2. Un arbore binar se spune că este echilibrat dacă adâncimile celor doi subarbori ai fiecărui nod nu diferă niciodată prin mai mult de 1. Arborele din fig.4.a nu este echilibrat deoarece subarborele stâng al rădăcinii are adâncimea 0 şi subarborele drept are adâncimea 2. Arborele din fig.4.b este echilibrat.

Un arbore binar de căutare conţine înregistrări care sunt preluate în funcţie de valorile cheilor. Obiectivul nostru este să organizăm cheile dintr-un arbore binar astfel încât timpul mediu necesar localizării unei chei să fie minimizat. Un arbore care este organizat în acest mod este denumit optimal. Nu este greu de observat că dacă toate cheile au aceeaşi probabilitate de a fi cheia de căutare, arborele din fig.4.b este optimal. Ne interesează, însă, cazul în care cheile nu au aceeaşi probabilitate. Un exemplu de asemenea caz ar fi căutarea în unul din arborii din fig.4 după un nume ales aleator. Deoarece „Radu” este un nume mai comun decât „Willy”, îi vom atribui o probabilitate mai mare lui „Radu”.

Vom analiza cazul în care se ştie că cheia de căutare este în arbore. Pentru a minimiza timpul mediu de căutare, trebuie să ştim complexitatea în timp a localizării unei chei. Aşadar, mai întâi, vom scrie şi analiza un algoritm care caută o cheie într-un arbore binar de căutare. Tipul de dată utilizat de acest algoritm este:

struct nodetype{

keytype key;nodetype* left;nodetype* right;

};typedef nodetype* node_pointer;

11

Page 12: proiectarea algoritmilor

Această declaraţie înseamnă că o variabilă node_pointer este un pointer la o înregistrare de tipul nodetype. Adică, valoarea sa este adresa de memorie unei asemenea înregistrări.

12