227

algoritmi_tehnici_dorel lucanu - carte

  • Upload
    minushp

  • View
    134

  • Download
    2

Embed Size (px)

Citation preview

Page 1: algoritmi_tehnici_dorel lucanu - carte

Capitolul 2

Despre algoritmi

2.1 Limbaj algoritmic

2.1.1 Introducere

Un algoritm este o secventa nita de pasi, aranjata ntr-o ordine logica specica care, atunci cand esteexecutata, produce o solutie corecta pentru o problema precizata. Algoritmii pot descrisi n orice limbaj,pornind de la limbajul natural pna la limbajul de asamblare al unui calculator specic. Un limbaj alcarui scop unic este cel de a descrie algoritmi se numeste limbaj algoritmic. Limbajele de programaresunt exemple de limbaje algoritmice.

In aceasta sectiune descriem limbajul algoritmic utilizat n aceasta carte. Limbajul nostru este tipizat,n sensul ca datele sunt organizate n tipuri de date. Un tip de date consta dintr-o multime de entitati detip data (valori), numita si domeniul tipului, si o multime de operatii peste aceste entitati. Convenimsa grupam tipurile de date n trei categorii:

tipuri de date elementare, n care valorile sunt entitati de informatie indivizibile;

tipuri de date structurate de nivel jos, n care valorile sunt structuri relativ simple obtinute prinasamblarea de valori elementare sau valori structurate iar operatiile sunt date la nivel de compo-nenta;

tipuri de date structurate de nivel nalt, n care valorile sunt structuri mai complexe iar operatiilesunt implementate de algoritmi proiectati de catre utilizatori.

Primele doua categorii sunt dependente de limbaj si de aceea descrierile lor sunt incluse n aceata sectiune.Tipurile de nivel nalt pot descrise ntr-o maniera independenta de limbaj si descrierile lor sunt inclusen capitolul 3. Un tip de date descris ntr-o maniera indepenedenta de reprezentarea valorilor si imple-mentarea operatiilor se numeste tip de date abstract.

Pasii unui algoritm si ordinea logica a acestora sunt descrise cu ajutorul instructiunilor. O secventade instructiuni care actioneaza asupra unor structuri de date precizate se numeste program. In sectiunea2.2 vom vedea care sunt conditiile pe care trebuie sa le ndeplineasca un program pentru a descrie unalgoritm.

2.1.2 Modelarea memoriei

Memoria este reprezentata ca o structura liniara de celule, ecare celula avand asociata o adresa siputand memora (stoca) o data de un anumit tip (g. 2.1). Accesul la memorie este realizat cu ajutorulvariabilelor. O variabila este caracterizata de:

un nume cu ajutorul careia variabila este referita,

o adresa care desemneaza o locatie de memorie si

un tip de date care descrie natura valorilor memorate n locatia de memorie asociata variabilei.

Daca n plus adaugam si valoarea memorata la un moment dat n locatie, atunci obtinem o instantaa variabilei. O variabila este reprezentata grac ca n g. 2.2a. Atunci cand tipul se subntelege din

3

Page 2: algoritmi_tehnici_dorel lucanu - carte

4 CAPITOLUL 2. DESPRE ALGORITMI

712

lungime integer

a

Figura 2.1: Memoria

b)

lungime lungime712integer 712

a)

Figura 2.2: Variabila

context, vom utiliza reprezentarea scurta sugerata n 2.2b. Convenim sa utilizam fontul type writer

pentru notarea variabilelor si fontul mathnormal pentru notarea valorilor memorate de variabile.

2.1.3 Tipuri de date elementare

Numere ntregi. Valorile sunt numere ntregi iar operatiile sunt cele uzuale: adunarea (+), nmultirea(), scaderea (), etc.

Numere reale. Deoarece prin data ntelegem entitate de informatie reprezentabila n memoria calcu-latorului, domeniul tipului numerelor reale este restrans la submultimea numerelor rationale. Operatiilesunt cele uzuale.

Valori booleene. Domeniul include numai doua valori: true si false. Peste aceste valori sint deniteoperatiile logice and, or si not cu semnicatiile cunoscute.

Pointeri. Domeniul unui tip pointer consta din adrese de variabile apartinand la alt tip. Presupunemexistenta valorii NULL care nu refera nici o variabila; cu ajutorul ei putem testa daca un pointer referasau nu o variabila. Nu consideram operatii peste aceste adrese. Cu ajutorul unei variabile pointer, numitape scurt si pointer, se realizeaza referirea indirecta a unei locatii de memorie. Un pointer este reprezentatgrac ca n g. 2.3a. Instanta variabilei pointer p are ca valoare adresa unei variabile de tip ntreg.Am notat integer* tipul pointer al carui domeniu este format din adrese de variabile de tip ntreg.Variabila referita de p este notata cu *p. In g. 2.3b si 2.3c sunt date reprezentarile grace simplicateale pointerilor.

Pointerii sunt utilizati la manipularea variabilelor dinamice. O variabila dinamica este o variabila careeste creata si poate distrusa n timpul executiei programului. Crearea unei variabile dinamice se face cuajutorul subprogramului new. De exemplu, apelul new(p) are ca efect crearea variabilei *p. Distrugerea(eliberarea spatiului de memorie) variabilei *p se face cu ajutorul apelului delete(p) al subprogramuluidelete.

2.1.4 Instructiuni

Atribuirea. Sintaxa:

hvariabilai hexpresiei

unde hvariabilai este numele unei variabile iar hexpresiei este o expresie corect formata de acelasi tip cuhvariabilai.Semantica: Se evalueaza hexpresiei si rezultatul obtinut se memoreaza n locatia de memorie desemnata dehvariabilai. Valorile tuturor celorlalte variabile raman neschimbate. Atribuirea este singura instructiunecu ajutorul careia se poate modica memoria. O reprezentare intuitiva a efectului instructiunii deatribuire este data n g. 2.4.

Page 3: algoritmi_tehnici_dorel lucanu - carte

2.1. LIMBAJ ALGORITMIC 5

p

a a’

a’

*p integer

*p integer

integer*p

integer*p

*p

a)

b) c)

Figura 2.3: Pointer

b) Dupa atribuirea "a <- a*b"

a 5 b -2

a -10 b -2

a) Inainte de atribuire

Figura 2.4: Atribuirea

if. Sintaxa:

if hexpresieithen hsecventa-instructiuni1ielse hsecventa-instructiuni2i

unde hexpresiei este o expresie care prin evaluare da rezultat boolean iar hsecventa-instructiuniii, i = 1; 2,sunt secvente de instructiuni scrise una sub alta si aliniate corespunzator. Partea else este facultativa.Daca partea else lipseste si hsecventa-instructiuni1i este formata dintr-o singura instructiune atunciinstructiunea if poate scrisa si pe un singur rand. De asemenea, o expresie n cascada de forma

if (...)

then ...

else if (...)

then ...

else if (...)

then ...

else ...

va scrisa sub urmatoarea forma liniara echivalenta:

if (...) then

...

else if (...) then

...

else if (...) then

Page 4: algoritmi_tehnici_dorel lucanu - carte

6 CAPITOLUL 2. DESPRE ALGORITMI

...

else ...

Semantica: Se evalueaza hexpresiei. Daca rezultatul evaluarii este true atunci se executa hsecventa-instructiuni1i dupa care executia instructiunii if se termina; daca rezultatul evaluarii este false atuncise executa hsecventa-instructiuni2i dupa care executia instructiunii if se termina.

while. Sintaxa:

while hexpresiei doh secventa-instructiunii

unde hexpresiei este o expresie care prin evaluare da rezultat boolean iar hsecventa-instructiunii este osecventa de instructiuni scrise una sub alta si aliniate corespunzator.

Semantica: 1. Se evalueaza hexpresiei.2. Daca rezultatul evaluarii este true atunci se executa hsecventa-instructiunii dupa care se reia procesulncepand cu pasul 1. Daca rezultatul evaluarii este false atunci executia instructiunii while se termina.

for. Sintaxa:

for hvariabilai hexpresie1i to hexpresie2i doh secventa-instructiunii

sau

for hvariabilai hexpresie1i downto hexpresie2i dohsecventa-instructiunii

unde hvariabilai este o variabila de tip ntreg, hexpresieii, i = 1; 2, sunt expresii care prin evaluaredau valori ntregi, hsecventa-instructiunii este o secventa de instructiuni scrise una sub alta si aliniatecorespunzator.

Semantica: Instructiunea

for i e1 to e2 do

S

simuleaza executia urmatorului program:

i e1temp e2while (i temp) do

S

i i+1

iar instructiunea

for i e1 downto e2 do

S

simuleaza executia urmatorului program:

i e1temp e2while (i temp) do

S

i i-1

Page 5: algoritmi_tehnici_dorel lucanu - carte

2.1. LIMBAJ ALGORITMIC 7

repeat. Sintaxa:

repeat

hsecventa-instructiuniiuntil hexpresiei

unde hexpresiei este o expresie care prin evaluare da rezultat boolean iar hsecventa-instructiunii este osecventa de instructiuni scrise una sub alta si aliniate corespunzator.Semantica: Instructiunea

repeat

S

until e

simuleaza executia urmatorului program:

S

while (not e) doS

Exceptii. Sintaxa:

throw hmesaji

unde hmesaji este un sir de caractere (un text).Semantica: Executia programului se opreste si este asat textul hmesaji. Cel mai adesea, throw esteutilizata mpreuna cu if:

if hexpresiei then throw hmesaji

Obtinerea rezultatului true n urma evaluarii expresiei are ca semnicatie aparitia unei exceptii, caz ncare executia programului se opreste. Un exemplu de exceptie este cel cand procedura new nu poate alocamemorie pentru variabilele dinamice:

new(p)

if (p = NULL) then throw 'memorie insuficienta'

2.1.5 Subprograme

Limbajul nostru algoritmic este unul modular, unde un modul este identicat de un subprogram. Existadoua tipuri de subprograme: proceduri si functii.

Proceduri. Interfata dintre o procedura si modulul care o apeleaza este realizata numai prin parametrisi variabilele globale. De aceea apelul unei proceduri apare numai ca o instructiune separata. Formagenerala a unei proceduri este:

procedure hnumei(hlista-parametrii)begin

hsecventa-instructiuniiend

Lista parametrilor este optionala. Consideram ca exemplu o procedura care interschimba valorile a douavariabile:

procedure swap(x, y)

begin

aux x

x y

y aux

end

Page 6: algoritmi_tehnici_dorel lucanu - carte

8 CAPITOLUL 2. DESPRE ALGORITMI

Permutarea circulara a valorilor a trei variabile a, b, c se face apeland de doua ori procedura swap:

swap(a, b)

swap(b, c)

Functii. In plus fata de proceduri, functiile ntorc valori calculate n interiorul acestora. De aceeaapelul unei functii poate participa la formarea de expresii. Forma generala a unei functii este:

function hnumei(hlista-parametrii)begin

hsecventa-instructiuniireturn hexpresiei

end

Lista parametrilor este optionala. Valoarea ntoarsa de functie este cea obtinuta prin evaluarea expresiei.Consideram ca exemplu o functie care calculeaza maximul dintre valorile a trei variabile:

function max3(x, y, z)

begin

temp x

if (y > temp) then temp y

if (z > temp) then temp z

return temp

end

Are sens sa scriem 2*max3(a, b, c) sau max3(a, b, c) < 5.

2.1.5.1 Comentarii

Comentariile sunt notate similar ca n limbajul C, utilizand combinatiile de caractere /* si */. Comen-tariile au rolul de a introduce explicatii suplimentare privind descrierea algoritmului:

function absDec(x)

begin

if (x > 0) /* testeaza daca x este pozitiv */

then x x-1 /* decrementeaza x*/

else x x+1 /* incrementeaza x*/

end

2.1.6 Tipuri de date structurate de nivel jos

2.1.6.1 Tablouri

Un tablou este un ansamblu omogen de variabile, numite componentele tabloului, n care toate variabilelecomponente apartin aceluiasi tip si sunt identicate cu ajutorul indicilor. Un tablou 1-dimensional (uni-dimensional) este un tablou n care componentele sunt identicate cu ajutorul unui singur indice. Deexemplu, daca numele variabilei tablou este a si multimea valorilor pentru indice este f0; 1; 2; : : : ; n 1g,atunci variabilele componente sunt a[0], a[1], a[2], ..., a[n-1]. Memoria alocata unui tablou1-dimensional este o secventa contigua de locatii, cate o locatie pentru ecare componenta. Ordineade memorare a componentelor este data de ordinea indicilor. Tablourile 1-dimensionale sunt reprezen-tate grac ca n g. 2.5. Operatiile asupra tablourilor se realizeaza prin intermediul componentelor.Prezentam ca exemplu initializarea tuturor componentelor cu 0:

for i 0 to n-1 do

a[i] 0

Un tablou 2-dimensional (bidimensional) este un tablou n care componentele sunt identicate cu aju-torul a doi indici. De exemplu, daca numele variabilei tablou este a si multimea valorilor pentru primulindice este f0; 1; : : : ;m 1g iar multimea valorilor pentru cel de-al doilea indice este f0; 1; : : : ; n

Page 7: algoritmi_tehnici_dorel lucanu - carte

2.1. LIMBAJ ALGORITMIC 9

tab1da

integer

integer

integer

integer

integer

a[0]

a[1]

a[2]

a[3]

a[4]

Figura 2.5: Tablou 1-dimensional

tab2da

integer

integer

integer

integer

a[0,0]

a[0,1]

a[1,1]

a[1,0]

Figura 2.6: Tablou 2-dimensional

1g atunci variabilele componente sunt a[0,0], a[0,1],..., a[0,m-1], ..., a[m-1,0], a[m-1,1],

..., a[m-1,n-1]. Ca si n cazul tablourilor 1-dimensionale, memoria alocata unui tablou 2-dimensionaleste o secventa contigua de locatii, cate o locatie pentru ecare componenta. Ordinea de memorare acomponentelor este data de ordinea lexicograca denita peste indici. Tablourile 2-dimensionale suntreprezentate grac ca n g. 2.6. Asa cum o matrice poate vazuta ca ind un vector de linii, tot asaun tablou 2-dimensional poate vazut ca ind un tablou 1-dimensional de tablouri 1-dimensionale. Dinacest motiv, componentele unui tablou 2-dimensional mai pot notate prin expresii de forma a[0][0],

a[0][1], etc (a se vedea si g. 2.7).

2.1.6.2 Structuri

O structura este un ansamblu eterogen de variabile, numite campuri, n care ecare camp are propriulsau nume si propriul sau tip. Numele complet al unui camp se obtine din numele structurii urmat decaracterul \." si numele campului. Memoria alocata unei structuri este o secventa contigua de locatii,cate o locatie pentru ecare camp. Ordinea de memorare a campurilor corespunde cu ordinea de descriere

tab2da

tab1da[0]

tab1da[1]

Figura 2.7: Tablou 2-dimensional vazut ca tablou de tablouri 1-dimensionale

Page 8: algoritmi_tehnici_dorel lucanu - carte

10 CAPITOLUL 2. DESPRE ALGORITMI

b)

punct

p.y

p.x

p

integer

integer

figura

f.vizibil

f

f.pozitie punct

boolean

a)

Figura 2.8: Structuri

pp->y

pp punct*

pp->x

(*pp).x

(*pp).y

Figura 2.9: Structuri si pointeri

a acestora n cadrul structurii. Ca exemplu, presupunem ca o gura f este descrisa de doua campuri:f.pozitie - punctul care precizeaza pozitia gurii, si f.vizibil - valoare booleana care precizeaza dacagura este desenata sau nu. La randul sau, punctul poate vazut ca o structura cu doua campuri - cateunul pentru ecare coordonata (consideram numai puncte n plan avand coordonate ntregi). Structurilesunt reprezentate grac ca n g. 2.8. Pentru identicarea campurilor unei structuri referite indirectprin intermediul unui pointer vom utiliza o notatie similara celei utilizate n limbajul C (a se vedea si g.2.9).

2.1.6.3 Liste liniare simplu nlantuite

O lista liniara simplu nlantuita este o nlantuire de structuri, numite noduri, n care ecare nod, ex-ceptand ultimul, \cunoaste" adresa nodului de dupa el (nodul succesor). In forma sa cea mai simpla,un nod v este o structura cu doua campuri: un camp v->elt pentru memorarea informatiei si un campv->succ care memoreaza adresa nodului succesor. Se presupune ca se cunosc adresele primului si re-spectiv ultimului nod din lista. O lista liniara simplu nlantuita este reprezentata grac ca n g. 2.10.Lista liniara simplu nlantuita este o structura de date dinamica n sensul ca pot inserate sau eliminatenoduri cu conditia sa e pastrata proprietatea de nlantuire liniara. Aceasta structura va utilizata lareprezentarea obiectelor de tip data a tipurilor de date de nivel nalt din capitolul 3.

Page 9: algoritmi_tehnici_dorel lucanu - carte

2.1. LIMBAJ ALGORITMIC 11

0 elt 2 elt n-1elt elt 1 . . .

L.prim L.ultim

Figura 2.10: Lista liniara simplu nlantuita

e1 e2e en-10 . . .

L.prim L.ultim

Figura 2.11: Lista liniara dublu nlantuita

2.1.6.4 Liste liniare dublu nlantuite

Listele liniare dublu nlantuite sunt asemanatoare celor simplu nlantuite cu deosebirea ca, n plus, ecarenod, exceptand primul, \cunoaste" adresa nodului din fata sa (nodul predecesor). Astfel, un nod v areun camp n plus v->pred care memoreaza adresa nodului predecesor. O lista liniara dublu nlantuitaeste reprezentata grac ca n g. 2.11.

2.1.7 Calculul unui program

Intuitiv, calculul (executia) unui program consta n succesiunea de pasi elementari determinati de executiileinstructiunilor ce compun programul. Fie, de exemplu, urmatorul program:

x 0

i 1

while (i < 10) do

x x*10+i

i i+2

Calculul descris de acest program ar putea descris de urmatorul tabel:

Pasul Instructiunea i x0 x 0 1 i 1 02 x x*10+i 1 03 i i+2 1 14 x x*10+i 3 15 i i+2 3 136 x x*10+i 5 137 i i+2 5 1358 x x*10+i 7 1359 i i+2 7 135710 x x*10+i 9 135711 i i+2 9 1357912 11 13579

Acest calcul este notat formal printr-o secventa c0 - c1 - - c12. Prin ci am notat conguratiile ceintervin n calcul. O conguratie include instructiunea curenta (starea programului) si starea memoriei(valorile curente ale variabilelor din program). In exemplul de mai sus, o conguratie este reprezentatade o linie n tabel. Relatia ci1 - ci are urmatoarea semnicatie: prin executia instructiunii din ci1, setransforma ci1 n ci. c0 se numeste conguratie initiala iar c12 conguratie nala. Notam ca pot existasi calcule innite. De exemplu instructiunea

Page 10: algoritmi_tehnici_dorel lucanu - carte

12 CAPITOLUL 2. DESPRE ALGORITMI

while (true) do

i i+1

genereaza un calcul innit.

2.1.8 Exercitii

Exercitiul 2.1.1. O sectiune a tabloului a, notata a[i..j], este formata din elementele a[i]; a[i +1]; : : : ; a[j], i j. Suma unei sectiuni este suma elementelor sale. Sa se scrie un program care, aplicandtehnica de la problema platourilor [Luc93], determina sectiunea de suma maxima.

Exercitiul 2.1.2. Sa se scrie o functie care, pentru un tabloub, determina valoarea predicatului:

P 8i; j : 1 i < j n) b[i] b[j]

Sa se modice acest subprogram astfel ncat sa ordoneze crescator elementele unui tablou.

Exercitiul 2.1.3. Sa se scrie un subprogram tip functie care, pentru un tablou de valori booleene b,determina valoarea predicatului:

P 8i; j : 1 i j n) b[i]) b[j])

Exercitiul 2.1.4. Se considera tabloul a ordonat crescator si tabloul b ordonat descrescator. Sa se scrieun program care determina cel mai mic x, cand exista, ce apare n ambele tablouri.

Exercitiul 2.1.5. Se considera doua tablouril a si b. Ambele tablouri au proprietatea ca oricare douaelemente sunt distincte. Sa se scrie un program care determina elementele x, cand exista, ce apar nambele tablouri. Sa se compare complexitatea timp acestui algoritm cu cea a algoritmului din 2.1.4. Cese poate spune despre complexitatile celor doua probleme?

Exercitiul 2.1.6. Sa se proiecteze structuri pentru reprezentarea punctelor si respectiv a dreptelor dinplan. Sa se scrie subprograme care sa rezolve urmatoarele probleme:

(i) Apartenenta unui punct la o dreapta:

Instanta O dreapta d si un punct P .

Intrebare P 2 d?

(ii) Intersectia a doua drepte:

Intrare Doua drepte d1 si d2.Iesire d1 \ d2.

(iii) Test de perpendicularitate:

Instanta Doua drepte d1 si d2.

Intrebare d1 ? d2?

(iv) Test de paralelism:

Instanta Doua drepte d1 si d2.

Intrebare d1kd2?

Exercitiul 2.1.7. Sa se proiecteze o structura pentru reprezentarea numerelor complexe. Sa se scriesubprograme care realizeaza operatii din algebra numerelor complexe.

Exercitiul 2.1.8. Presupunem ca numerele complexe sunt reprezentate ca n solutia exercitiului 2.1.7.Un polinom cu coecienti complecsi poate reprezentat ca un tablou de articole. Sa se scrie un sub-program care, pentru un polinom cu coecienti complecsi P si un numar complex z date, calculeazaP (z).

Page 11: algoritmi_tehnici_dorel lucanu - carte

2.1. LIMBAJ ALGORITMIC 13

Exercitiul 2.1.9. O sa ntr-o biblioteca poate contine informatii despre o carte sau o revista. Informatiilecare intereseaza despre o carte sunt: autor, titlu, editura si an aparitie, iar cele despre o revista sunt:titlu, editura, an, volum, numar. Sa se deneasca un tip de date articol cu variante pentru reprezentareaunei se.

Exercitiul 2.1.10. Sa se proiecteze o structura de date pentru reprezentarea datei calendaristice. Sa sescrie subprograme care realizeaza urmatoarele:

(i) Decide daca valoarea unei variabile din structura contine o data valida.

(ii) Avand la intrare o data calendaristica ofera la iesire data calendaristica urmatoare.

(iii) Avand la intrare o data calendaristica ofera la iesire data calendaristica precedenta.

Exercitiul 2.1.11. Sa se scrie tipurile si instructiunile care construiesc listele nlantuite din g. 2.12.Se va utiliza cel mult o variabila referinta suplimentara.

0C 0

0E0 0D0

0A0

0B0 ?

6

?

?

6

?

-

0B0 nil

0E0 0D0

0A0

0C 0

66

6 6

a)

b)

-

Figura 2.12:

Exercitiul 2.1.12. Sa se scrie un subprogram care inverseaza sensul legaturilor ntr-o lista simplunlantuita astfel ncat primul nod devine ultimul si ultimul nod devine primul.

Exercitiul 2.1.13. Se considera un tablou unidimensional de dimensiune mare care contine elementealocate (ocupate) si elemente disponibile. Ne putem imagina ca acest tablou reprezinta memoria unuicalculator (element al tabloului = cuvant de memorie). Zonele ocupate (sau zonele libere) din tablousunt gestionate cu ajutorul unei liste nlantuite. Asupra tabloului se executa urmatoarele operatii:

Aloca(m) - determina o secventa de elemente succesive de lungime m, apoi adresa si lungimeaacesteia le adauga ca un nou element la lista zonelor ocupate (sau o elimina din lista zonelor libere)si ntoarce adresa zonei determinate; daca nu se poate aloca o asemenea secventa ntoarce -1 (saualta adresa invalida n tablou).

Elibereaza(a; l) - disponibilizeaza secventa de lungime l ncepand cu adresa a; lista zonelor ocupate(sau a zonelor libere) va actualizata corespunzator.

Colecteaza - reaseaza zonele ocupate astfel nct sa existe o singura zona disponibila (compacticareazonelor disponibile); lista zonelor ocupate (sau a zonelor libere) va actualizata corespunzator.

Page 12: algoritmi_tehnici_dorel lucanu - carte

14 CAPITOLUL 2. DESPRE ALGORITMI

Observatie. Pentru functia de alocare se considera urmatoarele doua strategii:

FirstFit - aloca prima zona disponibila de lungime m;

BestFit - aloca cea mai mica zona de marime m.

Sa se proiecteze structurile de date si subprogramele care sa realizeze operatiile descrise mai sus.

Exercitiul 2.1.14. Se considera problema alocarii memoriei din exercitiul 2.1.13. Sa se proiecteze ostructura de date pentru gestionarea memoriei cand toate cererile au aceesi lungime k. Mai este necesaracolectarea zonelor neutilizate? Sa se scrie proceduri care aloca si elibereaza zone de memorie utilizandaceasta structura.

2.2 Probleme si programe

Un algoritm constituie solutia unei probleme specice. Descrierea algoritmului ntr-un limbaj algoritmicse face prin intermediul unui program. In aceasta sectiune vom preciza conditiile pe care trebuie sa lendeplineasca un program pentru a descrie un algoritm, adica ce nseamna ca un program descrie o solutiepentru o problema data.

2.2.1 Notiunea de problema

O problema are doua componente: domeniul, care descrie elementele care intervin n problema si relatiiledintre aceste elemente, si o ntrebare despre proprietatile anumitor elemente sau o cerinta de determinarea unor elemente ce au o anumita proprietate. In functie de scopul urmarit, exista mai multe moduri dea formaliza o problema. Noi vom utiliza numai doua dintre ele.

Intrare/Iesire. Daca privim un program ca o cutie neagra care transforma datele de intrare n date deiesire atunci putem formaliza problema rezolvata de program ca o pereche (Intrare; Iesire). ComponentaIntrare descrie datele de intrare iar componenta Iesire descrie datele de iesire. Un exemplu simplu deproblema reprezentata astfel este urmatorul:

Intrare: Un numar ntreg pozitiv x.

Iesire: Cel mai mare numar prim mai mic decat sau egal cu x.

Problema de decizie. Este un caz particular de problema cand iesirea este de forma 'DA' sau 'NU'. Oastfel de problema este reprezentata ca o pereche (Instanta; Intrebare) unde componenta Instanta descriedatele de intrare iar componenta Intrebare se refera, n general, la existenta unui obiect sau a uneiproprietati. Un exemplu tipic l reprezinta urmatoarea problema:

Instanta: Un numar ntreg x.

Intrebare: Este x numar prim?

Problemele de decizie sunt preferate atat n teoria complexitatii cat si n teoria calculabilitatii datoritareprezentarii foarte simple a iesirilor. In sectiunea 2.2.3 vom exemplica cum orice problema poate reprezentata ca o problema de decizie.

2.2.2 Problema rezolvata de un program

Convenim sa consideram ntotdeauna intrarile p ale unei probleme P ca ind instante si, prin abuz denotatie, scriem p 2 P .

Denitia 2.1. Fie S un program si P o problema. Spunem ca o conguratie initiala c0 a lui S includeinstanta p 2 P daca exista o structura de data inp, denita n S, astfel ncat valoarea lui inp din c0constituie o reprezentare a lui p. Analog, spunem ca o conguratie nala cn a unui program S includeiesirea P (p) daca exista o structura de data out, denita n S, astfel ncat valoarea lui out din cnconstituie o reprezentare a lui P (p).

Page 13: algoritmi_tehnici_dorel lucanu - carte

2.2. PROBLEME SI PROGRAME 15

Denitia 2.2. (Problema rezolvata de un program)1. Un program S rezolva o problema P n sensul corectitudinii totale daca pentru orice instanta p,calculul unic determinat de conguratia initiala ce include p este nit si conguratia nala include iesireaP (p).2. Un program S rezolva o problema P n sensul corectitudinii partiale daca pentru orice instanta p

pentru care calculul unic determinat de conguratia initiala ce include p este nit, conguratia nalainclude iesirea P (p).

Denitia 2.3. (Problema rezolvabila/nerezolvabila)1. O problema P este rezolvabila daca exista un program care sa o rezolve n sensul corectitudinii totale.Daca P este o problema de decizie, atunci spunem ca P este decidabila.2. O problema de decizie P este semidecidabila sau partial decidabila daca exista un program S carerezolva P n sensul corectitudinii partiale astfel ncat calculul lui S este nit pentru orice instanta p

pentru care raspunsul la ntrebare este 'DA'.3. O problema P este nerezolvabila daca nu este rezolvabila, adica nu exista un program care sa o rezolven sensul corectitudinii totale. Daca P este o problema de decizie, atunci spunem ca P este nedecidabila.

2.2.3 Un exemplu de problema nedecidabila

In teoria calculabilitatii este mult mai usor de lucrat cu probleme de decizie deoarece pentru acestease cunoaste forma raspunsului: 'DA' (true) sau 'NU' (false). Notam ca orice problema admite oreprezentare sub forma de problema de decizie, indiferent de reprezentarea sa initiala. Consideram caexemplu problema:

Problema P

Intrare: a; b 2 Z.

Iesire: x0; y0 cu ax0 + by0 = minfax+ by j x; y 2 f0; 1gg.

P poate reprezentata ca problema de decizie astfel:

Problema P 0

Instanta: a; b;K 2 Z.

Intrebare: Exista x; y 2 f0; 1g cu ax+ by K?

P si P 0 sunt echivalente din punct de vedere al calculabilitatii.De obicei, pentru reprezentarea problemelor de decizie se considera o multime A, iar o instanta este

de forma B A; x 2 A si ntrebarea de forma x 2 B?.Pentru a arata ca o problema este decidabila este sucient sa gasim un program care sa o rezolve.

Mai complicat este cazul problemelor nedecidabile. In legatura cu acestea din urma se pun, n mod resc,urmatoarele ntrebari: Exista probleme nedecidabile? Cum putem demonstra ca o problema nu estedecidabila? Raspunsul la prima ntrebare este armativ. Un prim exemplu de problema necalculabilaeste cea cunoscuta sub numele de problema opririi. Notam cu A multimea perechilor de forma hS; xiunde S este un program si x este o intrare pentru S, iar B este submultimea formata din acele perechihS; xi pentru care calculul lui S pentru intrarea x este nit. Daca notam prin S(x) (a se citi S(x) = true)faptul ca hS; xi 2 B, atunci problema opririi poate scrisa astfel:

Problema opririi

Instanta: Un program S, x 2 Z.

Intrebare: S(x)?

Teorema 2.1. Problema opririi nu este decidabila.

Demonstratie. Un program Q, care rezolva problema opririi, are ca intrare o pereche hS; xi si se oprestentotdeauna cu raspunsul 'DA', daca S se opreste pentru intrarea x, sau cu raspunsul 'NU', daca S nuse opreste pentru intrarea x. Fie Q0 urmatorul program:

Page 14: algoritmi_tehnici_dorel lucanu - carte

16 CAPITOLUL 2. DESPRE ALGORITMI

while (Q(x; x) = 0DA0) do/*nimic*/

Reamintim ca Q(x; x) = 0DA0 nseamna ca programul reprezentat de x se opreste pentru intrarea x,adica propria sa codicare. Presupunem acum ca x este codicarea lui Q0. Exista doua posibilitati.

1. Q0 se opreste pentru intrarea x. Rezulta Q(x; x) = 0NU 0, adica programul reprezentat de x nu seopreste pentru intrarea x. Dar programul reprezentat de x este chiar Q0. Contradictie.

2. Q0 nu se opreste pentru intrarea x. Rezulta Q(x; x) = 0DA0, adica programul reprezentat de x seopreste pentru intrarea x. Contradictie.

Asadar, nu exista un program Q care sa rezolve problema opririi. sfdem

Observatie: Rezolvarea teoremei de mai sus este strans legata de urmatorul paradox logic. \Exista unoras cu un barbier care barbiereste pe oricine ce nu se barbiereste singur. Cine barbiereste pe barbier?"

sfobs

2.3 Masurarea performantelor unui algoritm

Fie P o problema si A un algoritm pentru P . Fie c0 -A c1 -A cn un calcul nit al algoritmului A.Notam cu t(ci) timpul necesar obtinerii conguratiei ci din ci1; 1 i n, si cu s(ci) spatiul de memorieocupat n conguratia ci; 0 i n.

Denitia 2.4. Fie A un algoritm pentru problema P , p 2 P o instanta a problemei P si c0 -c1 - -cncalculul lui A corespunzator instantei p. Timpul necesar algoritmului A pentru rezolvarea instantei p este:

TA(p) =

nXi=1

t(ci)

Spatiul (de memorie) necesar algoritmului A pentru rezolvarea instantei p este:

SA(p) = max0in

s(ci)

In general este dicil de calculat cele doua masuri n functie de instante. Acesta poate simplicatastfel. Asociem unei instante p 2 P o marime g(p), care, n general, este un numar natural, pe care onumim marimea instantei p. De exemplu, g(p) poate suma lungimilor reprezentarilor corespunzanddatelor din instanta p. Daca reprezentarile datelor din p au aceeasi lungime, atunci se poate lua g(p)egala cu numarul datelor. Astfel daca p consta dintr-un tablou atunci se poate lua g(p) ca ind numarulde elemente ale tabloului; daca p consta dintr-un polinom se poate lua g(p) ca ind gradul polinomului(= numarul coecientilor minus 1); daca p este un graf se poate lua g(p) ca ind numarul de varfuri saunumarul de muchii etc.

Denitia 2.5. Fie A un algoritm pentru problema P .

1. Spunem ca A rezolva P n timpul T favA (n) daca:

TfavA (n) = inf

TA(p) j p 2 P; g(p) = n

2. Spunem ca A rezolva P n timpul TA(n) daca:

TA(n) = supTA(p) j p 2 P; g(p) = n

3. Spunem ca A rezolva P n spatiul SfavA (n) daca:

SfavA (n) = inf

sa(p) j p 2 P; g(p) = n

Page 15: algoritmi_tehnici_dorel lucanu - carte

2.3. MASURAREA PERFORMANTELOR UNUI ALGORITM 17

4. Spunem ca A rezolva P n spatiul SA(n) daca:

SA(n) = supsa(p) j p 2 P; g(p) = n

Functia T

favA (SfavA ) se numeste complexitatea timp (spatiu) a algoritmului A pentru cazul cel mai

favorabil iar functia TA (SA) se numeste complexitatea timp (spatiu) a algoritmului A pentru cazul celmai nefavorabil.

Exemplu: Consideram problema cautarii unui element ntr-un tablou:

Problema PIntrare: n; (a0; : : : ; an1); z numere ntregi.

Iesire: poz =

(minfi j ai = zg daca fi j ai = zg 6= ;;

1 altfel.

Presupunem ca secventa (a1; : : : ; an) este memorata n tabloul (a[i] j 1 i n). Algoritmul descris deurmatorul program rezolva P :

i 0

while (a[i] 6= z) and (i < n-1) do

i i+1

if (a[i] = z)

then poz i

else poz -1

Convenim sa notam acest algoritm cu A. Consideram ca dimensiune a problemei P numarul n al ele-mentelor din secventa n care se cauta. Deoarece suntem cazul cand toate datele sunt memorate pe cateun cuvant de memorie, vom presupune ca toate operatiile necesita o unitate de timp. Mai ntai calculamcomplexitatile timp. Cazul cel mai favorabil este obtinut cand a[0] = z si se efectueaza trei comparatii si

doua atribuiri. Rezulta T favA (n) = 3+2 = 5. Cazul cel mai nefavorabil se obtine cand z 62 fa0; : : : ; an1g

sau z = a[n1] si n acest caz sunt executate 2n+1 comparatii si n+1 atribuiri. Rezulta TA(n) = 3n+2.Pentru simplitatea prezentarii, nu au mai fost luate n considerare operatiile and si operatiile de adunare

si scadere. Complexitatea spatiu pentru ambele cazuri este n+ 6. sfex

Observatie: Complexitatile pentru cazul cel mai favorabil nu ofera informatii relevante despre ecientaalgoritmului. Mult mai semnicative sunt informatiile oferite de complexitatile n cazul cel mai nefavor-abil: n toate celelalte cazuri algoritmul va avea performante mai bune sau cel putin la fel de bune.

Pentru complexitatea timp nu este necesar totdeauna sa numaram toate operatiile. Pentru exemplulde mai sus, observam ca operatiile de atribuire (fara cea initiala) sunt precedate de comparatii. Astfelca putem numara numai comparatiile, pentru ca numarul acestora domina numarul atribuirilor. Putem

merge chiar mai departe si sa numaram numai comparatiile ntre z si componentele tabloului. sfobs

Exista situatii cand instantele p cu g(p) = n pentru care TA(p) este egala cu TA(n) sau ia valori foarteapropiate de TA(n) apar foarte rar. Pentru aceste cazuri este preferabil sa calculam comportarea n mediea algoritmului. Pentru a putea calcula comportarea n medie este necesar sa privim marimea TA(p) caind o variabila aleatoare (o experienta = executia algoritmului pentru o instanta p, valoarea experientei= durata executiei algoritmului pentru instanta p) si sa precizam legea de repartitie a acestei variabilealeatoare. Apoi, comportarea n medie (complexitatea medie) se calculeaza ca ind media acestei variabilealeatoare (consideram numai cazul complexitatii timp):

TmedA (n) =M(fTA(p) j p 2 P ^ g(p) = ng)

Daca multimea valorilor variabilei aleatoare TA(p) este nita , x1; : : : ; xk, si probabilitatea ca TA(p) = xieste pi, atunci media variabilei aleatoare TA (complexitatea medie) este:

TmedA (n) =

kXi=1

xi pi

Page 16: algoritmi_tehnici_dorel lucanu - carte

18 CAPITOLUL 2. DESPRE ALGORITMI

Exemplu: Consideram problema P din exemplul anterior. Multimea valorilor variabilei aleatoareTA(p) este f3i+ 2 j 1 i ng. In continuare trebuie sa stabilim legea de repartitie. Facem urmatoarelepresupuneri: probabibilitatea ca z 2 fa1; : : : ; ang este q si poz = i cu probabilitatea

qn (indicii i candideaza

cu aceeasi probabilitate pentru prima aparitie a lui z). Rezulta ca probabilitatea ca z 62 fa1; : : : ; ang este1 q. Acum probabilitatea ca TA(p) = 3i+ 2 (poz = i) este

qn , pentru 1 i < n, iar probabilitatea ca

TA(p) = 3n+2 este pn =qn +(1 q) (probabilitatea ca poz = n sau ca z 62 fa1; : : : ; ang). Complexitatea

medie este:

TmedA (n) =

nPi=1

pixi =n1Pi=1

qn (3i+ 2) + (

qn + (1 q)) (3n+ 2)

=3qn

nPi=1

i+qn

nPi=1

2 + (1 q) (3n+ 2)

=3qn

n(n+ 1)2 + 2q + (1 q) (3n+ 2)

=3q (n+ 1)

2 + 2q + (1 q) (3n+ 2)

= 3n 3nq2 + 3q

2 + 2

Pentru q = 1 (z apare totdeauna n secventa) avem TmedA (n) = 3n

2 + 72 si pentru q = 1

2 avem TmedA (n) =

9n4 + 11

4 . sfex

Exemplu: Fie P 0 urmatoarea problema: dat un numar natural n NMax, sa se determine cel maimic numar natural x cu proprietatea n 2x. P 0 poate rezolvata prin metoda cautarii secventiale:

x 0

doilax 1

while (n > doilax) do

x x+1

doilax doilax * 2

Daca se ia dimensiunea problemei egala cu n, atunci exista o singura instanta a problemei P 0 pentru unn xat si deci cele trei complexitati sunt egale. Daca se ia dimensiunea problemei ca ind NMax, atunci

cele trei complexitati se calculeaza ntr-o maniera asemanatoare cu cea de la exercitiul precedent. sfex

2.3.1 Calcul asimptotic

In practica, atat TA(n) cat si TmedA (n) sunt dicil de evaluat. Din acest motiv se cauta, de multe ori,

margini superioare si inferioare pentru aceste marimi. Urmatoarele clase de functii sunt utilizate cu succesn stabilirea acestor margini:

O(f(n)) = fg(n) j (9c > 0; n0 0)(8n n0)jg(n)j c jf(n)jg(f(n)) = fg(n) j (9c > 0; n0 0)(8n n0)jg(n)j c jf(n)jg(f(n)) = fg(n) j (9c1; c2 > 0; n0 0)(8n n0)c1 jf(n)j jg(n)j c2 jf(n)jg

Cu notatiile O; si se pot forma expresii si ecuatii. Consideram numai cazul O, celelalte tratandu-sesimilar. Expresiile construite cu O pot de forma:

O(f1(n)) op O(f2(n))

unde \op" poate +;; etc. si noteaza multimile:

fg(n) j (9g1(n); g2(n); c1; c2 > 0; n1; n2 > 1)((8n)g(n) = g1(n) op g2(n)^

(8n n1)g1(n) c1f1(n) ^ (8n n2)g2(n) c2f2(n))g

De exemplu:

O(n) +O(n2) = ff(n) = f1(n) + f2(n) j (8n n1)f1(n) c1n ^ (8n n2)f2(n) c2n2g

Page 17: algoritmi_tehnici_dorel lucanu - carte

2.3. MASURAREA PERFORMANTELOR UNUI ALGORITM 19

Utilizand regulile de asociere, se obtin expresii de orice lungime:

O(f1(n)) op1 O(f2(n)) op2

Orice functie f(n) o putem gandi ca o notatie pentru multimea cu un singur element f(n) si deci putemforma expresii de forma:

f1(n) + O(f2(n))

ca desemnand multimea:

ff1(n) + g(n) j (9c > 0; n0 > 1)(8n n0)g(n) c f2(n)g

Peste expresii consideram \ecuatii" de forma:

expr1 = expr2

cu semnicatia ca multimea desemnata de expr1 este inclusa n multimea desemnata de expr2. Deexemplu, avem:

n logn+O(n2) = O(n2)

pentru ca (9c1 > 0; n1 > 1)(8n n1)n logn c1n2, daca g1(n) 2 O(n2) atunci (9c2 > 0; n2 > 1)(8n

n2)g1(n) c2n2 si de aici (8n n0)g(n) = n logn + g1(n) n logn + c2n

2 (c1 + c2)n2, unde

n0 = maxfn1; n2g. De remarcat nesimetria ecuatiilor: partile stanga si cea dreapta joaca roluri distincte.Ca un caz particular, notatia f(n) = O(g(n)) semnica de fapt f(n) 2 O(g(n)).

Notatiile O; si ofera informatii cu care putem aproxima comportarea unei functii. Pentru caaceasta aproximare sa aiba totusi un grad de precizie cat mai mare, este necesar ca multimea desemnatade partea dreapta a ecuatiei sa e cat mai mica. De exemplu, avem atat 3n = O(n) cat si 3n = O(n2).Prin incluziunea O(n) = O(n2) rezulta ca prima ecuatie ofera o aproximare mai buna. De ecare datavom cauta multimi care aproximeaza cel mai bine comportarea unei functii.

Cu notatiile de mai sus, doua programe, care rezolva aceeasi problema, pot comparate numai dacaau complexitatile n clase diferite. De exemplu, un algoritm A cu TA(n) = O(n) este mai ecient decatun algoritm A0 cu TA0(n) = O(n2). Daca cei doi algoritmi au complexitatile n aceeasi clasa, atuncicompararea lor devine mai dicila pentru ca trebuie determinate si constantele cu care se nmultescreprezentantii clasei.

2.3.2 Complexitatea problemelor

In continuare extindem notiunea de complexitate la cazul problemelor.

Denitia 2.6. Problema P are complexitatea timp (spatiu) O(f(n)) n cazul cel mai nefavorabil dacaexista un algoritm A care rezolva problema P n timpul TA(n) = O(f(n)) (spatiul SA(n) = O(f(n))).Problema P are complexitatea timp (spatiu) (f(n)) n cazul cel mai nefavorabil daca orice algoritm A

pentru P are complexitatea timp TA(n) = (f(n)) (spatiu SA(n) = (f(n))).Problema P are complexitatea (f(n)) n cazul cel mai nefavorabil daca are simultan complexitatea(f(n)) si complexitatea O(f(n)).

Observatie: Denitia de mai sus necesita cateva comentarii. Pentru a arata ca o anumita problema arecomplexitatea O(f), este sucient sa gasim un algoritm pentru P care are complexitatea O(f(n)). Pentrua arata ca o problema are complexitatea (f(n)) este necesar de aratat ca orice algoritm pentru P arecomplexitatea n cazul cel mai nefavorabil n clasa (f(n)). In general, acest tip de rezultat este dicilde aratat, dar este util atunci cand dorim sa aratam ca un anumit algoritm este optimal. Complexitatea

unui algoritm optimal apartine clasei de functii care da limita inferioara pentru acea problema. sfobs

Page 18: algoritmi_tehnici_dorel lucanu - carte

20 CAPITOLUL 2. DESPRE ALGORITMI

2.3.3 Calculul complexitatii timp pentru cazul cel mai nefavorabil

Un algoritm poate avea o descriere complexa si deci evaluarea sa poate pune unele probleme. De aceeaprezentam cateva strategii ce sunt aplicate n determinarea complexitatii timp pentru cazul cel mainefavorabil. Deoarece orice algoritmul este descris de un program, n cele ce urmeaza consideram S osecventa de program. Regulile prin care se calculeaza complexitatea timp sunt date n functie de structuralui S:

1. S este o instructiune de atribuire. Complexitatea timp a lui S este egala cu complexitatea evaluariiexpresiei din partea dreapta.

2. S este forma:

S1S2

Complexitatea timp a lui S este egala cu suma complexitatilor programelor S1 si S2.

3. S este de forma if e then S1 else S2. Complexitatea timp a lui S este egala cu maximul dintrecomplexitatile programelor S1 si S2 la care se aduna complexitatea evaluarii expresiei e.

4. S este de forma while e do S1. Se determina cazul cand se executa numarul maxim de executii alebuclei while si se face suma timpilor calculati pentru ecare iteratie. Daca nu este posibila deter-minarea timpilor pentru ecare iteratie, atunci complexitatea timp a lui S este egala cu produsuldintre maximul dintre timpii executiilor buclei S1 si numarul maxim de executii ale buclei S1.

Plecand de la aceste reguli de baza, se pot obtine n mod natural reguli de calcul a complexitatii pentrutoate instructiunile. Consideram ca obtinerea acestora constituie un bun exrcitiu pentru cititor.

2.3.4 Exercitii

2.4 Exercitii

Exercitiul 2.4.1. Sa se arate ca:

1. 7n2 23n = (n2).

2. n! = O(nn).

3. n! = (nn).

4. 5n2 + n logn = (n2).

5.Pn

i=1 ik = (nk+1).

6. nk

logn= O(nk) (k > 0).

7. n5 + 2n = O(2n).

8. 5n = O(2n).

Exercitiul 2.4.2. Sa se determine complexitatea timp, pentru cazul cel mai nefavorabil, a algoritmuluidescris de urmatorul program:

x a

y b

z 1

while (y > 0) do

if (y impar) then z z*x

y y div 2

x x*x

Page 19: algoritmi_tehnici_dorel lucanu - carte

2.4. EXERCITII 21

Indicatie. Se va tine cont de faptul ca programul calculeaza z = abnot= f(a; b) dupa formula

f(u; v) =

8><>:1 ; daca v = 0

uv1 u ; daca v este impar

(uv

2 )2 ; daca v este par.

Exercitiul 2.4.3. Sa se determine complexitatea timp a algoritmului descris de urmatorul program:

x a

y b

s 0

while x<>0 do

while not odd(x) do

y 2*y

x x div 2

s s+y

x x-1

Exercitiul 2.4.4. Sa se scrie un program care pentru un tablou unidimensional dat, determina dacatoate elementele tabloului sunt egale sau nu. Sa se determine complexitatile timp pentru cazul cel mainefavorabil si n medie ale algoritmului descris de program.

Exercitiul 2.4.5. Se considera polinomul cu coecienti reali p = a0 + a1x+ + anxn si punctul x0.

a) Sa se scrie un program care sa calculeze valoarea polinomului p n x0, utilizand formula:

p(x0) =

nXi=0

ai xi0

b) Sa se mbunatateasca programul de mai sus, utilizand relatia xi+10 = xi0 x0.

c) Sa se scrie un program care sa calculeze valoarea polinomului p n x0, utilizand formula (schemalui Horner):

p(x0) = a0 + ( + (an1 + an x0) )

Pentru ecare dintre cele trei cazuri, sa se determine numarul de nmultiri si de adunari si sa se compare.Care metoda este cea mai ecienta?

Exercitiul 2.4.6. Sa se scrie un program care cauta secvential ntr-un tablou ordonat. Sa se determinecomplexitatile timp pentru cazul cel mai nefavorabil si n medie, ale algoritmului descris de program.

Page 20: algoritmi_tehnici_dorel lucanu - carte

Capitolul 3

Tipuri de date de nivel nalt

3.1 Lista liniara

3.1.1 Tipul de date abstract LLIN

3.1.1.1 Descrierea obiectelor de tip data

O lista liniara este o secventa nita (e0; : : : ; en1) n care elementele ei apartin unui tip dat Elt. Compo-nentele unei liste nu trebuie sa e neaparat distincte; adica, putem avea i 6= j si ei = ej . Lungimea uneiliste L = (e0; : : : ; en1), notata cu Lung(L), este data de numarul de componente din lista: Lung(L) = n.Lista vida ( ) este lista fara nici o componenta (de lungime 0).

3.1.1.2 Operatii.

ListaVida. Intoarce lista vida.

Intrare: nimic;

Iesire: lista vida ( ).

EsteVida. Testeaza daca o lista data este vida.

Intrare: o lista liniara L;

Iesire: true daca L = ( ), false daca L 6= ( ).

Lung. Intoarce lungimea unei listei date.

Intrare: o lista liniara L = (e0; : : : ; en1) cu n 0;

Iesire: n.

Copie. Intoarce o copie distincta a unei liste date.

Intrare: o lista liniara L;

Iesire: o copie L0 distincta a lui L.

Egal. Testeaza daca doua liste liniare sunt egale.

Intrare: doua liste L = (e0; : : : ; en1) si L0 = (e00; : : : ; e

0

n01);

Iesire: true daca n = n0 si e0 = e00; : : : ; en1 = e0n1, false, n celelalte cazuri.

23

Page 21: algoritmi_tehnici_dorel lucanu - carte

24 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Poz. Cauta daca un element dat x apare ntr-o lista liniara data L.

Intrare: o lista liniara L = (e0; : : : ; en1) si un element x din Elt;

Iesire: adresa invalida (1 sau NULL) daca x nu apare n L, adresa elementului ei daca ei = x si (8j)0 j < i) ej 6= x.

Parcurge. Parcurge o lista liniara data efectuand o prelucrare uniforma asupra componentelor acesteia.

Intrare: o lista liniara L si o procedura Viziteaza(e);

Iesire: lista L dar ale carei componente au fost prelucrate de procedura Viziteaza.

Citeste. Intoarce elementul de la o pozitie data dintr-o lista data.

Intrare: o lista liniara L = (e0; : : : ; en1) si o pozitie k 0;

Iesire: ek daca 0 k < n, eroare, n celelalte cazuri.

Insereaza. Adauga un element dat ntr-o lista liniara data la o pozitie data.

Intrare: o lista liniara L = (e0; : : : ; en1), un element e din Elt si o pozitie k 0;

Iesire: L = (e0; : : : ; ek1; e; ek; : : : ; en1) daca 0 k < n, L = (e0; : : : ; en1; e) daca k n.

EliminaDeLaK. Elimina elementul de la o pozitie data dintr-o lista liniara data.

Intrare: o lista liniara L = (e0; : : : ; en1) si o pozitie k 0;

Iesire: L = (e0; : : : ; ek1; ek+1; : : : ; en1) daca 0 k < n, L = (e0; : : : ; en1) daca k n.

Elimina. Elimina un element dat dintr-o lista liniara data.

Intrare: o lista liniara L = (e0; : : : ; en1) si un element e din Elt;

Iesire: lista L din care s-au eliminat toate elementele ei egale cu e.

3.1.2 Implementarea dinamica cu liste simplu nlantuite

3.1.2.1 Reprezentarea obiectelor de tip data

O lista liniara L = (e1; : : : ; en) este reprezentata printr-o lista ca cea din g. 3.1. Fiecare componenta alistei liniare este memorata ntr-un nod al listei simplu nlantuite. Exista doi pointeri L.prim si L.ultimcare fac referire la primul si respectiv ultimul nod.

n-1. . .

L.prim L.ultim

e0 e1 e2 e

Figura 3.1: Reprezentarea listei liniare cu lista simplu nlantuita

3.1.2.2 Implementarea operatiilor

ListaVida. Este reprezentata de lista fara nici un nod: L:prim = L:ultim = NULL.

EsteVida. Este sucient sa se testeze daca pointerul L.prim este egal cu NULL.

Page 22: algoritmi_tehnici_dorel lucanu - carte

3.1. LISTA LINIARA 25

Lung. Parcurge lista si contorizeaza ecare nod parcurs. Timpul necesar determinarii lungimii este O(n).Acesta poate redus la O(1) daca lungimea ar inclusa n reprezentarea listei. Aceasta ar presupuneca toate operatiile care modica lungimea listei sa actualizeze corespunzator variabila responsabila cumemorarea lungimii.

function lung(L)

begin

lg 0

p L.prim

while (p 6= NULL) do

lg lg+1

p p->succ

return lg

end

Copie. Parcurge lista sursa si adauga la lista destinatie o copie a ecarui nod parcurs. Daca presupunemca operatia de copiere a unui nod se face n timpul O(t) atunci copierea ntregii liste se realizeaza n timpulO(n t).

procedure copie(L, Lcopie)

begin

if (L.prim = NULL)

then Lcopie.prim NULL

Lcopie.ultim NULL

else new(Lcopie.prim)

Lcopie.prim->elt L.prim->elt

Lcopie.ultim Lcopie.prim

p L.prim->succ

while (p 6= NULL) do

new(Lcopie.ultim->succ)

Lcopie.ultim Lcopie.ultim->succ

Lcopie.ultim->elt p->elt

p p->succ

Lcopie.ultim->succ NULL

end

Egal. Parcurge simultan cele doua liste si compara perechile de noduri corespunzatoare. Daca pre-supunem ca operatia de comparare a unei perechi de noduri se face n timpul O(1) atunci compararealistelor se realizeaza n timpul O(n) n cazul cel mai nefavorabil, unde n este valoarea minima dintrelungimile celor doua liste.

function egal(L1, L2)

begin

p1 L1.prim

p2 L2.prim

while ((p1 6= NULL) and (p2 6= NULL)) do

if (p1->elt 6= p2->elt) then return false

p1 p1->succ

p2 p2->succ

if ((p1 = NULL) and (p2 = NULL))

then return true

else return false

end

Poz. Se aplica tehnica cautarii secventiale: se pleaca din primul nod si se interogheaza nod cu nod panacand este gasit primul care memoreaza pe x sau au fost epuizate toate nodurile. Plecand de la ipoteza

Page 23: algoritmi_tehnici_dorel lucanu - carte

26 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

ca interogarea unui nod se face n timpul O(1), rezulta ca operatia de cautare necesita timpul O(n) ncazul cel mai nefavorabil.

function poz(L, x)

begin

p L.prim

while (p 6= NULL) do

if (p->elt = x) then return p

p p->succ

return NULL

end

Parcurge. Se parcurge lista nod cu nod si se aplica procedura Viziteaza. Se obtine un grad mai marede aplicabilitate a operatiei daca procedurile de tip Viziteaza au ca parametru adresa unui nod si nuinformatia memorata n nod. Daca t este timpul necesar procedurii Viziteaza pentru a prelucra un nod,atunci complexitatea timp a operatiei de parcurgere este O(n t).

procedure parcurge(L, viziteaza())

begin

p L.prim

while (p 6= NULL) do

viziteaza(p)

p p->succ

end

Citeste. Pentru a putea citi informatia din cel de-al k-lea nod, este necesara parcurgerea secventiala aprimelor k-noduri. Deoarece k < n, rezulta ca avem o complexitate n cazul cel mai nefavorabil egala cuO(n).

function citeste(L, k)

begin

p L.prim

i 0

while ((p 6= NULL) and (i < k)) do

i i + 1

p p->succ

if (p = NULL) then throw `eroare'

return p->elt

end

Insereaza. Ca si n cazul operatiei de citire, este necesara parcurgerea secventiala a primelor k1 noduri(noul nod va al k-lea). Daca avem k = 0 sau k Lung(L) atunci pointerii prim si respectiv ultim seactualizeaza corespunzator. Deoarece operatia de adaugare a unui nod dupa o adresa data se realizeazan timpul O(1), rezulta ca operatia de inserare necesita timpul O(n) n cazul cel mai nefavorabil.

procedure insereaza(L, k, e)

begin

if (k < 0) then throw `eroare'

new(q)

q->elt e

if ((k = 0) or (L.prim = NULL))

then q->succ L.prim

L.prim q

if (L.ultim = NULL) then L.ultim q

else p L.prim

i 0

while ((p 6= L.ultim) and (i < k-1)) do

Page 24: algoritmi_tehnici_dorel lucanu - carte

3.1. LISTA LINIARA 27

i i + 1

p p->succ

q->succ p->succ

p->succ q

if (p = L.ultim) then L.ultim q

end

EliminaDeLaK. Se realizeaza ntr-o maniera asemanatoare cu cea a operatiei de inserare.

procedure eliminaDeLaK(L, k)

begin

if ((k < 0) or (L.prim = NULL)) then throw `eroare'

if (k = 1)

then p L.prim

L.prim L.prim->succ

delete(p)

else p L.prim

i 1

while ((p 6= NULL) and (i < k-1)) do

i i + 1

p p->succ

if (p 6= NULL)

then q p->succ

p->succ q->succ

if (L.ultim = q) then L.ultim p

delete(q)

end

Elimina. Se parcurge lista secvential si ecare nod care memoreaza un element egal cu e este eliminat.Eliminarea unui nod presupune cunoasterea adresei nodului anterior; aceasta este determinata n timpulparcurgerii secventiale. Daca se elimina primul sau ultimul nod atunci pointerii L.prim si respectivL.ultim se actualizeaza corespunzator. Operatia de eliminare a unui nod se realizeaza n timpul O(1).Daca operatia de comparare se realizeaza n timpul O(1) atunci operatia de eliminare necesita timpulO(n) n cazul cel mai nefavorabil.

procedure elimina(L, e)

begin

while ((L.prim 6= NULL) and (L.prim->elt = e)) do

q L.prim

L.prim q->succ

delete(q)

if (L.prim = NULL)

then L.ultim NULL

else p L.prim

while (p 6= NULL) do

q p->succ

if ((q 6= NULL) and (q->elt = e))

then p->succ q->succ

if (L.ultim = q) then L.ultim p

delete(q)

p p->succ

end

Page 25: algoritmi_tehnici_dorel lucanu - carte

28 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

3.1.3 Implementarea statica cu tablouri

3.1.3.1 Reprezentarea obiectelor de tip data

O lista liniara L = (e0; : : : ; en1) este reprezentata printr-un tablou L.tab si o variabila indice L.ultimca n g. 3.2. Cele n componente a listei liniare sunt memorate n primele n componente ale tabloului.Dimensiunea maxima a tabloului este MAX astfel ca vor putea reprezentate numai liste de lungimeMAX . Pointerul indice L.ultim memoreaza adresa n tablou a ultimului element din lista; el coincidesi cu lungimea listei.

1

10 2 n-1 MAX-1

L.tab

L.ultim

e 0 e e e n-12

Figura 3.2: Reprezentarea listei liniare cu tablouri

3.1.3.2 Implementarea operatiilor

ListaVida. Este reprezentata faptul ca valoarea pointerului ultim este 1.

EsteVida. Se testeaza daca pointerul L.ultim este egal cu 1.

Lung. Intoarce valoarea pointerului L.utim adunata cu 1. Deci este realizata n timpul O(1).

function lung(L)

begin

return L.ultim+1

end

Copie. Parcurge tabloul sursa si copie ecare componenta parcursa. Daca presupunem ca operatia decopiere a unui nod se face n timpul O(t) atunci copierea ntregii liste se realizeaza n timpul O(n t).

procedure copie(L, Lcopie)

begin

Lcopie.ultim L.ultim

for i 0 to L.ultim do

Lcopie.tab[i] L.tab[i]

end

Egal. Parcurge simultan cele doua tablouri si compara perechile de componente corespunzatoare. Dacapresupunem ca operatia de comparare a unei perechi de elemente se face n timpul O(1) atunci compararealistelor se realizeaza n timpul O(n) n cazul cel mai nefavorabil, unde n este valoarea minima dintrelungimile celor doua liste.

function egal(L1, L2)

begin

if (L1.ultim 6= L2.ultim)

then return false

else for i 0 to L1.ultim do

if (L1.tab[i] 6= L2.tab[i]) then return false

return true

end

Page 26: algoritmi_tehnici_dorel lucanu - carte

3.1. LISTA LINIARA 29

Poz. Se aplica tehnica cautarii secventiale: se pleaca din prima componenta a tabloului si se interogheazacomponenta cu componenta pana cand este gasit prima care memoreaza pe x sau au fost epuizate toatecomponentele de adresa L:ultim. Plecand de la ipoteza ca interogarea unei componente se face ntimpul O(1) rezulta ca operatia de cautare necesita timpul O(n) n cazul cel mai nefavorabil.

function poz(L, x)

begin

i 0

while ((i < L.ultim) and (L.tab[i] 6= x)) do

i i+1

if (L.tab[i] = x)

then return i

else return -1

end

Parcurge. Se parcurge tabloul componenta cu componenta si se aplica procedura Viziteaza. Ca si ncazul implementarii cu liste simplu nlantuite, se obtine un grad mai mare de aplicabilitate a operatieidaca procedurile de tip Viziteaza au ca parametru adresa n tablou. Daca t este timpul necesar proceduriiViziteaza pentru a prelucra un nod, atunci complexitatea timp a operatiei de parcurgere este O(n t).

procedure parcurge(L, viziteaza())

begin

for i 0 to L.ultim do

viziteaza(L.tab, i)

end

Citeste. Intoarce valoarea din componenta k a tabloului. Este realizata n timpul O(1).

function citeste(L, k)

begin

if ((k >L.ultim) or (k < 0)) then throw `eroare'

return L.tab[k]

end

Insereaza. Elementele memorate n componentele k; k+1; : : : ; ultim trebuie deplasate (siftate) la dreaptacu o pozitie pentru a face componenta k libera. Valoarea pointerului ultim este incrementata cu o unitate.Cum k poate si 1, rezulta ca operatia de inserare necesita timpul O(n) n cazul cel mai nefavorabil.

procedure insereaza(L, k, e)

begin

if (k < 0) then throw `eroare'

if (L.ultim = MAX-1) then throw `memorie insuficienta'

L.ultim L.ultim+1

if (k L.ultim)

then L.tab[L.ultim] e

else for i L.ultim downto k+1 do

L.tab[i] L.tab[i-1]

L.tab[k] e

end

EliminaDeLaK. Elementele memorate n componentele k; k + 1; : : : ; ultim trebuie deplasate (siftate) lastanga cu o pozitie. Valoarea pointerului ultim este decrementata cu o unitate. Complexitatea timp ncazul cel mai nefavorabil este O(n).

procedure eliminaDeLaK(L, k)

begin

if (k < 0) then throw `eroare'

Page 27: algoritmi_tehnici_dorel lucanu - carte

30 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

if (L.ultim = -1) then throw `lista vida'

L.ultim L.ultim-1

for i k to L.ultim do

L.tab[i] L.tab[i+1]

end

Elimina. Se parcurge tabloul secvential si ecare componenta care memoreaza un element egal cu eeste eliminata prin deplasarea la stanga a elementelor memorate dupa ea. La ecare eliminare pointerulL.ultim se actualizeaza corespunzator. Operatia de eliminare a unui nod se realizeaza n timpul O(k),unde k este adresa n tablou a elementului. Daca operatia de comparare se realizeaza n timpul O(1)atunci operatia de eliminare necesita timpul O(n2) n cazul cel mai nefavorabil (cnd toate elementelesunt egale cu e).

procedure elimina(L, e)

begin

if (k < 0) then throw `eroare'

k 0

while (k L.ultim) do

if (L.tab[k] = e)

then L.ultim L.ultim-1

for i k to L.ultim do

L.tab[i] L.tab[i+1]

end

3.1.4 Exercitii

Exercitiul 3.1.1. Sa se proiecteze o structura de date de tip lista liniara pentru reprezentarea poli-noamelor rare cu o singura variabila si cu coecienti ntregi (polinoame de grade mari cu multi coecientiegali cu zero). Sa se scrie proceduri care, utilizand aceasta structura, realizeaza operatiile algebrice cupolinoame si operatiile de citire si scriere de polinoame.

Exercitiul 3.1.2. Acelasi lucru ca la problema 3.1.1 dar considerand polinoame cu trei variabile.

Exercitiul 3.1.3. Sa se proiecteze o structura de date de tip lista liniara pentru reprezentarea ntregilormari ntr-o baza b. Sa se scrie proceduri care realizeaza operatii aritmetice cu ntregi reprezentati astfel.

Exercitiul 3.1.4. Fie A un alfabet. Daca w = a1 : : : an este un sir din A atunci prin w notam oglinditullui w, w = an : : : a1. Presupunem ca sirurile din A sunt reprezentate prin liste liniare simplu nlantuite.Sa se scrie subprograme care sa realizeze:

dat un sir w determina oglinditul sau w;

dat un sir w decide daca w este de forma uu.

date doua siruri w si w0, decide daca w w0 (se considera ordonarea lexicograca).

Exercitiul 3.1.5. Sa se proiecteze o structura de date de tip lista liniara pentru reprezentarea multi-milor nite de numere complexe. Sa se scrie proceduri care sa realizeze operatii cu multimi de numerecomplexe reprezentate astfel.

Exercitiul 3.1.6. Sa se scrie un program care sa creeze o lista liniara ordonata crescator cu toatenumerele de forma 2i 3j 5k (i; j; k ntregi pozitivi) mai mici dect un n dat. (In legatura cu problemalui Hamming [Luc93].)

Exercitiul 3.1.7. Sa se proiecteze o structura de date de tip lista liniara pentru reprezentarea numerelorrationale mari si cu multe zecimale. Sa se scrie proceduri care sa realizeze operatii aritmetice cu numererationale reprezentate astfel.

Exercitiul 3.1.8. Se considera siruri peste un alfabet A reprezentate prin liste liniare. Sa se scrie unsubprogram care avand la intrare doua siruri x = x1 : : : xm si y = y1 : : : ym, xi; yi 2 A, construieste sirulm(x; y) = x1y1 : : : xmym. Sa se deneasca o operatie asemanatoare cand x si y au lungimi diferite si sase scrie subprogramul care realizeaza aceasta noua operatie.

Page 28: algoritmi_tehnici_dorel lucanu - carte

3.2. LISTA LINIARA ORDONATA 31

3.2 Lista liniara ordonata

3.2.1 Tipul de date abstract LLINORD

3.2.1.1 Descrierea obiectelor de tip data

O lista liniara ordonata este o lista liniara (e0; : : : ; en1) n care elementele ei apartin unei multimi totalordonate date Elt si sunt ordonate crescator: e0 < < en1.

3.2.1.2 Operatii

Operatiile ListaVida, EsteVida, Lung, Egal, Copie, Parcurge si Poz sunt aceleasi ca la lista liniara.

Insereaza. Adauga un element dat ntr-o lista liniara ordonata astfel ncat dupa inserare lista ramneordonata crescator.

Intrare: o lista liniara ordonata L = (e0 < < en1) si un element e din Elt;

Iesire: L = (e0 < < ek1 < e < ek < < en1).

Elimina. Elimina un element dat dintr-o lista liniara ordonata data.

Intrare: o lista liniara ordonata L = (e0 < < en1) si un element e din Elt;

Iesire: L = (e0 < < ek1 < ek+1 < < en1) daca e apare n l pe locul k (e = ek), lista L neschimbata daca e nu apare n L.

3.2.2 Implementarea dinamica cu liste simplu nlantuite

3.2.2.1 Reprezentarea obiectelor de tip data

Similara cu cea a listelor liniare.

3.2.2.2 Implementarea operatiilor

Operatiile ListaVida, EsteVida, Lung, Egal, Copie si Parcurge au aceleasi implementari ca cele de la listaliniara.

Poz. Algoritmul de cautare secventiala poate mbunatatit n sensul urmator: daca s-a ntalnit unelement ek > x atunci toate elementele care urmeaza sunt mai mari dect x si procesul de cautare setermina fara succes (ntoarce valoarea -1). Complexitatea timp n cazul cel mai nefavorabil ramane O(n).

function poz(L, x)

begin

p L.prim

while (p 6= NULL) do

if (p->elt = x) then return p

if (p->elt > x) then return NULL

p p->succ

return NULL

end

Insereaza. Se disting urmatoarele cazuri:

1. Lista L este vida. Se creeaza un nod n care va memorat e. Pointerii L.prim si L.ultim vor referin continuare acest nod.

2. e < L:prim->elt. Se adauga un nod la nceputul listei si se memoreaza e n acest nod. PointerulL.prim va referi n continuare acest nod.

Page 29: algoritmi_tehnici_dorel lucanu - carte

32 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

3. e > L:ultim->elt. Se adauga un nod la sfrsitul listei si se memoreaza e n acest nod. PointerulL.ultim va referi n continuare acest nod.

4. L:prim->elt e L:ultim->elt. Algoritmul de inserare are doua subetape:

4.1. Cauta pozitia pe care trebuie memorat e. Daca n timpul cautarii este ntlnit un ek = e atunciprocesul de inserare se termina fara a modica lista.

4.2. Daca procesul de cautare s-a terminat pe prima pozitie k astfel ncat e > ek, atunci insereazaun nod n fata celui pe care s-a terminat procesul de cautare (acesta memoreaza cel mai micelement mai mare dect e) si memoreaza e n acest nou nod.

Complexitatea timp n cazul cel mai nefavorabil a algoritmului este O(n).

procedure insereaza(L, e)

begin

new(q)

q->elt e

if (L.prim = NULL) then /* cazul 1 */

q->succ NULL

L.prim q

L.ultim q

else if (e < L.prim->elt) then /* cazul 2 */

q->succ L.prim

L.prim q

else if (e > L.ultim->elt) then /* cazul 3 */

q->succ NULL

L.ultim->succ q

L.ultim q

else p L.prim /* cazul 4 */

while (p->elt < e) do

p p->succ

if (p->elt 6= e) /* subcazul 4.2 */

then q->succ p->succ

p->succ q

q->elt p->elt

p->elt e

else delete(q)

end

Elimina. Cauta nodul care memoreaza e ca la implementarea operatiei Poz. In timpul procesului deparcurgere si cautare se memoreaza ntr-o variabila pointer adresa nodului ce precede nodul curent(predecesorul). Daca a fost gasit un astfel de nod (e apare n lista), atunci l elimina. Daca e apare peprima sau ultima pozitie, atunci trebui actualizati pointerii L.prim si respectiv L.ultim. Complexitateatimp n cazul cel mai nefavorabil a algoritmului este O(n).

procedure elimina(L, e)

begin

if (L.prim = NULL) then throw 'eroare'

p L.prim

if (p->elt = e)

then L.prim p->succ

delete(p)

else while ((p 6= NULL) and (p->elt 6= e)) do

predp p

p p->succ

if (p 6= NULL)

then predp->succ p->succ

Page 30: algoritmi_tehnici_dorel lucanu - carte

3.2. LISTA LINIARA ORDONATA 33

if (p = L.ultim) then L.ultim predp

delete(p)

end

3.2.3 Implementarea statica cu tablouri

3.2.3.1 Reprezentarea obiectelor de tip data

Similara cu cea a listelor liniare.

3.2.3.2 Implementarea operatiilor

Operatiile ListaVida, EsteVida, Lung, Egal, Copie si Parcurge au aceleasi implementari ca cele de la listaliniara.

Poz. (Cautarea binara). Accesul direct la componentele listei si ordonarea crescatoare a acestorapermite o metoda de cautare foarte ecienta, cunoscuta sub numele de cautare binara. Descrierea metodeiare un caracter recursiv. Generalizam presupunand ca procesul de cautare a lui x se face cercetandcomponentele de la pozitia p la pozitia q. Cautarea n lista L corespunde cazului particular p = 0 siq = lung(L) 1. Exista urmatoarele cazuri:

1. p > q. Subtabloul n care se cauta este vid.

2. p q. Se determina pozitia de la (cea mai apropiata de) mijlocul subtabloului:

m

p+ q

2

2.1 x = L:tab[m]. Cautarea se termina cu suces: Poz m.

2.2 x < L:tab[m]. Deoarece toate elementele a ate la dreapta lui m sunnt mai mari dect x rezultaca singurul loc unde avem sanse sa-l gasim pe x este la stnga lui m. Se modica limita dreaptaa subtabloului n care se cauta, q m 1, si se reia procesul de cautare.

2.3 x > L:tab[m]. Deoarece toate elementele a ate la stanga lui m sunt mai mici dect x rezulta casingurul loc unde avem sanse sa-l gasim pe x este la dreapta lui m. Se modica limita stangaa subtabloului n care se cauta, p m+ 1, si se reia procesul de cautare.

Complexitatea timp n cazul cel mai nefavorabil a algoritmului este O(log2 n). Demonstratia acestuirezultat este prezentata n sectiunea 5.2.

function poz(L, x)

begin

p 0

q L.ultim

m hp+ q2

iwhile ((x 6= L.tab[m]) and (p < q)) do

if (x < L.tab[m])

then q m-1

else p m+1

m hp+ q2

iif (x = L.tab[m])

then return m

else return 0

end

Page 31: algoritmi_tehnici_dorel lucanu - carte

34 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Insereaza. Se realizeaza n doi pasi:

1 Se cauta binar pozitia k unde urmeaza a memorat e.

2. Se translateaza la dreapta toate elementele de la pozitia k la pozitia L:ultim si se memoreaza e pepozitia k.

Daca n timpul cautarii este ntlnita o componenta ce contine e (e este deja n lista) atunci operatiase termina fara a modica lista. Etapa de cautare necesita O(log2 n) timp n cazul cel mai nefavorabil,dar operatia de translatare necesita O(n). Astfel ca algoritmul care realizeaza operatia de inserare arecomplexitatea timp n cazul cel mai nefavorabil O(n).

procedure insereaza(L, e)

begin

p 0

q L.ultim

k hp+ q2

iwhile ((e 6= L.tab[k]) and (p < q)) do

if (e < L.tab[k])

then q k-1

else p k+1

k hp+ q2

iif (e 6= L.tab[k])

then if (e > L.tab[k]) then k k+1

if (L.ultim = MAX) then throw 'memorie insuficienta'

L.ultim L.ultim+1

for i L.ultim downto k

L.tab[i] L.tab[i-1]

L.tab[k] e

end

Elimina. Se realizeaza n doi pasi:

1 Se cauta binar, apeland Poz, pozitia k unde este memorat e. Daca Poz ntoarce zero atunci e nuapare n lista si operatia se termina fara a modica lista.

2. Se translateaza la stnga toate elementele de la pozitia k + 1 la pozitia L:ultim. Ca si n cazulinserarii, algoritmul care realizeaza operatia de eliminare are complexitatea timp n cazul cel mainefavorabil O(n).

procedure elimina(L, e)

begin

p 1

q L.ultim

k hp+ q2

iwhile ((e 6= L.tab[k]) and (p < q)) do

if (e < L.tab[k])

then q k-1

else p k+1

k hp+ q2

iif (e = L.tab[k])

L.ultim L.ultim-1

for i k to L.ultim

L.tab[i] L.tab[i+1]

end

Page 32: algoritmi_tehnici_dorel lucanu - carte

3.3. STIVA 35

3.3 Stiva

3.3.1 Tipul de date abstract STIVA

3.3.1.1 Descrierea obiectelor de tip data

Stivele sunt liste cu proprietatea ca se cunoaste \vechimea" ecarui element n lista, i.e., se cunoasteordinea introducerii elementelor n lista. La orice moment, ultimul element introdus n lista este primulcandidat la operatiile de citire si eliminare. Din acest motiv se mai numesc si liste LIFO (Last In, FirstOut). Presupunem ca elementele unei stive apartin tipului abstract Elt.

3.3.1.2 Operatii

StivaVida. Intoarce stiva vida.

Intrare: nimic;

Iesire: stiva fara nici un element.

EsteVida. Testeaza daca o stiva este vida.

Intrare: o stiva S;

Iesire: true daca S este stiva vida, false n caz contrar.

Push. Scrie un element n stiva.

Intrare: o stiva S si un element e din Elt;

Iesire: stiva S la care s-a adaugat e. Elementul e este ultimul introdus si va primul candidat laoperatiile de citire si eliminare.

Pop. Elimina ultimul element introdus n stiva.

Intrare: o stiva S;

Iesire: stiva S din care s-a eliminat ultimul element introdus daca S nu este vida, stiva vida daca S este stiva vida.

Top. Citeste ultimul element introdus ntr-o stiva.

Intrare: o stiva S;

Iesire: ultimul element introdus n S daca S nu este stiva vida, un mesaj de eroare daca S este stiva vida.

Observatie: Tipul abstract STIVA poate privit ca un caz particular al tipului abstract LLIN n sensulca o stiva poate privita ca o lista liniara si ca operatiile stivei pot exprimate cu ajutorul celor de lalista liniara:

STIVA.Push(S; e) = LLIN.Insereaza(S; Lungime(S); e)STIVA.Top(S) = LLIN.Citeste(S; Lungime(S))STIVA.Pop(S) = LLIN.Elimina(S; Lungime(S))

Astfel, o stiva poate reprezentata printr-o secventa (e1; : : : ; en) unde en este elementul din varful stivei(cu vechimea cea mai mica). Ca o consecinta, obtinem urmatoarea interpretare pentru operatii:

StivaVida : 7! ()Push : ((e0; : : : ; en1); e) 7! (e0; : : : ; en1; e)Pop : (e0; : : : ; en1) 7! (e0; : : : ; en2)Pop : () 7! eroareTop : (e0; : : : ; en1) 7! en1

Top : () 7! eroare

sfobs

Page 33: algoritmi_tehnici_dorel lucanu - carte

36 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

3.3.2 Implementarea dinamica cu liste simplu nlantuite

3.3.2.1 Reprezentarea obiectelor de tip data

O stiva consta dintr-o pereche formata din o lista simplu nlantuita, care contine elementele memorate nstiva la un moment dat, si o variabila referinta care indica varful stivei, adica ultimul element introdus(g. 3.3).

Æ S - -

?

?

...

en1

en2

e0

?

Figura 3.3: Stiva modelata ca lista nlantuita

3.3.2.2 Implementarea operatiilor

StivaVida. Consta n crearea listei simplu nlantuite vide.

EsteVida. Testeaza daca varful S este egal cu NULL.

Push. Consta n adaugarea unui nod la nceputul listei si \mutarea" vrfului S la nodul adaugat. Im-plementarea operatiei necesita timpul O(1).

procedure push(S, e)

begin

new(q)

q->elt e

q->succ S

S q

end

Pop. Consta n eliminarea nodului referit de pointerul S si \mutarea" vrfului la urmatorul nod. Operatiaeste descrisa de o functie booleana care ntoarce true daca si numai daca stiva era nevida nainte deeliminare. Ca si implementarea operatiei Push, necesita timpul O(1).

procedure pop(S)

begin

if (S = NULL) then throw 'eroare'

q S

S S->succ

delete(q)

end

Top. Daca stiva nu este vida, furnizeaza informatia memorata n nodul referit de varful S.

function top(S)

begin

if (S = NULL) then throw 'eroare'

Page 34: algoritmi_tehnici_dorel lucanu - carte

3.3. STIVA 37

return S->elt

end

3.3.3 Implementarea statica cu tablouri

3.3.3.1 Reprezentarea obiectelor de tip data

O stiva S este o pereche formata dintr-un tablou S.tab, care memoreaza elementele stivei, si o variabilaindice (varful) S.varf care indica pozitia ultimului element introdus n stiva (g. 3.4).

S.varf en-1

e0 0

n-1

MAX-1

S.tab

Figura 3.4: Stiva modelata ca tablou

3.3.3.2 Implementarea operatiilor

StivaVida. Varful, care memoreaza atat adresa ultimului element introdus cat si numarul elementelorexistente n stiva, este pus pe zero.

EsteVida. Testeaza daca varful este zero.

Push. Incrementeaza varful si memoreaza noul element n tablou la noua adresa data de varf. Deoarecedimensiunea maxima a tabloului care memoreaza stiva este xa, este necesar sa se verice daca nu sedepaseste aceasta limita. Operatia este realizata n timpul O(1).

procedure push(S, e)

begin

if (S.varf = MAX) then throw 'memorie insuficienta'

S.varf S.varf+1

S.tab[S.varf] e

end

Pop. Daca varful este mai mare ca zero atunci l decrementeaza. Evident, realizarea operatiei se face ntimpul O(1).

procedure pop(S)

begin

if (S.varf = 0) then throw 'eroare'

S.varf S.varf-1

end

Page 35: algoritmi_tehnici_dorel lucanu - carte

38 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Top. Daca varful este mai mare ca zero atunci ntoarce elementul memorat n tablou la adresa data devarf.

function top(S)

begin

if (S.varf = 0) then throw 'eroare'

return S.tab[S.varf]

end

3.3.4 Exercitii

Exercitiul 3.3.1. [?] Se considera o masina compusa din trei memorii: o sectiune de intrare si o sectiunede iesire constand dintr-o secventa de n celule ecare (o celula poate memora un numar ntreg) si o stivacu memorie innita. Controlul nit al masinii este format dintr-un program construit cu urmatoareleinstructiuni:

Read - introduce valoarea din prima celula din sectiunea de intrare n stiva apoi deplaseaza continutulsectiunii de intrare astfel ncat continutul din celula k + 1 trece n celula k. Continutul din primacelula se pierde iar cel din ultima celula devine nedenit;

Write - deplaseaza continutul sectiunii de iesire astfel ncat continutul din celula k trece n celulak + 1. Continutul din ultima celula se pierde apoi, extrage un element din stiva si-l memoreaza nprima celula din sectiunea de iesire.

a) Presupunand ca sectiunea de intrare contine n valori distincte, sa se determine numarul an alpermutarilor ce pot obtinute n sectiunea de iesire.

b) Sa se scrie un program care listeaza toate programele masinilor ce realizeaza permutari.

3.4 Coada

3.4.1 Tipul de date abstract COADA

3.4.1.1 Descrierea obiectelor de tip data

Ca si stivele, cozile sunt liste cu proprietatea ca se cunoaste vechimea ecarui element n lista. La oricemoment, primul element introdus n lista este primul candidat la operatiile de citire si eliminare. Dinacest motiv se mai numesc si liste FIFO (First In, First Out). Presupunem ca elementele unei stiveapartin tipului abstract Elt.

3.4.1.2 Operatii

CoadaVida. Intoarce coada vida.

Intrare: nimic;

Iesire: coada fara nici un element.

EsteVida. Testeaza daca o coada este vida.

Intrare: o coada C;

Iesire: true daca C este coada vida, false n caz contrar.

Insereaza. Scrie un element n coada.

Intrare: o coada C si un element e din Elt;

Iesire: coada C la care s-a adaugat e. Elementul e este ultimul introdus si va ultimul candidatla operatiile de citire si eliminare.

Page 36: algoritmi_tehnici_dorel lucanu - carte

3.4. COADA 39

Elimina. Elimina primul element introdus n coada.

Intrare: o coada C;

Iesire: coada C din care s-a eliminat primul element introdus daca C nu este vida, coada vida daca C este coada vida.

Citeste. Citeste primul element introdus n coada.

Intrare: o coada C;

Iesire: primul element introdus n C daca C nu este coada vida, un mesaj de eroare daca C este coada vida.

Observatie: Ca si n cazul stivei, tipul abstract COADA poate privit ca un caz particular al tipuluiabstract LLIN n sensul ca o coada este privita ca o lista liniara si ca operatiile cozii pot exprimate cuajutorul celor de la lista liniara:

COADA.Insereaza(C; e) = LLIN.Insereaza(C; Lungime(C); e)COADA.Citeste(C) = LLIN.Citeste(C; 0)COADA.Elimina(C) = LLIN.Elimina(S; 0)

Astfel, o coada poate reprezentata printr-o secventa (e1; : : : ; en), unde e1 reprezinta capul cozii (ele-mentul cu vechimea cea mai mare) iar en este elementul de la sfarsitul cozii (cu vechimea cea mai mica).Utilizand reprezentarea prin secvente, operatiile se rescriu astfel:

CoadaVida : 7! ()Insereaza : h(e0; : : : ; en1); ei 7! (e0; : : : ; en1; e)Citeste : (e0; : : : ; en1) 7! e0Citeste : () 7! eroareElimina : (e0; : : : ; en1) 7! (e1; : : : ; en1

Elimina : () 7! eroare

sfobs

3.4.2 Implementarea dinamica cu liste simplu nlantuite

3.4.2.1 Reprezentarea obiectelor de tip data

O coada este formata dintr-o lista simplu nlantuita C, care contine elementele memorate la un momentdat n coada, o variabila referinta C.prim care face referire la nodul cu vechimea cea mai mare (candidatulla stergere si la interogare) si o variabila referinta C.ultim care face referire la ultimul nod introdus ncoada (nodul cu vechimea cea mai mica) (g. 3.5).

Æ

-

6

C:prim -

-

Æ

6

C:ultim -

Figura 3.5: Coada reprezentata ca lista simplu nlantuita

3.4.2.2 Implementarea operatiilor

CoadaVida. Creeaza lista simplu nlantuita vida.

EsteVida. Testeaza daca pointerul C.prim este egal cu NULL.

Page 37: algoritmi_tehnici_dorel lucanu - carte

40 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Citeste. Daca lista nu este vida, furnizeaza informatia din nodul cu vechimea cea mai mare (referit deC:prim).

function citeste(C)

begin

if (C.prim = NULL) then throw 'eroare'

return C.prim->elt

end

Insereaza. Adauga un nod dupa cel referit de C:ultim si \muta" referinta C:ultim la nodul nou introdus.In cazul cand s-a adaugat la coada vida, se actualizeaza si referinta C:prim.

procedure insereaza(C, e)

begin

new(q)

q->elt e

q->succ NULL

if (C.ultim 6= NULL)

then C.ultim->succ q

C.ultim q

else C.prim q

C.ultim q

end

Elimina. In cazul n care coada nu este vida, elimina nodul referit de C:prim (cel cu vechimea cea maimare) si \muta" referinta C:prim la nodul urmator. Daca lista avea un singur nod atunci dupa eliminareva deveni vida si cei doi pointeri vor actualizati corespunzator.

procedure elimina(C)

begin

if (C.prim = NULL) then throw 'eroare'

p C.prim

C.prim C.prim->succ

if (C.prim = NULL) then C.ultim NULL

delete(p)

end

3.4.3 Implementarea statica cu tablouri

3.4.3.1 Reprezentarea obiectelor de tip data

Elementele unei cozi sunt memorate ntr-un tablou. Pointerul C.prim, care acum este adresa n tablou,refera cel mai \vechi" element n coada iar pointerul C.ultim cel mai nou element n coada (g. 3.6).Pentru o mai buna utilizare a spatiului de memorie vom conveni ca, atunci cnd cel mai nou elementeste memorat pe pozitia ultima Max din tablou, urmatorul element sa e memorat pe prima pozitie dintablou, daca aceasta este libera (g. 3.6b). Aceasta conduce la utilizarea unei aritmetici modulare pentrupointerii C.prim si C.ultim. Mai ramane de rezolvat problema reprezentarii cozii vide. Aceasta devinefoarte simpla daca vom considera o variabila contor suplimentara C.nrElem care sa memoreze numarulelementelor din coada. In plus, pentru ca valoarea lui C.ultim poate dedusa din valorile C.prim siC.nrElem, utlizarea campului C.ultim devine acum optionala.

3.4.3.2 Implementarea operatiilor

CoadaVida. Variabila nr elem este pusa pe zero. Este convenabil ca pointerul C.ultim sa e facut egalcu MAX-1 iar C.prim sa e facut egal cu prima adresa din tablou.

EsteCoadaVida. Testeaza daca variabila C.nrElem este zero.

Page 38: algoritmi_tehnici_dorel lucanu - carte

3.4. COADA 41

MAX-1

C.ultimC.prim MAX-1

. . . . . .

a)

0

C.ultim

b)

C.prim

. . .

0

Figura 3.6: Reprezentarea cozii printr-un tablou

Citeste. Daca coada nu este vida, furnizeaza informatia de la adresa din tablou data de pointerul C:prim.

function citeste(C)

begin

if (C.nrElem = 0) then throw 'eroare'

return C.tab[C.prim]

end

Insereaza. Daca mai este loc n tablou, nr elem < Max, atunci incrementeaza C.ultim modulo MAX simemoreaza noul element e la noua adresa data de C.ultim. Variabila contor C.nrElem este incrementata.

procedure insereaza(C, e)

begin

if (C.nrElem = MAX) then throw 'memorie insuficienta'

C.ultim (C.ultim + 1) % MAX

C.tab[C.ultim] e

C.nrElem C.nrElem + 1

end

Elimina. In cazul n care coada nu este vida, incrementeaza pointerul C:prim modulo MAX si decre-menteaza variabila contor C.nrElem.

procedure pop(S)

begin

if (C.nrElem = 0) then throw 'eroare'

C.prim (C.prim + 1) % MAX

C.nrElem C.nrElem - 1

end

3.4.4 Exercitii

Exercitiul 3.4.1. O coada completa cu restrictie la intrare este o lista liniara abstracta cu proprietateaca elementele se pot insera numai la unul din capete iar stergerile/citirile se pot efectua la oricare dincapete.

(ii) Sa se implementeze aceasta structura cu ajutorul listelor nlantuite.

(iii) Sa se implementeze aceasta structura cu ajutorul tablourilor.

Exercitiul 3.4.2. O coada completa cu restrictie la iesire este o lista liniara abstracta cu proprietateaca elementele se pot insera la oricare din capete iar stergerile/citirile se pot efectua numai la unul dincapete.

(ii) Sa se implementeze aceasta structura cu ajutorul listelor nlantuite.

(iii) Sa se implementeze aceasta structura cu ajutorul tablourilor.

Exercitiul 3.4.3. O coada completa (\deque") este o lista liniara abstracta cu proprietatea ca elementelese pot insera, sterge si citi la ambele capete.

Page 39: algoritmi_tehnici_dorel lucanu - carte

42 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

(ii) Sa se implementeze aceasta structura cu ajutorul listelor nlantuite.

(iii) Sa se implementeze aceasta structura cu ajutorul tablourilor.

Exercitiul 3.4.4. Se considera un tablou unidimensional cu 10000 de componente. Sa se scrie subpro-grame care sa realizeze:

memorarea ecienta n tablou a doua stive;

memorarea n tablou a doua cozi. Se pot memora doua cozi la fel de ecient ca doua stive? Dacada atunci sa se arate cum, daca nu sa se argumenteze de ce.

3.5 Arbori binari

3.5.1 Tipul de date abstract ABIN

3.5.1.1 Descrierea obiectelor de tip data

Multimea arborilor binari peste Elt este denita recursiv astfel:

arborele vid [ ] este un arbore binar,

arborele t format dintr-un nod distinct, numit radacina, ce memoreaza un element e din Elt, si dindoi arbori binari t1 si t2, numiti subarborele stang si respectiv subarborele drept (ai radacinii), esteun arbore binar; notam acest arbore prin [e](t1; t2).

Convenim ca arborele cu un singur nod [e]([ ]; [ ]) sa mai e notat si prin notatia mai simpla [e]. Fie v unnod ntr-un arbore binar t si v1 si v2 radacinile subarborilor stang si respectiv drept ai nodului v. Atuncispunem ca v este nod tata pentru v1 si v2, v1 este ul stang al lui v iar v2 este ul drept al lui v. Un nodpentru care ambii subarbori sunt vizi este numit frunza. Totalitatea nodurilor frunza formeaza frontieraarborelui. Un drum ntr-un arbore este o succesiune de noduri v1; : : : ; vn astfel ncat vi este tatal lui vi+1

pentru i = 1; : : : ; n 1. Lungimea unui drum e1; : : : ; en este n 1. Dimensiunea unui arbore t este egalacu numarul de noduri din t. Inaltimea unui arbore t este lungimea celui mai lung drum de la radacinalui t la un nod frunza. Prin denitie, naltimea arborelui vid este 1.

Exemplu: Fie a; b; c; d; e; f; g; h; i noua elemente n Elt. Aplicand de mai multe ori partea a doua adenitiei obtinem succesiv urmatorii arbori binari: [a]([ ]; [d]), [b]([f ]; [i]), [g]([h]; [ ]), [e]([b]([f ]; [i]); [g]([h]; [ ])),[c]([a]([ ]; [d]); [e]([b]([f ]; [i]); [g]([h]; [ ]))). Ultimul arbore binar este reprezentat n g. 3.7. De exemplu, eeste tatal nodurilor b si g, b este ul stang al lui e iar g este ul drept al lui e. Inaltimea arborelui este 3

iar dimensiunea sa este 9. sfex

e

f i

c

a

b g

h

d

Figura 3.7: Exemplu de arbore binar

Page 40: algoritmi_tehnici_dorel lucanu - carte

3.5. ARBORI BINARI 43

3.5.1.2 Operatii

ArbBinVid.

Intrare: nimic;

Iesire: arborele binar vid.

EsteVid.

Intrare: un arbore binar t;

Iesire: true daca t este vid, false n caz contrar.

Dimensiune.

Intrare: un arbore binar t;

Iesire: dimensiunea lui t.

Inaltime.

Intrare: un arbore binar t;

Iesire: naltimea arborelui t.

Copie.

Intrare: un arbore binar t;

Iesire: o copie distincta a lui t.

Egal.

Intrare: doi arbori binari t1 si t2;

Iesire: true daca cei doi arbori sunt egali, i.e., elementul memorat n radacina lui t1 este egal cucel memorat de radacina lui t2 si subarborele stang al lui t1 este egal cu subarborele stangal lui t2 si subarborele drept al lui t1 este egal cu subarborele drept al lui t2. Doi arbori vizisunt egali prin denitie. Formal, t1 = t2 daca si numai daca:

t1 = [ ] = t2 sau

t1 = [a](t01; t00

1 ), t2 = [a](t02; t00

2 ) si t0

1 = t02, t00

1 = t002 .

false n caz contrar.

ParcurgePreordine.

Intrare: un arbore binar t si o procedura Viziteaza(adr nod);

Iesire: arborele t dar n care nodurile au fost procesate n ordinea data de parcurgerea preordinea lui t. Parcurgerea preordine a unui arbore t este obtinuta aplicand recursiv urmatorulproces:

viziteaza radacina;

viziteaza subarborele stang;

viziteaza subarborele drept.

De exemplu, parcurgerea preordine a arborelui din g. 3.7 produce lista: c; a; d; e; b; f; i; g; h.

Page 41: algoritmi_tehnici_dorel lucanu - carte

44 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

ParcurgeInordine.

Intrare: un arbore binar t si o procedura Viziteaza(adr nod);

Iesire: arborele t dar n care nodurile au fost procesate n ordinea data de parcurgerea inordine alui t. Parcurgerea inordine a unui arbore t este obtinuta aplicand recursiv urmatorul proces:

viziteaza subarborele stang;

viziteaza radacina;

viziteaza subarborele drept.

De exemplu, parcurgerea inordine a arborelui din g. 3.7 produce lista: a; d; c; f; b; i; e; h; g.

ParcurgePostordine.

Intrare: un arbore binar t si o procedura Viziteaza(adr nod);

Iesire: arborele t dar n care nodurile au fost procesate n ordinea data de parcurgerea postordinea lui t. Parcurgerea postordine a unui arbore t este obtinuta aplicand recursiv urmatorulproces:

viziteaza subarborele stang;

viziteaza subarborele drept;

viziteaza radacina.

De exemplu, parcurgerea postordine a arborelui din g. 3.7 produce lista: d; a; f; i; b; h; g; e; c.

ParcurgeBFS.

Intrare: un arbore binar t si o procedura Viziteaza(adr nod);

Iesire: arborele t dar n care nodurile au fost procesate n ordinea data de parcurgerea BFS a luit. Parcurgerea BFS (Breadth First Search) a unui arbore t consta n: vizitarea radacinii,apoi a ilor radacinii (nodurile a ate la distanta 1 fata de radacina), apoi a nodurilor a atela distanta 2 fata de radacina s.a.m.d. De exemplu, parcurgerea BFS a arborelui din g. 3.7produce lista: c; a; e; d; b; g; f; i; h.

3.5.2 Implementarea dinamica

3.5.2.1 Reprezentarea obiectelor de tip data

Fiecare nod al arborelui binar este reprezentat printr-o structura care, n forma sa cea mai simpla, aretrei campuri: un camp elt pentru memorarea informatiei din nod, un camp stg pentru memorareaadresei radacinii subarborelui stang si un camp drp pentru memorarea adresei radacinii subarboreluidrept. Accesul la ntreaga structura de date este realizat prin intermediul radacinii. Figura 3.8 includereprezentarea dinamica a arborelui binar din g. 3.7.

3.5.2.2 Implementarea operatiilor

ArbBinVid. Consta n crearea listei vide.

EsteVid. Testeaza daca radacina t face referire la vreun nod.

Page 42: algoritmi_tehnici_dorel lucanu - carte

3.5. ARBORI BINARI 45

h

t

c

a e

gd b

f i

Figura 3.8: Reprezentarea dinamica a arborelui binar

Dimensiune. Descrierea functiei care calculeaza dimensiunea unui arbore binar are un caracter recursiv:daca arborele este vid, atunci ntoarce 0; daca arborele nu este vid, atunci ntoarce suma dintre dimensi-unea subarborelui stang si dimensiunea subarborelui drept la care se adauga 1 (radacina). Complexitateatimp pentru cazul cel mai nefavorabil este O(n), unde n este chiar dimensiunea arborelui.

function dimens(t)

begin

if (t = NULL)

then return 0

else d1 dimens(t->stg)

d2 dimens(t->drp)

return d1 + d2 + 1

end

Inaltime. Functia care calculeaza naltimea are o descriere asemanatoare celei care calculeaza dimensi-unea. Complexitatea timp pentru cazul cel mai nefavorabil este O(n).

function inalt(t)

begin

if (t = NULL)

then return -1

else h1 inalt(t->stg)

h2 inalt(t->drp)

return max(h1, h2) + 1

end

Copie. Si aceasta functie are o descriere recursiva: se realizeaza o copie a radacinii dupa care se realizeazaprin apeluri recursive copii ale subarborilor radaciniii. Lantul apelurilor recursive se termina atunci candeste ntalnit subarborele vid. Complexitatea timp pentru cazul cel mai nefavorabil este O(n).

function copie(t)

begin

if (t = NULL)

then return NULL

else new(t copie)

t copie->elt t->elt

t copie->stg copie(t->stg)

t copie->drp copie(t->drp)

return t copie

end

Page 43: algoritmi_tehnici_dorel lucanu - carte

46 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Egal. Deoarece descrierea functiei egal este foarte simpla, omitem scrierea ei.

ParcurgePreordine. Cea mai simpla descriere este cea recursiva:

procedure preordine(t, viziteaza())

begin

if (t 6= NULL)

then viziteaza(t)

preordine(t->stg, viziteaza)

preordine(t->drp, viziteaza)

end

ParcurgeInordine. Similara parcurgerii preordine.

ParcurgePostordine. Similara parcurgerii preordine.

ParcurgeBFS. Pentru implementarea acestei operatii se utilizeaza o coada C cu urmatoarele proprietati:

1. initial coada contine numai radacina subarborelui;

2. la momentul curent se viziteaza nodul extras din C;

3. atunci cand un nod este vizitat, i acestuia sunt adaugati n C.

Complexitatea timp pentru cazul cel mai nefavorabil este O(n).

procedure parcurgeBFS(t, viziteaza())

begin

if (t 6= NULL)

then C coadaVida()

insereaza(C,t)

while not esteVida(C) do

v citeste(C)

elimina(C)

viziteaza(v)

if (t->stg 6= NULL) then insereaza(C, t->stg)

if (t->drp 6= NULL) then insereaza(C, t->drp)

end

3.5.3 Implementarea statica cu tablouri

Nodurile arborelui binar sunt memorate ntr-un tablou de structuri. Acum, valorile campurilor de legaturanu mai sunt adrese de variabile ci adrese n tablou. O reprezentare statica a arborelui din g. 3.7 estedata n g. 3.9. Valoarea -1 joaca rolul pointerului NULL. Descrierile operatiilor sunt asemanatoare cucele de la implementarea dinamica. Prezentam, ca exemplu, parcurgerea inordine:

procedure inordine(t, i, viziteaza())

begin

if (i 6= -1)

then inordine(t, t.tab[i].stg, viziteaza)

viziteaza(t, i)

inordine(t, t.tab[i].drp, viziteaza)

end

Page 44: algoritmi_tehnici_dorel lucanu - carte

3.5. ARBORI BINARI 47

t.rad

t.tab[i].eltt.tab[i].stgt.tab[i].drp

0 1 2 3 4 5 6 7 8 9 10 11 . . .

b c dea h g if-1

-1-1

867

15

02 -1

-1-14

-1-1 -1

-1

Figura 3.9: Reprezentarea statica a arborelui binar

3.5.4 Exercitii

Exercitiul 3.5.1. Sa se scrie proceduri care implementeaza operatiile pentru arborii binari reprezentaticu tablouri.

Exercitiul 3.5.2. Asociem varfurilor unui arbore binar adrese simbolice, ce sunt secvente de 0 si 1construite astfel: radacina are adresa simbolica 1; daca varful v are adresa simbolica atunci ul a atla stanga lui v are adresa simbolica 0 iar ul a at la dreapta are adresa 1.

a) Sa se scrie un program care, pentru un arbore dat, aseaza adresele simbolice ale tuturor varfurilorn preordine, inordine si postordine.

b) Sa se scrie un program care, avand la intrare adresele simbolice ale tuturor varfurilor, construiesteo lista nlantuita care reprezinta arborele.

Exercitiul 3.5.3. Sa se scrie un program care, avand la intrare listele liniare ale nodurilor unui arborebinar n preordine, respectiv n inordine, construieste lista nlantuita care reprezinta arborele. Mai esteposibil acelasi lucru daca se considera la intrare oricare alta pereche de liste (preordine si postordine sauinordine si postordine)?

Exercitiul 3.5.4. Fie t un arbore binar cu n noduri, v1; : : : ; vn lista nodurilor n preordine si vp1 ; : : : ; vpnlista nodurilor n inordine. Sa se arate ca permutarea p1; : : : ; pn se poate obtine cu o masina de la exercitiul3.3.1 si reciproc, orice permutare obtinuta cu o masina de la exercitiul 3.3.1 corespunde unui arbore binar.

Exercitiul 3.5.5. Peste arborii binari se deneste relatia astfel: t1 t2 daca si numai daca:

t1 = [ ], sau

t1 = [a1](t0

1; t00

1 ), t2 = [a2](t0

2; t00

2 ) si

a1 < a2 sau

a1 = a2 si t0

1 t02 sau

a1 = a2 si t0

1 = t02 si t00

1 t002 .

a) Sa se arate ca, pentru orice doi arbori t1 si t2, are loc t1 t2 sau t2 t1.

b) Sa se scrie un program care, avand la intrare doi arbori t1 si t2, decide daca t1 t2 sau t2 t1 saut1 = t2.

Exercitiul 3.5.6. Doi arbori binari t si t0 se numesc echivalenti daca:

(i) lista inordine a lui t este (u1; : : : ; un),

(ii) lista inordine a lui t0 este u01; : : : ; u0

n, si

(iii) informatia din ui si u0

i este aceeasi, pentru orice i = 1; : : : ; n.

Sa se scrie o procedura care testeaza daca doi arbori binari sunt echivalenti.

Page 45: algoritmi_tehnici_dorel lucanu - carte

48 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

Exercitiul 3.5.7. (Arbori binari nsailati la dreapta.) Presupunem ca structura unui nod cuprinde uncamp suplimentar tdrp cu urmatoarea semnicatie:

v->:tdrp = false semnica faptul ca v nu are succesor dreapta iar v->:drp va contine adresasuccesorului lui v din lista inordine. Un astfel de pointer se numeste nsailare.

v->:tdrp = true semnica faptul ca v are succesor dreapta.

In plus, se presupune ca primul nod este succesorul-inordine al ultimului nod din lista inordine. Un astfelde arbore se numeste nsailat la dreapta.

a) Sa se scrie un subprogram sucInord(p, t) care determina succesorul-inordine al unui nod arbitrarp n arborele t. Procedura va utiliza O(1) spatiu suplimentar. Care este complexitatea timp aalgoritmului descris de subprogram pentru cazul cel mai nefavorabil?

b) Este posibil sa se scrie o procedura sucInord pentru arborii binari nensailati la dreapta? Daca da,sa se arate cum, iar daca nu sa se spuna de ce.

c) Sa se descrie o procedura de parcurgere a arborilor binari nsailati la dreapta, utilizand procedurasucInord. Sa se arate ca algoritmul de parcurgere descris necesita O(n) timp (n este numarul denoduri din arbore).

Exercitiul 3.5.8. Se considera urmatoarea modicare a structurii de arbore binar:

zona de legaturi a ecarui nod contine doua cmpuri suplimentare: tstg si tdrp cu semnicatiile:

v->:tstg = true daca v are subarbore stanga,

v->:tstg = false daca v nu are subarbore stanga si n acest caz v->:lstg este adresa predece-sorului lui v n inordine,

v->:tdrp = true daca v are subarbore dreapta,

v->:tdrp = false daca v nu are subarbore dreapta si n acest caz v->:drp este adresa succe-sorului lui v n inordine.

Un asemenea arbore se numeste nsailat.

(i) Sa se scrie o procedura de parcurgere n inordine a arborilor nsailati.

(ii) Sa se scrie o procedura care copie un arbore binar obisnuit ntr-un arbore nsailat.

Exercitiul 3.5.9. Sa se scrie o procedura care sa numere nodurile de pe frontiera arbore binar.

Exercitiul 3.5.10. Se considera arbori binar care au ca informatie n noduri numere ntregi. Lungimeaexterna ponderata a arborelui t este

Pfv->inf lung(v) j v este nod pe frontiera lui tg, unde lung(v)

este lungimea drumului de la radacina la nodul v. Sa se scrie un subprogram care determina lungimeaexterna a unui astfel de arbore.

Exercitiul 3.5.11. (Reprezentarea expresiilor aritmetice) Consideram expresii formate numai din nu-mere ntregi si operatorii binari +; ; =; ; %. Unei expresii e i se poate asocia un arbore ninar a(e)astfel:

daca e este un numar ntreg atunci a(e) este format dintr-un singur nod [e]:

Æ ea(e) =

daca e = e1 op e2 atunci a(e) este arborele [](a(e1); a(e2)):

Page 46: algoritmi_tehnici_dorel lucanu - carte

3.5. ARBORI BINARI 49

Æ opa(e) =

a(e1) a(e2)

Radacina lui a(e) are eticheta \op", subarborele din stanga radacinii este a(e1) iar subarborele dindreapta radacinii este a(e2).

Sa se scrie un subprogram care are la intrare o lista liniara ce reprezinta o expresie si ofera la iesirearborele binar asociat expresiei. Arborele asociat este unic? Sa se justice cum rezolva programulproblema unicitatii.

Exercitiul 3.5.12. Asa cum am vazut n exercitiul 3.5.11, orice expresie aritmetica poate reprezentataprin arbori. Notatia postxata a unei expresii se obtine prin parcurgerea n postordine a arborelui. Deexemplu, expresia a=b2+bdac are urmatoarea forma postxata: a b 2 =b d+a c. Urmatorulalgoritm realizeaza conversia unei expresii din notatia inxata n notatia postxata (listele cu formeleinxate si respectiv inxate sunt reprezentate prin cozi):

S stivaVida()

while not esteVida(listaInfix) do

x citeste(listaInfix)

if (x este operand)then insereaza(listaPostfix, x)

else if (x = ')')

then while (top(S) 6= '(') do

y top(S)

pop(S)

insereaza(listaPostfix, y)

pop(S)

else while ((isp(top(S)) icp(x)) and not esteVida(S)) do

y top(S)

pop(S)

insereaza(listaPostfix, y)

push(S, x)

while (not esteVida(S)) do

x top(S)

pop(S)

insereaza(listaPostfix, x)

unde isp si icp sunt operatorii de prioritate (n stiva si respectiv n evaluarea expresiei) si sunt dati prinurmatorul tabel:

Simbol isp icp) ; =;% 2 2+;(binari) 1 1( 0 4

Sa se descrie executia algoritmului pentru expresia 12 + 45 2=6 23%5 3.

Exercitiul 3.5.13. Pentru notatia postxata exista un algoritm simplu de evaluare a expresiei. Acestalgoritm utilizeaza o stiva S si are urmatoarea descriere:

Page 47: algoritmi_tehnici_dorel lucanu - carte

50 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

S stivaVida()

while (not esteVida(listaPostfix) do

x citeste(listaPostfix)

if (x este operand)then push(S, x)

else y2 top(S)

pop(S)

y1 top(S)

pop(S)

push(S, y1 op(x) y2)

return top(S)

Sa se descrie executia algoritmului pentru forma postxata a expresiei 12 + 45 2=6 23%5 3.

3.6 Grafuri

3.6.1 Denitii

Prezentarea de aici se bazeaza pe cea din [Cro92]. Un graf este o pereche G = (V;E), unde V esteo multime ale carei elemente le numim varfuri, iar E este o multime de perechi neordonate fu; vg devarfuri, pe care le numim muchii. Aici consideram numai cazul cand V si E sunt nite. Daca e = fu; vgeste o muchie, atunci u si v se numesc extremitatile muchiei e; mai spunem ca e este incidenta n u si vsau ca varfurile u si v sunt adiacente (vecine). In general, muchiile si grafurile sunt reprezentate gracca n g. 3.10. Daca G contine muchii de forma fu; ug, atunci o asemenea muchie se numeste bucla,iar graful se numeste graf general sau pseudo-graf. Daca pot sa existe mai multe muchii fu; vg atunci Gse numeste multigraf. Denumirea provine de la faptul ca, n acest caz, E este o multi-multime. Douagrafuri G = (V;E); G0 = (V 0; E0) sunt izomorfe daca exista o functie f : V ! V 0 astfel ncat fu; vg estemuchie n G daca si numai daca ff(u); f(v)g este muchie n G0. Un graf G0 = (V 0; E0) este subgraf al luiG = (V;E) daca V V 0; E E0. Un subgraf partial G0 al lui G este un subgraf cu proprietatea V 0 = V .Daca G este un graf si X V o submultime de varfuri, atunci subgraful indus de X are ca multime devarfuri pe X si multimea de muchii formata din toate muchiile lui G incidente n varfuri din X .

c

c

Muchie

u

v

c

c c

c

1 2

34

Doua reprezentari ale aceluiasi graf

c c

c c

1 3

2 4

Figura 3.10: Reprezentarea grafurilor

Un mers de la u la v (de extremitati u si v) n graful G este o secventa

u = v0; fvo; v1g; v1; : : : ; fvn1; vng; vn = v

unde vi; 0 i n sunt varfuri, iar fvi1; vig; 1 i n sunt muchii. Uneori, un mers se pre-cizeaza numai prin muchiile sale sau numai prin varfurile sale. In exemplul din g. 3.10, secventa4; f4; 3g; 3; f3; 1g; 1; f1; 2g; 2; f2; 3g; 3; f3; 1g; 1 este un mers de la varful 4 la varful 1. Acest mers maieste notat prin f4; 3g; f3; 1g; f1; 2g; f2; 3g; f3; 1g sau prin 4; 3; 1; 2; 3; 1. Daca ntr-un mers toate muchiilesunt distincte, atunci el se numeste parcurs, iar daca toate varfurile sunt distincte, atunci el se numestedrum. Mersul din exemplul de mai sus nu este nici parcurs si nici drum. Un mers n care extremitatilecoincid se numeste nchis, sau ciclu. Daca ntr-un mers toate varfurile sunt distincte, cu exceptia ex-tremitatilor, se numeste circuit (drum nchis). Un graf G se numeste conex daca ntre oricare douavarfuri ale sale exista un drum. Un graf care nu este conex se numeste neconex. Orice graf se poate

Page 48: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 51

exprima ca ind reuniunea disjuncta de subgrafuri induse, conexe si maximale cu aceasta proprietate;aceste subgrafuri sunt numite componente conexe. De fapt, o componenta conexa este subgraful indusde o clasa de echivalenta, unde relatia de echivalenta este data prin: varfurile u si v sunt echivalentedaca si numai daca exista un drum de la u la v. Graful din g. 3.11 are doua componente conexe:G1 = (f1; 3; 4; 6g; ff1; 4g; f3; 6g; f4; 3g; f6; 3gg) si G2 = (f2; 5; 7g; ff2; 7g; ff5; 2g; ff7; 5gg).

5

G1 G2

1

34

6

2

7

Figura 3.11: Componente conexe

Un digraf este o pereche D = (V;A) unde V este o multime de varfuri iar A este o multime deperechi ordonate (u; v) de varfuri. Consideram cazul cand V si A sunt nite. Elementele multimii A senumesc arce. Daca a = (u; v) este un arc, atunci spunem ca u este extremitatea initiala (sursa) a luia si ca v este extremitatea nala (destinatia) lui a; mai spunem ca u este in predecesor imediat al luiv si ca v este un succesor imediat al lui u. Formulari echivalente: a este incident din u si incident n(spre) v, sau a este incident cu v spre interior si a este incident cu u spre exterior, sau a pleaca dinu si soseste n v. Arcele si digrafurile sunt reprezentate ca n g. 3.12. Orice digraf D deneste ungraf, numit graf suport al lui D, obtinut prin nlocuirea oricarui arc (u; v) cu muchia fu; vg (daca maimulte arce denesc aceeasi muchie, atunci se considera o singura muchie). Graful suport al digrafuluidin g. 3.12 este cel reprezentat n g. 3.10. Mersurile, parcursurile, drumurile, ciclurile si circuitele sedenesc ca n cazul grafurilor, dar considerand arce n loc de muchii. Un digraf se numeste tare conexdaca pentru orice doua varfuri u si v, exista un drum de la u la v si un drum de la v la u. Ca si ncazul grafurilor, orice digraf este reuniunea disjuncta de subgrafuri induse, tare conexe si maximale cuaceasta proprietate, pe care le numim componente tare conexe. O componenta tare conexa este subgrafulindus de o clasa de echivalenta, unde relatia de echivalenta de aceasta data invoca denitia de drumntr-un digraf. Digraful din g. 3.13 are trei componente tare conexe: G1 = (f1; 3g; f(1; 3); (3; 1)g),G2 = (f2g; ;), G3 = (f4; 5; 6g; f(4; 5); (5; 6); (6; 4)g). Un digraf D este conex daca graful suport al lui Deste conex.

c

c

Arc

u

v

c

c c

c

1 2

34

Digraf

>

-

?-3

ZZ

ZZ

ZZ

Figura 3.12: Reprezentarea digrafurilor

Un (di)graf etichetat pe varfuri este un (di)graf G = (V;E) mpreuna cu o multime de etichete Lsi o functie de etichetare ` : V ! L. In g. 3.14a este reprezentat un graf etichetat, n care functiade etichetare este `(1) = A; `(2) = B; `(3) = C. Un (di)graf etichetat pe muchii (arce) este un (di)grafG = (V;E) m preuna cu o multime de etichete L si o functie de etichetare ` : E ! L. In g. 3.14beste reprezentat un graf etichetat pe arce, n care functia de etichetare este `(f1; 2g) = A; `(f2; 3g) =B; `(f3; 1g) = C. Daca multimea de etichete este R (multimea numerelor reale) atunci (di)graful se mainumeste ponderat.

Page 49: algoritmi_tehnici_dorel lucanu - carte

52 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

e

e

e e e

-

9 R

1

23

4

e

w

5

6-

Figura 3.13: Componente tare conexe

n n

n3

21 A

C

B e e

e

1

2

3

A B

C

a) b)

Figura 3.14: Grafuri etichetate

Un arbore este un graf conex fara circuite. Un arbore cu radacina este un digraf conex, fara circuite,n care exista un varf r, numit radacina, cu proprietatea ca, pentru orice alt varf v, exista un drum dela r la v. Un arbore cu radacina si ordonat este un arbore cu radacina cu proprietatea ca orice varf u,exceptand radacina, are exact un predecesor imediat si, pentru orice varf, multimea succesorilor imediatieste total ordonata. Intr-un arbore cu radacina ordonat, succesorii imediati ai varfului u se numesc sii ai lui u, iar predecesorul imediat al lui u se numeste tatal lui u. Un caz particular de arbore ordonateste arborele binar, unde relatia de ordine peste multimea ilor varfului u este precizata prin (ul stang,ul drept). Exemple de arbori sunt date n g. 3.15.

0 1 2

0 2 1 0 1 2

Arbore Arbore cu radacina ordonat

Arbore binar

Figura 3.15: Exemple de arbori

3.6.2 Tipul de data abstract Graf

3.6.2.1 Descrierea obiectelor de tip data

Obiectele de tip data sunt grafuri G = (V;E), denite n mod unic pana la un izomorsm, unde multimeade varfuri V este o submultime nita a tipului abstract Varf, iar multimea de muchii E este o submultime

Page 50: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 53

a tipului abstract Muchie. Fara sa restrangem generalitatea, presupunem ca multimile de varfuri V suntmultimi de forma f0; 1; : : : ; n 1g, unde n = #V , iar multimile de muchii sunt submultimi ale multimiiffi; jg j i; j 2 f0; 1; : : : ; n1gg. Daca G = (V;E) este oarecare cu #V = n, atunci putem deni o functiebijectiva indexG : V ! f0; 1; : : : ; n1g si graful G0 = (f0; 1; : : : ; n1g; E0) cu findexG(u); indexG(v)g 2E0 () fu; vg 2 E. Evident, G si G0 sunt izomorfe si deci putem lucra cu G0 n loc de G. Intoarcereade la G0 la G se poate face via functia inversa lui indexG, numeG : f0; 1; : : : ; n 1g ! V data prinnumeG(i) = v () indexG(v) = i.

3.6.2.2 Operatii

GrafVid.

Intrare: nimic;

Iesire: graful vid G = (;; ;).

EsteGrafVid.

Intrare: un graf G = (V;E);

Iesire: true daca G este vid, false n caz contrar..

InsereazaVarf.

Intrare: un graf G = (V;E) cu V = f0; 1; : : : ; n 1g;

Iesire: graful G la care se adauga varful n ca varf izolat (nu exista muchii incidente n n).

InsereazaMuchie.

Intrare: un graf G = (V;E) si doua varfuri i; j 2 V ;

Iesire: graful G la care se adauga muchia fi; jg.

StergeVarf.

Intrare: un graf G = (V;E) si un varf k 2 V ;

Iesire: graful G din care au fost eliminate toate muchiile incidente n k (au o extremitate n k)iar vrfurile i > k sunt redenumite ca ind i 1.

StergeMuchie.

Intrare: un graf G = (V;E) si doua varfuri i; j 2 V ;

Iesire: graful G din care a fost eliminata muchia fi; jg.

ListaDeAdiacenta.

Intrare: un graf G = (V;E) si un varf i 2 V ;

Iesire: multimea varfurilor adiacente cu varful i.

ListaVarfurilorAccesibile.

Intrare: un graf G = (V;E) si un varf i 2 V ;

Iesire: multimea varfurilor accesibile din varful i. Un varf j este accesibil din i daca si numaidaca exista un drum de la i la j.

Page 51: algoritmi_tehnici_dorel lucanu - carte

54 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

3.6.3 Tipul de data abstract Digraf

3.6.3.1 Descrierea obiectelor de tip data

Obiectele de tip data sunt digrafuri D = (V;A), unde multimea de varfuri V o consideram de formaf0; 1; : : : ; n 1g, iar multimea de arce este o submultime a produsului cartezian V V . Tipul Varf areaceeasi semnicatie ca n cazul modelului constructiv Graf, iar tipul Arc este produsul cartezian VarfVarf.

3.6.3.2 Operatii

DigrafVid.

Intrare: nimic;

Iesire: digraful vid D = (;; ;).

EsteDigrafVid.

Intrare: un digraf D = (V;A);

Iesire: true daca D este vid, false n caz contrar..

InsereazaVarf.

Intrare: un digraf D = (V;A) cu V = f0; 1; : : : ; n 1g;

Iesire: digraful D la care s-a adaugat varful n.

InsereazaArc.

Intrare: un digraf D = (V;A) si doua varfuri i; j 2 V ;

Iesire: digraful D la care s-a adaugat arcul (i; j).

StergeVarf.

Intrare: un digraf D = (V;A) si un varf k 2 V ;

Iesire: digraful D din care au fost eliminate toate arcele incidente n k (au o extremitate n k) iarvrfurile i > k sunt redenumite ca ind i 1.

StergeArc.

Intrare: un digraf D = (V;A) si doua varfuri i; j 2 V ;

Iesire: digraful D din care s-a eliminat arcul (i; j).

ListaDeAdiacentaInterioara.

Intrare: un digraf D = (V;A) si un varf i 2 V ;

Iesire: multimea surselor (varfurilor de plecare ale) arcelor care sosesc n varful i.

ListaDeAdiacentaExterioara.

Intrare: un digraf D = (V;A) si un varf i 2 V ;

Iesire: multimea destinatiilor (varfurilor de sosire ale) arcelor care pleaca din varful i.

ListaVarfurilorAccesibile.

Intrare: un graf D = (V;A) si un varf i 2 V ;

Iesire: multimea varfurilor accesibile din varful i. Un varf j este accesibil din i daca si numaidaca exista un drum de la i la j.

Page 52: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 55

3.6.4 Reprezentarea grafurilor ca digrafuri

Orice graf G = (V;E) 2 Graf poate reprezentat ca un digraf D = (V;A) 2 Digraf considerand pentruecare muchie fi; jg 2 E doua arce (i; j); (j; i) 2 A. Cu aceste reprezentari, operatiile tipului Graf pot exprimate cu ajutorul celor ale tipului Digraf. Astfel, inserarea/stergerea unei muchii este echivalenta cuinserarea/stergerea a doua arce, iar celelalte operatii coincid cu cele de la digrafuri. Aceasta reprezentarene va permite sa ne ocupam n continuare numai de implementari ale tipului abstract Digraf.

3.6.5 Implementarea cu matrice de adiacenta (incidenta)

3.6.5.1 Reprezentarea obiectelor de tip data

Digraful D este reprezentat printr-o structura cu trei campuri: D.n, numarul de varfuri, D.m, numarulde arce, si un tablou bidimensional D.a de dimensiune n n astfel ncat:

D:a[i; j] =

(0 ; (i; j) 62 A

1 ; (i; j) 2 A

pentru i; j = 0; : : : ; n1. Daca D este reprezentarea unui graf atunci matricea de adiacenta este simetrica:

D:a[i; j] = D:a[j; i] pentru orice i; j:

Observatie: In loc de valorile 0 si 1 se pot considera valorile booleene false si respectiv true. sfobs

3.6.5.2 Implementarea operatiilor

DigrafVid. Este reprezentat de orice variabila D cu D:n = 0 si D:m = 0.

esteDigrafVid. Se testeaza daca D.m si D.n sunt egale cu zero.

InsereazaVarf. Consta n adaugarea unei linii si a unei coloane la matricea de adiacenta.

procedure insereazaVarf(D)

begin

D.n D.n+1

for i 0 to D.n-1 do

D.a[i,n-1] 0

D.a[n-1,i] 0

end

InsereazaArc. Inserarea arcului (i; j) presupune numai actualizarea componentei D:a[i; j].

StergeVarf. Notam cu a valoarea matricei D:a nainte de stergerea varfului k si cu a0 valoarea de dupastergere. Au loc urmatoarele relatii (a se vedea si g. 3.16):

1. daca i; j < k atunci a0i;j = ai;j ;

2. daca i < k j atunci a0i;j = ai;j+1;

3. daca j < k i atunci a0i;j = ai+1;j ;

4. daca k i; j atunci a0i;j = ai+1;j+1.

Din aceste relatii deducem urmatorul algoritm:

Page 53: algoritmi_tehnici_dorel lucanu - carte

56 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

procedure stergeVarf(D, k)

begin

D.n D.n-1

for i 0 to D.n-1 do

for j 0 to D.n-1 do

if (i k and j k) then

D.a[i,j] D.a[i+1,j+1]

else if (i k) then

D.a[i,j] D.a[i+1,j]

else if (j k) then

D.a[i,j] D.a[i,j+1]

end

i; j<k

j<k<i

i<k<j

k<i; j

...

6

a) b)

k

k

Figura 3.16: Stergerea unui varf

StergeArc. Asemanator operatiei InsereazaArc.

ListaDeAdiacInt si ListaDeAdiacExt. Lista varfurilor destinatare ale arcelor care \pleaca" din i estereprezentata de linia i, iar lista varfurilor sursa ale arcelor care sosesc n i este reprezentata de coloanai. Daca D este reprezentarea unui graf atunci lista varfurilor adiacente se obtine numai prin consultarealiniei (sau numai a coloanei) i.

ListaVarfurilorAccesibile. Reamintim ca un varf j este accesibil n D din i daca exista n D un drum dela i la j. Daca i = j atunci evident j este accesibil din i (exista un drum de lungime zero). Daca i 6= jatunci exista drum de la i la j daca exista arc de la i la j, sau exista k astfel ncat exista drum de la i la ksi drum de la k la j. De fapt, cele de mai sus spun ca relatia \exista drum de la i la j", denita peste V ,este nchiderea re exiva si tranzitiva a relatiei \exista arc de la i la j". Ultima relatie este reprezentatade matricea de adiacenta, iar prima relatie se poate obtine din ultima prin urmatorul algoritm datoratlui Warshall (1962):

procedure detInchReflTranz(D, b)

begin

for i 0 to D.n-1 do

for j 0 to D.n-1 do

b[i,j] D.a[i,j]

if (i = j) then b[i,j] 1

for k 0 to D.n-1 do

for i 0 to D.n-1 do

if (b[i,k] = 1)

then for j 0 to D.n-1 do

if (b[k,j] = 1) then b[i,j] 1

end

Lista varfurilor accesibile din varful i este reprezentata acum de linia i a tabloului bidimensional b. Incontinuare vom arata ca subprogramul detInchReflTranz determina ntr-adevar nchiderea re exiva si

Page 54: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 57

tranzitiva. Se observa usor ca re exivitatea este rezolvata de primele doua instructiuni for care realizeazasi copierea D.a n b. In continuare ne ocupam de tranzitivitate. Fie i si j doua varfuri astfel ncat j esteaccesibil din i. Exista un k si un drum de la i la j cu varfuri intermediare din multimea X = f0; : : : ; kg.Vom arata ca dupa k iteratii avem b[i; j] = 1. Procedam prin inductie dupa #X . Daca X = ;, atuncib[i; j] = D:a[i; j] = 1. Presupunem #X > 0. Rezulta ca exista un drum de la i la k cu varfuri intermediaredin f0; : : : ; k 1g si un drum de la k la j cu varfuri intermediare tot din f0; : : : ; k 1g. Din ipotezainductiva rezulta ca dupa k 1 executii ale buclei for k ... avem b[i; k] = 1 si b[k; j] = 1. Dupa ceade-a k-a executie a buclei obtinem b[i; j] = 1, prin executia ramurii then a ultimei instructiuni if.

3.6.6 Implementarea cu liste de adiacenta dinamice

3.6.6.1 Reprezentarea obiectelor de tip data

Un digraf D este reprezentat printr-o structura asemanatoare cu cea de la matricele de adiacenta darunde matricea de adiacenta este nlocuita cu un tablou unidimensional de n liste liniare, implementateprin liste simplu nlantuite si notate cu D:a[i] pentru i = 0; : : : ; n 1, astfel ncat lista D:a[i] continevarfurile destinatare ale arcelor care pleaca din i (= lista de adiacenta exterioara).

Exemplu: Fie G graful reprezentat n g. 3.17a. Tabloul listelor de adiacenta corepunzatoare lui Geste reprezentat n g. 3.17b. Pentru digraful D din gura 3.18a, tabloul listelor de adiacenta nlantuite

este reprezentat n g. 3.18b. sfex

De multe ori este util ca, atunci cand peste multimea varfurilor este data o relatie de ordine, compo-nentele listelor de adiacenta sa respecte aceasta ordine.

g

g g

g \

\\\\\

0 1

2 3

0

1

2

3

-

-

-

-

-

-

-

1

2 3

1 3

1 2

?

a

a) b)

Figura 3.17: Graf reprezentat prin liste de adiacenta nlantuite

g

g g

g

0 1

2 3

0

1

2

3

-

-

-

-

1

2

3

1

?

a

-

-S

SSSSSo

a) b)

Figura 3.18: Digraf reprezentat prin liste de adiacenta nlantuite

Page 55: algoritmi_tehnici_dorel lucanu - carte

58 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

3.6.6.2 Implementarea operatiilor

DigrafVid. Similar celei de la implementarea cu matrice de adiacenta.

EsteDigrafVid. Similar celei de la implementarea cu matrice de adiacenta.

InsereazaVarf. Se incrementeaza D.n si se initializeaza D.a[n] cu lista vida:

D.n D.n+1

D.a[n-1] listaVida()

InsereazaArc. Adaugarea arcului (i; j) consta n inserarea unui nou nod n lista D.a[i] n care se mem-oreaza valoarea j:

insereaza(D.a[i], 0, j)

Complexitatea timp n cazul cel mai nefavorabil este O(1).

StergeVarf. Stergerea varfului i consta n eliminarea listei D.a[i] din tabloul D.a si parcurgerea tuturorlistelor pentru a elimina nodurile care memoreaza i si pentru a redenumi varfurile j > i cu j 1.

procedure stergeVarf(D, i)

begin

while (D.a[i].prim 6= NULL) do

p D.a[i].prim

D.a[i].prim p->succ

delete(p)

D.a[i].ultim NULL

for j 0 to D.n-1 do

elimina(D.a[j], i)

D.n D.n-1

for j i to D.n-1 do

D.a[j] D.a[i+1]

end

Complexitatea timp n cazul cel mai nefavorabil este O(m), unde m este numarul de arce din digraf(m n2).

StergeArc. Stergerea arcului (i; j) consta n eliminarea nodului care memoreaza valoarea j din listaD.a[i].

procedure stergeArc(D, i, j)

begin

elimina(D.a[i], j)

end

Complexitatea timp n cazul cel mai nefavorabil este O(n).

ListaDeAdiacentaInterioara. Determinarea listei de adiacenta interioara pentru varful i consta n se-lectarea acelor vrfuri j cu proprietatea ca i apare n lista D.a[j]. Presupunem ca lista de adiacentainterioara este reprezentata de o coada C:

procedure listaAdInt(D, i, C)

begin

C coadaVida()

for j 0 to D.n-1 do

p D.a[j].prim

Page 56: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 59

while (p 6= NULL) do

if (p->elt = i)

then insereaza(C, j)

p NULL

p p->succ

end

Complexitatea timp n cazul cel mai nefavorabil este O(m), unde m este numarul de arce din digraf(m n2).

ListaDeAdiacentaExterioara. Lista de adiacenta exterioara a varfului i este D.a[i].

ListaVarfurilorAccesibile. Notam cu i0 varful din (di)graful D pentru care se doreste sa se calculeze listavarfurilor accesibile. Algoritmul pe care-l propunem va impune un proces de vizitare succesiva a vecinilorimediati lui i0, apoi a vecinilor imediati ai acestora si asa mai departe. In timpul procesului de vizitarevor gestionate doua multimi:

S multimea varfurilor accesibile din i0 vizitate pana n acel moment,

SB o submultime de varfuri din S pentru care este posibil sa existe varfuri adiacente accesibiledin i0 nevizitate nca.

Vom utiliza, de asemenea, un tablou de pointyeri (p[i] j 0 i < n) cu care tinem evidenta primuluivarf nevizitat nca din ecare lista de adiacenta. Mai precis, daca p[i] 6= NULL si i 2 S atunci i 2 SB.Algoritmul consta n executia repetata a urmatorului proces:

se alege un varf i 2 SB,

daca primul element neprocesat nca din lista D:a[i] nu este n S atunci se adauga atat la S cat sila SB,

daca lista D:a[i] a fost parcursa complet, atunci elimina i din SB.

Descrierea schematica a algoritmului de explorare a unui digraf este:

procedure ExplorareGraf(D, i0, viziteaza(), S)

beginfor 0 to D.n-1 do

p[i] D.a[i].prim

S fi0g

SB fi0g

viziteaza(i0)

while (SB 6= ;) do

i citeste(SB)

if (p[i] = NULL)

then SB SB n fig

else j p[i]->elt

p[i] p[i]->succ

if j 62 Sthen viziteaza(j)

S S [ fjg

SB SB [ fjg

end

Teorema 3.1. Procedura ExplorareGraf determina varfurile accesibile din i0 n timpul O(max(n;m0)),unde m0 este numarul muchiilor accesibile din i0, si utilizand spatiul O(max(n;m)).

Demonstratie. Corectitudinea rezulta din faptul ca urmatoarea proprietate este invarianta:

Page 57: algoritmi_tehnici_dorel lucanu - carte

60 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

S contine o submultime de noduri accesibile din i0 vizitate deja, SB S si multimea varfuriloraccesibile din i0 nevizitate nca este inclusa n multimea varfurilor accesibile din SB.

Complexitatea timp O(max(n;m0)) rezulta n ipoteza ca operatiile asupra multimilor S si SB se realizeazan timpul O(1). Se observa imediat ca partea de initializare necesita O(n) timp iar bucla-while se repeta

de O(m0) ori. Complexitatea spatiu rezulta imediat din declaratii. sfdem

Functie de structura de date utilizata pentru gestionarea multimii SB, obtinem diferite strategii deexplorare a digrafurilor.

Explorarea DFS (Depth First Search). Se obtine din ExplorareGraf prin reprezentarea multimiiSB printr-o stiva. Presupunem ca multimea S este reprezentata prin vectorul sau caracteristic:

S[i] =

(1 ; daca i 2 S

0 ; altfel.

Inlocuim operatiile scrise n dreptunghiuri din procedura ExplorareGraf cu operatiile corespunzatoarestivei si obtinem procedura DFS care descrie strategia DFS:

procedure DFS(D, i0, viziteaza(), S)

beginfor i 0 to D.n-1 do

p[i] D.a[i].prim

S[i] 0

SB stivaVida()

push(SB, i0)

S[i0] 1

viziteaza(i0)

while (not esteStivaVida(SB)) do

i top(SB)

if (p[i] = NULL)

then pop(SB)

else j p[i]->elt

p[i] p[i]->succ

if S[j] = 0

then viziteaza(j)

S[j] 1

push(SB, j)

end

Notam faptul ca implementarea respecta cerinta ca operatiile peste multimile S si SB sa se execute ntimpul O(1).

Exemplu: Consideram digraful din g. 3.20. Presupunem i0 = 0. Calculul procedurii DFS estedescris n tabelul din g. 3.19. Descrierea pe scurt a acestui calcul este: se viziteaza varful 0, apoi primuldin lista varfului 0 adica 1, dupa care primul din lista lui 1 adica 2. Pentru ca 2 nu are varfuriadiacente spre exterior, se ntoarce la 1 si viziteaza al doilea din lista varfului 1 adica 4. Analog ca la2, pentru ca 4 nu are varfuri adiacente spre exterior se ntoarce la 1 si pentru ca lista lui 1 este epuizatase ntoarce la lista lui 0. Al doilea din lista lui 0 este 2, dar acesta a fost deja vizitat si deci nu mai esteluat n considerare. Urmatorul din lista lui 0 este varful 3 care nu a mai fost vizitat, dupa care se ia nconsiderare primul din lista lui 3 adica 1, dar acesta a mai fost vizitat. La fel si urmatorul din lista lui

3 4. Asadar lista ordonata data de explorarea DFS a varfurilor accesibile din 0 este: (0,1,2,4,3). sfex

Metodei i putem asocia un arbore, numit arbore partial DFS, n modul urmator: Notam cu Tmultimea arcelor (i; j) cu proprietatea ca j este vizitat prima data parcurgand acest arc. Pentru aobtine T este sucient sa nlocuim n procedura DFS apelul Viziteaza(j) cu o instructiune de forma\adauga (i; j) la T". Arborele partial DFS este S(D; i0) = (V0; T ), unde V0 este multimea varfurilor ac-cesibile din i0. Denitia este valabila si pentru cazul cand argumentul procedurii DFS este reprezentarea

Page 58: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 61

i j S SBf0g (0)

0 1 f0; 1g (0; 1)1 2 f0; 1; 2g (0; 1; 2)2 f0; 1; 2g (0; 1)1 4 f0; 1; 2; 4g (0; 1; 4)4 f0; 1; 2; 4g (0; 1)1 f0; 1; 2; 4g (0)0 2 f0; 1; 2; 3g (0)0 3 f0; 1; 2; 3; 4g (0; 3)3 1 f0; 1; 2; 3; 4g (0; 3)3 4 f0; 1; 2; 3; 4g (0; 3)3 f0; 1; 2; 3; 4g (0)0 f0; 1; 2; 3; 4g ( )

Figura 3.19: Un calcul al procedurii DFS

unui graf, doar cu precizarea ca se considera muchii n loc de arce. In g. 3.20a este reprezentat arborelepartial DFS pentru digraful din g. 3.20b si varful 0. Arborele partial DFS este util n multe aplicatii cenecesita parcurgeri de grafuri.

Explorarea BFS (Breadth First Search). Se obtine din ExplorareGraf prin reprezentarea multimiiSB printr-o coada.

Exercitiul 3.6.1. Sa se nlocuiasca operatiile scrise n dreptunghiuri din procedura ExplorareGraf cuoperatiile corespunzatoare cozii. Noua procedura se va numi BFS.

Exemplu: Consideram digraful din exemplul precedent. Presupunem de asemenea i0 = 1. Calcululprocedurii BFS este descris n tabelul din g. 3.21. Descrierea sumara a acestui calcul este: se viziteazavarful 0, apoi toate varfurile din lista lui 0, apoi toate cele nevizitate din lista lui 1, apoi cele nevizitate

din lista lui 2 si asa mai departe. Lista ordonata data de parcurgerea BFS este (0,1,2,3,4). sfex

Ca si n cazul parcurgerii DFS, metodei i se poate atasa un arbore, numit arbore partial BFS. In g.3.20c este reprezentat arborele partial BFS din exemplul de mai sus.

Sugeram cititorului sa testeze cele doua strategii pe mai multe exemple pentru a vedea clar care estediferenta dintre ordinile de parcurgere a varfurilor.

Exercitiul 3.6.2. Am vazut ca, n cazul reprezentarii digrafurilor prin matrice de adiacenta, liste deadiacenta exterioara sunt incluse n liniile matricei. Sa se rescrie subprogramele DFS si BFS pentru cazulcand digraful este reprezentat prin matricea de adiacenta.

3.6.7 Implementarea cu liste de adiacenta statice

Listele de adiacenta ale digrafuluiD = hV;Ai sunt reprezentate prin doua tablouri D.a[i], i = 0; : : : ; D:n,si D.s[j], j = 0; : : : ; D:m, care satisfac proprietatile:

D:a[i] este adresa j n tabloul D:s a primului element cu proprietatea hi; s[j]i 2 A;

varfurile destinatare ale arcelor care pleaca din i sunt memorate n componente consecutive din D:s;

D:a[0] = 0 si D:a[n] = D:m.

Exemplu: In g. 3.22 este dat un exemplu de digraf reprezentat prin liste de acest fel. Din varful 0pleaca trei arce cu destinatiile 1,2 si 3 - ce sunt memorate n primele trei componente ale tabloului D:s.Din varful 1 pleaca doua arce cu destinatiile 2 si 3 - ce sunt memorate n D:s[3] si D:s[4]. Din varful 2 nupleaca nici un arc si de aceea D:a[2] = D:a[3]. Din varful 3 pleaca un singur arc ce este memorat n D:s[5].Elementul D:a[4] are rolul de a marca locul unde se termina lista de adiacenta exterioara a varfului 3.

sfex

Page 59: algoritmi_tehnici_dorel lucanu - carte

62 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

0

1

3

4

1 - 2 3- -

2

1

-

-

4-

4-

3- 4-5

2

e e

e e

e

-

e=

?

k

?

~

->

0 1

2

3 4

5

e e

e

e

e/ R

/ ^

0

31

2 4

e

e e e

e

R

?

?

0

1 2 3

4

b) Arbore partial DFS c) Arbore partial BFS

a) Digraf

Figura 3.20: Explorarea unui digraf

Exercitiul 3.6.3. Sa se descrie implementarile operatiilor tipului Digraf pentru cazul cand digrafurilesunt reprezentate prin liste de adiacenta statice.

3.6.8 Exercitii

Exercitiul 3.6.4. Daca G este un graf atunci gradul (i) al unui varf i este egal cu numarul de varfuriadiacente cu i. Daca D este un digraf, atunci gradul extern (+(i)) al unui varf i este egal cu numarulde varfuri adiacente cu i spre exterior, iar gradul intern ((i)) este numarul de varfuri adiacente cu ispre interior.

Sa se scrie o procedura detGrad(D, tip, din,dout) care determina gradele varfurilor digrafului D(cazul cand tip = true) sau ale grafului reprezentat de D (cazul cand tip = false).

Exercitiul 3.6.5. O alegere de drumuri care unesc toate perechile de varfuri conectabile i; j ntr-undigraf poate memorata ntr-o matrice p cu semnicatia: p[i; j] este primul varf intermediar ntalnitdupa i pe drumul de la i la j.

1. Sa se modice subprogramul detInchReflTranz astfel ncat sa determine si o alegere de drumuricare unesc varfurile conectabile.

2. Sa se scrie un subprogram care, avand date matricea drumurilor si doua varfuri i; j, determina undrumul de la i la j.

Exercitiul 3.6.6. Un digraf D poate reprezentat si prin listele de adiacenta interioara, unde D:a[i]este lista varfurilor sursa ale arcelor care sosesc n i. Sa se scrie procedurile care implementeaza operatiiletipului Digraf pentru cazul cand digrafurile sunt reprezentate prin listele de adiacenta interioara.

Exercitiul 3.6.7. Sa se scrie o procedura Conex(D : TDigrafListAd) : Boolean care decide daca grafulreprezentat de D este conex sau nu.

Page 60: algoritmi_tehnici_dorel lucanu - carte

3.6. GRAFURI 63

i j S SBf0g (0)

0 1 f0; 1g (0; 1)0 2 f0; 1; 2g (0; 1; 2)0 3 f0; 1; 2; 3g (0; 1; 2; 3)0 f0; 1; 2; 3g (1; 2; 3)1 2 f0; 1; 2; 3g (1; 2; 3)1 4 f0; 1; 2; 3; 4g (1; 2; 3; 4)1 f0; 1; 2; 3; 4g (2; 3; 4)2 f0; 1; 2; 3; 4g (3; 4)3 1 f0; 1; 2; 3; 4g (3; 4)3 4 f0; 1; 2; 3; 4g (3; 4)3 f0; 1; 2; 3; 4g (4)4 f0; 1; 2; 3; 4g ( )

Figura 3.21: Un calcul al procedurii BFS

e

e

e

e

/

W

s

j

:

0

1

2

3

00

3

5

5

6

1

2

3

4

1

2

3

2

3

0

1

2

3

4

2 5

6

Æ

?

s

?-

-

--

-

Figura 3.22: Digraf reprezentat prin liste de adiacenta tablouri

Exercitiul 3.6.8. Sa se scrie o procedura Arbore(D : TDigrafListAd) : Boolean care decide daca grafulreprezentat de D este arbore sau nu.Indicatie. Se poate utiliza faptul ca un graf cu n varfuri este arbore daca si numai daca este conex si aren 1 muchii [Cro92].

Exercitiul 3.6.9. Sa se proiecteze o structura de date pentru reprezentarea componentelor conexe aleunui graf si sa se scrie o procedura care, avand la intrare reprezentarea unui graf, construieste compo-nentele conexe ale acestuia pe baza algoritmului prezentat n ??.

Exercitiul 3.6.10. Fie D = (V;A) un digraf cu n varfuri. Un varf i se numeste groapa (\sink") dacapentru orice alt varf j 6= i exista un arc (j; i) 2 A si nu exista arc de forma (i; j). Sa se scrie o functieGroapa(D, g) care decide daca digraful reprezentat de D are o groapa sau nu; daca da, atunci variabilag va memora o asemenea groapa. Algoritmul descris de program va avea complexitatea O(n). Pot maimulte gropi?

Exercitiul 3.6.11. Se considera un arbore G (graf conex fara circuite) cu muchiile colorate cu culoridintr-un alfabet A. Sa se scrie un program care, pentru un sir a 2 A dat, determina daca exista undrum n G etichetat cu a.

Exercitiul 3.6.12. Multimea grafurilor serie-paralel (G; s; t), unde G este un multigraf (graf cu muchiimultiple) iar s si t sunt varfuri n G numite sursa respectiv destinatie, este denita recursiv astfel:

Orice muchie G = fu; vg deneste doua grafuri serie-paralel: (G; u; v) si (G; v; u).

Page 61: algoritmi_tehnici_dorel lucanu - carte

64 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

s cs

s ss s s

s t

s1 = s2 t1 = t2s1s1 = t1

t2

arc

compunere serie compunere paralela

G1 G2

G1

G2

Figura 3.23: Grafuri serie-paralel

Daca (G1; s1; t1) si (G2; s2; t2) sunt doua grafuri serie-paralel atunci:

compunerea serie G1G2 = (G; s1; t2), obtinuta prin reuniunea disjuncta a grafurilor G1 si G2

n care varfurile s2 si t1 sunt identicate, este graf serie-paralel;

compunerea paralela G1kG2 = (G; s1 = s2; t1 = t2), obtinuta prin reuniunea disjuncta agrafurilor G1 si G2 n care sursele s1 si s2 si respectiv destinatiile t1 si t2 sunt identicate, estegraf serie-paralel.

Denitia este sugerata grac n g. 3.23.Sa se scrie un program care decide daca un graf dat este serie-paralel.

Exercitiul 3.6.13. Sa se scrie un program care, pentru un graf G = (V;E) si i0 2 V date, enumaratoate drumurile maximale care pleaca din i0.

Exercitiul 3.6.14. Se considera problema din exercitiul 3.6.13. Presupunem ca muchiile grafului G suntetichetate cu numere ntregi. Sa se modice programul de la 3.6.13 astfel ncat drumurile sa e enumeraten ordine lexicograca.

3.7 \Heap"-uri

3.7.1 Tipul de date abstract \coada cu prioritati"

3.7.1.1 Obiectele de tip data

O coada cu prioritati este o structura de date n care elementele sunt numite atomi iar ecare atomcontine un camp-cheie care ia valori dintr-o multime total ordonata. Valoarea acestui camp-cheie senumeste prioritate. Operatiile de citerie/eliminare se refra ntotdeauna la atomul cu prioritatea cea maimare. Interpretarea notiunii de prioritate poate diferi de la caz la caz. Exista situatii cand atomii ceimai prioritari sunt cei cu cheile valorilor mai mici si exista situatii cand atomii cei mai prioritari sunt ceicu cheile valorilor mai mari. Noi consideram aici ultimul caz.

3.7.1.2 Operatii

CoadaVida.

Intrare: nimic;

Iesire: coada cu prioritati vida.

Elimina.

Intrare: o coada cu prioritati Q;

Iesire: Q din care s-a eliminat atomul cu cheia cea mai mare.

Page 62: algoritmi_tehnici_dorel lucanu - carte

3.7. \HEAP"-URI 65

4

1

3 4

2

0

a) b)

7

17 5

23

100

1 2

3

Figura 3.24: Arbore binar complet

Insereaza.

Intrare: o coada cu prioritati Q si un atom a;

Iesire: Q la care s-a adaugat a.

Citeste.

Intrare: o coada cu prioritati Q;

Iesire: atomul cu cheia cea mai mare din coada Q.

3.7.2 Implementarea cu max-"heap"-uri

3.7.2.1 Descrierea max-"heap"-urilor

Denitia 3.1. Un max-"heap" este un arbore binar complet cu proprietatile:

1. informatiile din noduri sunt valori dintr-o multime total ordonata numite chei;

2. pentru orice nod intern v, cheia memorata n v este mai mare decat sau egala cu cheia oricaruiadintre i.

In continuare aratam cum max-"heap" sunt reprezentate prin tablouri 1-dimensionale.

Denitia 3.2. Pentru un n 2 N, arborele binar complet atasat lui n este denit prin

Hn = (f0; : : : ; n 1g; E)

unde E = f(hi 12

i; i) j i = 1; : : : ; n 1g.

Exemplu: Pentru n = 5 arborele H5 este reprezentat n g. 3.24a. sfex

Lema 3.1. Au loc urmatoarele proprietati ale arborelui Hn:

1. Varful i are succesorii 2i+ 1 si 2i+ 2.

2. Varful i are ca varf-tata pehi 12

i, daca i 2.

3. Arborele are [log2 n] + 1 nivele.

4. Pe nivelul k se gasesc varfurile 2k 1; 2k; : : : ;minf2k+1 2; n 1g.1

Denitia 3.3. Fie a = (a0; : : : ; an1). Prin Hn(a) notam arborele obtinut din Hn prin etichetareavarfurilor i cu elementele ai n mod corespunzator.

1Aici nivelurile sunt numerotate ncepand cu 0; radacina este pe nivelul 0.

Page 63: algoritmi_tehnici_dorel lucanu - carte

66 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

b)

4321023 17 5 10 7a

10 7

17 5

23

a)

Figura 3.25: Exemplu de max-"heap"

Exemplu: Daca a = (10; 17; 5; 23; 7) atunci arborele H5(a) este reprezentat n g. 3.24b. sfex

Denitia 3.4. a) Tabloul (a[i] j i = 0; : : : ; n 1) are proprietatea MAX-HEAP daca (8k)(1 k < n)

ahk 12

i a[k]). Notam aceasta proprietate prin MAX-HEAP(a).

b) Tabloul a are proprietatea MAX-HEAP ncepand cu pozitia ` daca (8k)(` k 12 < k < n )

ahk 12

i a[k]). Notam aceasta proprietate prin MAX-HEAP(a; `).

Vom da cateva proprietati ale predicatelor MAX-HEAP(a) si MAX-HEAP(a; `).

Lema 3.2. 1. Tabloul (a[i] j i = 0; : : : ; n 1) are proprietatea MAX-HEAP (adica MAX-HEAP(a) =true) daca si numai daca pentru orice varf a[i] din Hn(a), a[i] este mai mare decat sau egal cu oricesuccesor a[j] al sau n Hn(a).

2. Pentru orice tablou (a[i] j i = 0; : : : ; n 1) are loc MAX-HEAP(a;hn2

i).

3. Daca MAX-HEAP(a; `), atunci pentru orice j > ` are loc MAX-HEAP(a; j).4. Daca MAX-HEAP(a) atunci a[0] este elementul maxim din tablou.5. Daca MAX-HEAP(a) atunci Hn(a) este un max-"heap".

In g. 3.25 este aratat un exemplu de max-"heap" si tabloul cu reprezentarea sa.

3.7.2.2 Implementarea operatiilor

CoadaVida. Este reprezentata de tabloul vid.

Elimina. Atomul cu cea mai mare cheie se a a n radacina max-"heap"-ului (prima pozitie n tablou).Stergerea acestuia lasa un loc liber n radacina n care copiem atomul de pe ultima pozitie din tablou.Dimensiunea max-"heap"-ului este decrementata cu 1. Refacerea proprietatii MAX-HEAP se realizeazaprin parcurgerea unui drum de la radacina spre frontiera conform urmatorului algoritm:

1. Se considera varful curent j. Initial avem j = 0.

2. Determina varful cu valoarea maxima dintre ii lui j. Fie acesta k.

3. Daca a[j] < a[k] atunci interschimba a[j] cu a[k].

4. Daca 2 j n atunci repeta pasii 2-4 cu varful curent j k.

Descrierea completa a algoritmului de eliminare este:

procedure elimina(a, n)

begin

a[0] a[n-1]

n n-1

j 0

esteHeap false

Page 64: algoritmi_tehnici_dorel lucanu - carte

3.7. \HEAP"-URI 67

7

b)

10

17 5

7

a)

10 7

17 5

c)

5

17

10

Figura 3.26: Eliminarea din max-"heap"-ul din g. 3.25

while ((2*j+1 n-1) and not esteHeap)

k 2*j+1

if ((k < n-1) and (a[k] < a[k+1])) then k k+1

if (a[j] < a[k])

then swap(a[j], a[k])

else esteHeap true

j k

end

Complexitatea timp n cazul cel mai nefavorabil este O(log2 n). In g. 3.26 este aratat modul n careeste eliminat atomul cu cheia cea mai mare din max-"heap"-ul din g. 3.25.

Insereaza. Daca max-"heap"-ul are n elemente, atunci se meoreaza noul atom pe pozitia n + 1 si seincrementeaza dimensiunea max-"heap"-ului. Apoi se reface proprietatea MAX-HEAP parcurgand undrum de la nodul ce memoreaza noul atom spre radacina, conform urmatorului algoritm:

1. Se considera varful curent j. Initial avem j = n 1.

2. Fie k pozitia nodului tata. Daca a[j] > a[k] atunci interschimba a[j] cu a[k].

3. Daca j > 1 atunci repeta pasii 2-3 cu varful curent j k.

Descrierea completa a algoritmului de inserare este:

procedure insereaza(a, n, o cheie)

begin

n n+1

a[n-1] o cheie

j n

esteHeap false

while ((j > 0) and not esteHeap)

k [j/2]

if(a[j] > a[k])

then swap(a[j], a[k])

else esteHeap true

j k

end

Complexitatea timp n cazul cel mai nefavorabil este O(log2 n). In g. 3.27 este aratata inserareaunui atom cu cheia egala cu 20 n max-"heap"-ul din g. 3.25.

Citeste. Intoarce primul element din tablou. Complexitatea timp n cazul cel mai nefavorabil este O(1).

Page 65: algoritmi_tehnici_dorel lucanu - carte

68 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

20

a)

10 7

17 5

23

20

b)

10 7

17

23

5

Figura 3.27: Inserarea cheii 20 n max-"heap"-ul din g. 3.25

1 parinte

parinte

a)

b)

3 5 8

4

9-10 1 3 4 5 7 8 92

2-1 -10 0 4 4 406

-10 1 3 4 5 7 8 92

2-1 -1-1 0 4 4 406

3 6

1 2

7 5 8

40

9

2

7

6

0

Figura 3.28: Structuri \union-nd"

3.8 \Union-nd"

Grafurile pot reprezenta colectii de multimi disjuncte ntr-un mod foarte natural: varfurile corespundobiectelor iar o muchie are semnicatia ca extremitatile sale sunt n aceeasi multime. Aceasta reprezentarepermite rezolvarea ecienta a multor probleme legate de multimi. De exemplu, a raspunde la ntrebarea\La ce multime apartine obiectul x" (operatia \nd") presupune de fapt a preciza la ce componenta conexaapartine varful x. Exista si un inconvenient al reprezentarii: aceeasi multime poate reprezentata prinmai multe grafuri conexe. De aceea, de exemplu, informatiile oferite de parcurgerile sistematice are outilitate mai redusa.

Un caz aparte se obtine cand se da un aspect dinamic problemei: la diferite momente, doua multimise pot reuni ntr-una singura (operatia \union"). Formularea unei cereri de acest tip este de forma:\reuneste multimea la care apartine i cu multimea la care apartine j". Aceasta operatie se poate realizafoarte simplu prin adaugarea unei muchii care sa uneasca un varf din componenta conexa corespunzatoareprimei multimi cu un varf din componenta corespunzatoare celei de-a doua multimi. Ramane de stabilitcare varfuri candideaza la momentul respectiv pentru unire printr-o muchie. Aceasta alegere va trebuisa permita construirea de algoritmi ecienti pentru ambele operatii: \union" si \nd". Avand n vedereca topologia componentelor conexe nu este importanta, vom alege structura de tip arbore cu radacinapentru reprezentarea unei multimi. Colectia de multimi este reprezentata de o colectie de arbori (opadure). Pentru reprezentarea unei paduri vom utiliza un tablou parinte cu semnicatia ca parinte[i]este predecesorul imediat (parintele) varfului i. Multimea univers, peste care se considera colectia demultimi, este aplicata prin functia index ntr-un interval de numere ntregi [0; n 1]. Astfel o colectieC va reprezentata de numarul ntreg n si tabloul parinte. Daca i este radacina unui arbore, atunciparinte[i] = 1. Un exemplu de colectie reprezentata astfel este aratat n g. 3.28a.

Numele unei multimi este dat de radacina arborelui ce o reprezinta. Crearea unei multimi cu unsingur element este banala:

Page 66: algoritmi_tehnici_dorel lucanu - carte

3.8. \UNION-FIND" 69

procedure singleton(C, i)

begin

C.parinte[i] -1

end

Determinarea multimii la care apartine i este echivalenta cu determinarea radacinii:

function find(C, i)

begin

temp i

while (C.parinte[temp] > 0) do

temp C.parinte[temp]

return temp

end

Reuniunea a doua multimi nseamna ducerea unui arc de la radacina unui arbore la radacina celuilalt:

procedure union(C, i, j)

begin

r1 find(i)

r2 find(j)

if (r1 6= r2) then C.parinte[r2] r1

end

Executand operatia union(C; 7; 8) pentru colectia din g. 3.28a obtinem structura din g. 3.28b.Prin executia repetata a operatiei \union" se pot obtine arbori dezechilibrati, n care determinarea

radacinii pentru anumite varfuri sa dureze mult. Structura ar putea mbunatatita daca s-ar puteamentine o forma cat mai aplatizata a rborilor, adica sa nu existe noduri a ate la distante mari deradacina. Aceasta se poate realiza prin memorarea n radacini a numarului de varfuri din arbore (greu-tatea arborelui). Aceasta va memorata cu semnul minus pentru a distinge radacinile de celelalte noduri.In g. 3.29 este reprezentata o asemenea structura. In plus, procedura union va realiza mai ntai o \apla-tizare" a arborilor si apoi duce un arc de la radacina arborelui cu greutatea mai mare la radacina celuicu greutatea mai mica.

union(C, i, j)

begin

r1 find(i)

r2 find(j)

while (C.parinte[i] > 0) do

temp i

i C.parinte[i]

C.parinte[temp] r1

while (C.parinte[j] > 0) do

temp j

j C.parinte[j]

C.parinte[temp] r2

if (C.parinte[r1] > C.parinte[r2]) then

C.parinte[r2] C.parinte[r1]+C.parinte[r2]

C.parinte[r1] r2

else if (C.parinte[r1] < C.parinte[r2]) then

C.parinte[r1] C.parinte[r1]+C.parinte[r2]

C.parinte[r2] r1

end

O solutie alternativa la cea de mai sus este sa memoram naltimea arborelui n loc de greutate.Operatia union va ancora arborele cu naltime mai mica de cel cu naltimea mai mare.

Tipul de date denit mai sus este cunoscut n literatura sub numele de structura \union-nd".

Page 67: algoritmi_tehnici_dorel lucanu - carte

70 CAPITOLUL 3. TIPURI DE DATE DE NIVEL INALT

63 5 8

4

92

7

6

0 1 parinte

-50 1 3 4 5 7 8 92

2-1 -40 0 4 4 40

Figura 3.29: Structura \union-nd" ponderata

Teorema 3.2. O secventa de m operatii singleton, union si find din care n sunt operatii singletonpoate realizata n timpul O(m log n) n cazul cel mai nefavorabil, unde log n este cel mai mic numar

natural k cu proprietatea log(k) n 1 si log(k) desemneaza functia log compusa cu ea nsasi de k ori:log(0) n = n, log(i+1) n = log log(i) n.

Demonstratia acestei teoreme poate gasita n [CLR93].

Page 68: algoritmi_tehnici_dorel lucanu - carte

Capitolul 4

Sortare interna

Alaturi de cautare, sortarea este una dintre problemele cele mai importante atat din punct de vederepractic cat si teoretic. Ca si cautarea, sortarea poate fi formulata ın diferite moduri. Cea mai generalaformulare si mai des utilizata este urmatoarea:

Fie data o secventa (v0, . . . , vn−1) cu componentele vi dintr-o multime total ordonata. Prob-lema sortarii consta ın determinarea unei permutari π astfel ıncat vπ(0) ≤ vπ(1) ≤ · · · ≤ vπ(n−1)

si ın rearanjarea elementelor din secventa ın ordinea data de permutare.

O alta formulare, echivalenta cu cea de mai sus, este urmatoarea:

Fie data o secventa de ınregistrari (R0, . . . , Rn−1), unde fiecare ınregistrare Ri are o valoarecheie Ki. Peste multimea cheilor Ki este definita o relatie de ordine totala. Problema sortariiconsta ın determinarea unei permutari π astfel ıncat Kπ(0) ≤ Kπ(1) ≤ · · · ≤ Kπ(n−1) si ınrearanjarea ınregistrarilor ın ordinea (Rπ(0), . . . , Rπ(n−1)).

Pentru ambele formulari presupunem ca secventa data este reprezentata printr-o lista liniara. Dacaaceasta lista este memorata ın memoria interna a calculatorului atunci avem sortare interna si daca segaseste ıntr-un fisier memorat pe un periferic atunci avem sortare externa. In acest capitol ne ocupamnumai de sortarea interna.

Vom simplifica formularea problemei presupunand ca secventa data este un tablou unidimensional.Acum problema sortarii se reformuleaza astfel:

Intrare: n si tabloul (a[i] | i = 0, . . . , n− 1) cu a[i] = vi, i = 0, . . . , n− 1.Iesire: tabloul a cu proprietatile: a[i] = wi pentru i = 0, . . . , n − 1, w0 ≤ · · · ≤ wn−1 si(w0, . . . , wn−1) este o permutare a secventei (v1, . . . , vn); convenim sa notam aceasta propri-etate prin (w0, . . . , wn−1) = Perm(v0, . . . , vn−1).

Exista foarte multi algoritmi care rezolva problema sortarii interne. Nu este ın intentia noastra a-itrece ın revista pe toti. Vom prezenta numai cateva metode pe care le consideram cele mai semnificative.Doua dintre acestea, anume sortarea prin interclasare si sortarea rapida, vor fi prezentate ın capitoluldedicat metodei divide-et-impera.

4.1 Sortare bazata pe comparatii

In aceasta sectiune am grupat metodele de sortare bazate pe urmatoarea tehnica: determinarea permutariise face comparand la fiecare moment doua elemente a[i] si a[j] ale tabloului supus sortarii. Scopulcompararii poate fi diferit: pentru a rearanja valorile celor doua componente ın ordinea fireasca (sortareprin interschimbare), sau pentru a insera una dintre cele doua valori ıntr-o subsecventa ordonata deja(sortare prin insertie), sau pentru a selecta o valoare ce va fi pusa pe pozitia sa finala (sortare prinselectie). Decizia ca o anumita metoda apartine la una dintre subclasele de mai sus are un anumit gradde subiectivitate. De exemplu selectia naiva ar putea fi foarte bine considerata ca fiind o metoda bazatape interschimbare.

71

Page 69: algoritmi_tehnici_dorel lucanu - carte

72 CAPITOLUL 4. SORTARE INTERNA

4.1.1 Sortarea prin interschimbare

Vom prezenta aici strategia cunoscuta sub numele de sortare prin metoda bulelor (bubble sort).Notam cu SORT (a) predicatul care ia valoarea true daca si numai daca tabloul a este sortat. Metoda

bubble sort se bazeaza pe urmatoarea definitie a predicatului SORT (a):

SORT (a) ⇐⇒ (∀i)(0 ≤ i < n− 1)⇒ a[i] ≤ a[i+ 1]

O pereche (i, j) cu i < j formeaza o inversiune (inversare) daca a[i] > a[j]. Astfel, pe baza definitiei demai sus vom spune ca tabloul a este sortat daca si numai daca nu exista nici o inversiune de elementevecine. Metoda “bubble sort” propune parcurgerea iterativa a tabloului a si, la fiecare parcurgere, ori decate ori se ıntalneste o inversiune (i, i + 1) se procedeaza la interschimbarea a[i] ↔ a[i+ 1]. La primaparcurgere, elementul cel mai mare din secventa formeaza inversiuni cu toate elementele aflate dupa elsi, ın urma interschimbarilor realizate, acesta va fi deplasat pe ultimul loc care este si locul sau final.La iteratia urmatoare, la fel se va intampla cu cel de-al doilea element cel mai mare. In general, dacasubsecventa a[r+1..n−1] nu are nici o inversiune la iteratia curenta, atunci ea nu va avea inversiuni la niciuna din iteratiile urmatoare. Aceasta permite ca la iteratia urmatoare sa fie verificata numai subsecventaa[0..r]. Terminarea algoritmului este data de faptul ca la fiecare iteratie numarul de interschimbari estemicsorat cu cel putin 1.

Descrierea Pascal a algoritmului este urmatoarea:

procedure bubbleSort(a, n)begin

ultim ← n-1while (ultim > 0) do

n1 ← ultim - 1ultim ← 0for i ← 0 to n1 do

if (a[i] > a[i+1])then swap(a[i], a[i+1])

ultim ← iend

Evaluarea algoritmului Cazul cel mai favorabil este intalnit atunci cand secventa de intrare este dejasortata, caz ın care algoritmul bubbleSort executa O(n) operatii. Cazul cel mai nefavorabil este obtinutcand secventa de intrare este ordonata descrescator si, ın acest caz, procedura executa O(n2) operatii.In continuare ne ocupam de complexitatea timp medie. Mai precis, vom arata ca numarul mediu decomparatii este

O(12(n2 − n logn−O(n)) +O(

√n))

Fara a restrange generalitatea, presupunem ca valoarea initiala a tabloului a este o permutare a multimii1, 2, . . . , n : 〈v1, . . . , vn〉 = Perm(1, 2, . . . , n).

Definitia 4.1. Fie x = 〈x0, . . . , xn−1〉 o permutare a multimii 0, 1, ..., n−1. Numim cod al permutariix secventa cod(x) = (y0, . . . , yn−1) unde yj reprezinta numarul elementelor xi aflate la stanga lui j simai mari decat j, i.e.

yj = #xi | i < k si xi > junde k satisface xk = j. Secventa cod(x) mai este numita si tablou de inversari. Vom prefera totusidenumirea de cod al permutarii.

Codurile permutarilor ne vor ajuta la studiul proprietatilor algoritmului BubbleSort. Sa observammai ıntai ca valoarea cod(v)(j) reprezinta numarul de inversiuni ale caror componenta secundara estej. De exemplu, daca v = (4, 2, 3, 1, 0) atunci cod(v) = (4, 3, 1, 1, 0). Dupa o trecere a algoritmuluiBubbleSort (o executie a buclei while ) se obtine urmatoarea valoare pentru a: w = (2, 3, 1, 0, 4). Avemcod(w) = (3, 2, 0, 0, 0). Se observa urmatoarea proprietate:

cod(v)(i) = 0⇒ cod(w)(i) = cod(v)(i) − 1

In general are loc:

Page 70: algoritmi_tehnici_dorel lucanu - carte

4.1. SORTARE BAZATA PE COMPARATII 73

Teorema 4.1. Presupunem ca valoarea tabloului a este v = (v0, . . . , vn−1) = Perm(0, 1, . . . , n− 1) si cadupa o trecere a algoritmului BubbleSort se obtine valoarea w = (w0, . . . , wn−1) pentru a. Atunci areloc:

(∀i)cod(v)(i) = 0⇒ cod(w)(i) = cod(v)(i) − 1

Teorema de mai sus justifica atat proprietatea de terminare a algoritmului BubbleSort cat si corectautilizare a variabilei ultim. In continuare ne ocupam de calculul numarului mediu de comparatii. Plecamde la presupunerea ca orice permutare v a multimii 0, 1, ..., n−1 poate sa apara cu aceeasi probabilitate,p = 1

n! , ca intrare a algoritmului BubbleSort. Notam cu uj valoarea expresiei ultim-1 (variabilei n1la ınceputul iteratiei j). Fie w valoarea tabloului a obtinuta dupa cea de-a j − 1-a iteratie. Dacacod(w)(i) > 0 atunci exista cod(w)(i) elemente mai mari decat i aflate la stanga lui i; cel mai mare dintreaceste elemente va avea pozitia finala p ≥ cod(w)(i) + i. Mai mult , daca elementul i este cel mai dindreapta care trebuie schimbat la iteratia j, atunci are loc:

cod(w)(i) ≥ 1 si ultim = cod(w)(i) + i

De aici rezulta uj = maxicod(w)(i) + i − 1 | cod(w)(i) ≥ 1. Aplicand teorema de mai sus de j − 1ori, obtinem: cod(w)(i) = cod(v)(i) − (j − 1). Relatia de mai sus devine uj = maxicod(v)(i) + i − j |cod(v)(i) > j − 1. Pentru un k dat, algoritmul BubbleSort va executa cel mult k iteratii pentru aceleintrari care satisfac ∀i : cod(v)(i) < k. Numarul de permutari care satisfac proprietatea de mai suseste egal cu kn−kk! (conform [Knu76] pag.108). Rezulta ca probabilitatea ca algoritmul BubbleSortsa execute cel mult k iteratii este 1

n! (kn−kk!) iar probabilitatea ca sa se execute exact k iteratii este

1n! (k

n−kk! − (k − 1)n−k+1(k − 1)!). Pentru calcularea numarului mediu de comparatii, vom determinavalorile medii pentru uj. Pentru aceasta, este util sa determinam numarul permutarilor v cu proprietatea

(∀i)cod(v)(i) < j − 1 sau cod(v)(i) + i− j ≤ k

(numarul intrarilor pentru care BubbleSort executa cel mult j+k iteratii). Conform cu [Knu76] pag.108, acest numar este:

fj(k) = (j + k)!(j − 1)n−j−k pentru j ≤ j + k ≤ nValoarea medie a lui uj este:

umedj =

∑(k|j<k+j≤n)

k(fj(k)− fj(k − 1))

n!Facem calculele:∑

k(fj(k)− fj(k − 1)) = fj(1)− fj(0) + 2(fj(2)− fj(1)) + 3(fj(3)− fj(2)) + · · ·+(n− j)(fj(n− j)− fj(n− j − 1))

= (n− j)fj(n− j)−n−j∑k=1

fj(k)

= (n− j)n!−n−j∑k=1

fj(k)

si obtinem:

umedj = (n− j)− 1

n!

n−j∑k=1

fj(k)

Numarul mediu de comparatii este:

Cmed(n) =n∑

j=1

umedj

=n∑

j=1

[(n− j)− 1n!

n−j∑k=1

fj(k)]

= n(n− 1)2 − 1

n!n∑

j=1

n−j∑k=1

fj(k)

= n(n− 1)2 − 1

n!∑

0≤p<q≤n

q!pn−q

Page 71: algoritmi_tehnici_dorel lucanu - carte

74 CAPITOLUL 4. SORTARE INTERNA

Conform cu [Knu76] pag. 108 si pag. 129-134 are loc:

Cmed(n) = O(12(n2 − n logn−O(n)) +O(

√n))

4.1.2 Sortare prin insertie

Una din familiile importante de tehnici de sortare se bazeaza pe metoda ”jucatorului de bridge” (atuncicand ısi aranjeaza cartile), prin care fiecare element este inserat ın locul corespunzator ın raport cuelementele sortate anterior.

4.1.2.1 Sortare prin insertie directa

Principiul de baza al algoritmului de sortare prin insertie este urmatorul: Se presupune ca subsecventa(a[0], . . . , a[j− 1]) este sortata. Se cauta ın aceasta subsecventa locul i al elementului a[j] si se insereazaa[j] pe pozitia i. Pozitia i este determinata astfel:

• i = 0 daca a[j] < a[0];

• 0 < i < j si satisface a[i− 1] ≤ a[j] < a[i];

• i = j daca a[j] ≥ a[j − 1].

Determinarea lui i se poate face prin cautare secventiala sau prin cautare binara. Consideram cazulcand pozitia i este determinata prin cautare secventiala (de la dreapta la stanga) simultan cu deplasareaelementelor mai mari decat a[j] cu o pozitie la dreapta. Aceasta deplasare se realizeaza prin interschimbariastfel ıncat valoarea a[j] realizeaza cate o deplasare la stanga pana ajunge la locul ei final.

procedure insertSort(a, n)begin

for j ← 1 to n-1 doi ← j-1temp ← a[j]while ((i ≥ 0) and (temp < a[i])) do

a[i+1] ← a[i]i ← i-1

if (i = j-1) then a[i+1] ← tempend

Evaluarea Cautarea pozitiei i ın subsecventa a[0..j − 1] necesita O(j − 1) timp. Rezulta ca timpultotal ın cazul cel mai nefavorabil este O(1 + · · ·+ n− 1) = O(n2). Pentru cazul cel mai favorabil, candvaloarea tabloului la intrare este deja ın ordine crescatoare, complexitatea timp este O(n).

Exercitiul 4.1.1. Complexitatea algoritmului de sortare prin insertie poate fi ımbunatatita considerandsecventa de sortat reprezentata printr-o lista simplu ınlantuita. Sa se rescrie algoritmul InsertSortcorespunzator acestei reprezentari. Sa se precizeze complexitatea timp a noului algoritm.

4.1.2.2 Metoda lui Shell

In algoritmul precedent elementele se deplaseaza numai cu cate o pozitie o data si prin urmare timpulmediu va fi proportional cu n2, deoarece fiecare element calatoreste ın medie n/3 pozitii ın timpul pro-cesului de sortare. Din acest motiv s-au cautat metode care sa ımbunatateasca insertia directa, prinmecanisme cu ajutorul carora elementele fac salturi mai lungi ın loc de pasi mici. O asemenea metodaa fost propusa in anul 1959 de Donald L. Shell, metoda pe care o vom mai numi sortare cu micsorareaincrementului. Urmatorul exemplu ilustreaza ideea generala care sta la baza metodei.

Exemplu: Presupunem n = 16. Sunt executati urmatorii pasi:

Page 72: algoritmi_tehnici_dorel lucanu - carte

4.1. SORTARE BAZATA PE COMPARATII 75

1. Prima trecere. Se impart cele 16 elemente ın 8 grupe de cıte doua ınregistrari (valoarea incremen-tului h0 = 8): (a[0], a[8]), (a[1], a[9]), . . . , (a[7], a[15]). Fiecare grupa este sortata separat, astfel caelementele mari se deplaseaza spre dreapta.

2. A doua trecere. Se ımpart elementele ın grupe de cate 4 (valoarea incrementului h1 = 4) care sesorteaza separat:

(a[0], a[4], a[8], a[12]), . . . , (a[3], a[7], a[11], a[15])

3. A treia trecere. Se grupeaza elementele ın doua grupe de cate 8 elemente (valoarea incrementuluih2 = 2): (a[0], a[2], . . . , a[14]), (a[1], a[3], . . . , a[15]) si se sorteaza separat.

4. A patra trecere. Acest pas termina sortarea prin considerarea unei singure grupe care contine toateelementele. In final cele 16 elemente sunt sortate.

sfex

Fiecare din procesele intermediare de sortare implica, fie o sublista nesortata de dimensiune relativscurta, fie una aproape sortata, astfel ca, insertia directa poate fi utilizata cu succes pentru fiecare operatiede sortare. Prin aceste insertii intermediare, elementele tind sa convearga rapid spre destinatia lor finala.Secventa de incremente 8, 4, 2, 1 nu este obligatorie; poate fi utilizata orice secventa hi > hi−1 > · · · > h0,cu conditia ca ultimul increment h0 sa fie 1.

Presupunem ca numarul de incremente este memorat de variabila nincr si ca acestea sunt memorateın tabloul (kval[h] | 0 ≤ h ≤ nincr − 1). Subprogramul care descrie metoda lui Shell este:

procedure ShellSort(a, n)begin

for h ← nincr-1 downto 0 dok ← kval[h]for i ← k to n-1 do

temp ← a[i]j ← i-kwhile ((j ≥ 0) and (temp < a[j])) do

a[j + k] ← a[j]j ← j - k

if (j+k = i) then a[j+k] ← tempend

Evaluarea metodei lui Shell Pentru evaluare vom presupune ca elementele din secventa sunt diferitesi dispuse aleator. Vom denumi operatia de sortare corespunzatoare primei treceri ht-sortare, apoi ht−1-sortare, etc.. O subsecventa pentru care a[i] ≤ a[i + h], pentru 0 ≤ i ≤ n − 1 − h, va fi denumitah-ordonata. Vom considera pentru ınceput cea mai simpla generalizare a insertiei directe si anume cazulcand avem numai doua incremente: h1 = 2 si h0 = 1. Cazul cel mai favorabil este obtinut cand secventade intrare este ordonata crescator si sunt executate n2 −1+n−1 comparatii si nici o deplasare. Cazul cel

mai nefavorabil, cand secventa de intrare este ordonata descrescator, necesita 14n(n− 2) + n

2 comparatiisi tot atatea deplasari (s-a presupus n numar par). In continuare ne ocupam de comportarea ın medie.In cea de-a doua trecere avem o secventa 2-ordonata de elemente a[0], a[1], . . . , a[n − 1]. Este usor devazut ca numarul de permutari (i0, i1, . . . in−1) ale multimii 0, 1, . . . , n − 1 cu proprietatea ik ≤ ik+2,

pentru 0 ≤ k ≤ n−3, este C[n2 ]n deoarece obtinem exact o permutare 2-ordonata pentru fiecare alegere de

[n2 ] elemente care sa fie puse in pozitii impare 1, 3, . . .. Fiecare permutare 2-ordonata este egal posibiladupa ce o subsecventa aleatoare a fost 2-ordonata. Determinam numarul mediu de inversari ıntre astfelde permutari. Fie An numarul total de inversari peste toate permutarile 2-ordonate de 0, 1, . . . , n− 1.Relatiile A1 = 0, A2 = 1, A3 = 2 sunt evidente. Considerand cele sase cazuri 2-ordonate

0 1 2 3 0 2 1 3 0 1 3 2 1 0 2 3 1 0 3 2 2 0 3 1

vom gasi A4 = 0 + 1 + 1 + 2 + 3 = 8. In urma calculelor, care sunt un pic dificile (a se vedea [Knu76]pag. 87), se obtine pentru An o forma destul de simpla:

An =[n2

]2n−2

Page 73: algoritmi_tehnici_dorel lucanu - carte

76 CAPITOLUL 4. SORTARE INTERNA

De aceea numarul mediu de inversari ıntr-o permutare aleatoare 2-ordonata este[n2

]2n−2

C[n2 ]n

Dupa aproximarea lui Stirling aceasta converge asimptotic catre√π

128n32≈ 0.15n

32 .

Teorema 4.2. Numarul mediu de inversari executate de algoritmul lui Shell pentru secventa de incre-mente (2, 1) este O(n

32 ).

Se pune problema daca ın loc de secventa de incremente (2, 1) se considera (h, 1), atunci pentru cevalori ale lui h se obtine un timp cat mai mic pentru cazul cel mai nefavorabil. Are loc urmatorul rezultat([Knu76], pag. 89).

Teorema 4.3. Daca h ≈(16nπ

) 13 atunci algoritmul lui Shell necesita timpul O(n

53 ) pentru cazul cel mai

nefavorabil.

Pentru cazul general, cand secventa de incremente pentru algoritmul lui Shell este ht−1, . . . , h0, se cunoscurmatoarele rezultate. Primul dintre ele pune ın evidenta o alegere nepotrivita pentru incremente.

Teorema 4.4. Daca secventa de incremente ht−1, . . . , h0 satisface conditia

hs+1 mod hs = 0 pentru 0 ≤ s < t− 1

atunci complexitatea timp pentru cazul cel mai nefavorabil este O(n2).

O justificare intuitiva a teoremei de mai sus este urmatoarea. De exemplu daca hs = 2s, 0 ≤ s ≤ 3 atuncio 8-sortare urmata de o 4-sortare, urmata de o 2-sortare nu permite nici o interactiune ıntre elementelede pe pozitiile pare si impare. De aceea, trecerii finale de 1-sortare ıi vor reveni O(n

32 ) inversari. Dar

sa observam ca o 7-sortare urmata de o 5-sortare, urmata de o 3-sortare amesteca astfel lucrurile ıncattrecerea finala de 1-sortare nu va gasi mai mult de 2n inversari. Astfel are loc urmatoarea teorema.

Teorema 4.5. Complexitatea timp ın cazul cel mai nefavorabil a algoritmului ShellSort este O(n32 )

cand hs = 2s, 0 ≤ s ≤ t− 1 = [log2 n].

4.1.3 Sortarea prin selectie

Strategiile de sortare incluse ın aceasta clasa se bazeaza pe urmatoarea schema : la pasul curent seselecteaza un element din secventa si se plaseaza pe locul sau final. Procedeul continua pana cand toateelementele sunt plasate pe locurile lor finale. Dupa modul ın care se face selectarea elementului curent,metoda poate fi mai mult sau mai putin eficienta. Noi ne vom ocupa doar de doua strategii de sortareprin selectie.

4.1.3.1 Selectia naiva

Este o metoda mai putin eficienta dar foarte simpla ın prezentare. Se bazeaza pe urmatoarea caracterizarea predicatului SORT (a):

SORT (a) ⇐⇒ (∀i)(0 ≤ i < n)⇒ a[i] = maxa[0], . . . , a[i]

Ordinea ın care sunt asezate elementele pe pozitiile lor finale este n−1, n−2, . . . , 0. O formulare ehivalentaeste:

SORT (a) ⇐⇒ (∀i)(0 ≤ i < n) : a[i] = mina[i], . . . , a[n]

caz ın care ordinea de asezare este 0, 1, . . . , n− 1.Subprogramul naivSort determina de fiecare data locul valorii maxime:

Page 74: algoritmi_tehnici_dorel lucanu - carte

4.1. SORTARE BAZATA PE COMPARATII 77

procedure naivSort(a, n)begin

for i ← n-1 downto 1 dolocmax ← 0maxtemp ← a[0]for j ← 1 to i do

if (a[j] > maxtemp)then locmax ← j

maxtemp← a[j]a[locmax]← a[i]a[i] ← maxtemp

end

Evaluare algoritmului descris de procedura NaivSort este simpla si conduce la o complexitate timpO(n2) pentru toate cazurile, adica algoritmul NaivSort are complexitatea Θ(n2). Este interesant decomparat BubbleSort cu NaivSort. Cu toate ca sortarea prin metoda bulelor face mai putine comparatiidecat selectia naiva, ea este aproape de doua ori mai lenta decat selectia naiva, datorita faptului carealizeaza multe schimbari ın timp ce selectia naiva implica o miscare redusa a datelor. In tabelul dinfig. 4.1 sunt redati timpii de executie (ın sutimi de secunde) pentru cele doua metode obtinuti ın urmaa 10 teste pentru n = 1000.

Nr. test BubbleSort NaivSort1 71 332 77 273 77 284 94 385 82 276 77 287 83 328 71 339 71 3910 72 33

Figura 4.1: Compararea algoritmilor BubbleSort si NaivSort

4.1.3.2 Selectia sistematica

Se bazeaza pe structura de date de tip max-”heap” 3.7.2. Metoda de sortare prin selectie sistematicaconsta ın parcurgerea a doua etape:

I Construirea pentru secventa curenta a proprietatii MAX-HEAP(a).

II Selectarea ın mod repetat a elementului maximal din secventa curenta si refacerea proprietatiiMAX-HEAP pentru secventa ramasa.

Etapa I Consideram ca tabloul a are lungimea n. Initial are loc MAX-HEAP(a, n2 ).

Exemplu: Presupunem ca valoarea tabloului a este a = (10, 17, 5, 23, 7). Se observa imediat ca are locMAX-HEAP(a, 2):

5

23 7

Page 75: algoritmi_tehnici_dorel lucanu - carte

78 CAPITOLUL 4. SORTARE INTERNA

sfex

Daca are loc MAX-HEAP(a, & + 1) atunci se procedeaza la introducerea lui a[&] ın gramada dejaconstruita a[& + 1..n − 1], astfel ıncat sa obtinem MAX-HEAP(a, &). Procesul se repeta pana cand &devine 0.

Exemplu: (Continuare) Avem & = 1 si introducem pe a[1] = 17 ın gramada a[2..4]:

5

23 7

5

17 7

2317

Se obtine secventa (10, 23, 5, 17, 7) care are proprietatea MAX-HEAP ıncepand cu 2. Consideram& = 1 si introducem a[1] = 10 ın gramada a[2..5]. Se obtine valoarea (23, 17, 5, 10, 7) pentru tabloul a,valoare care verifica proprietatea MAX-HEAP. sfex

Algoritmul de introducerea elementului a[&] ın gramada a[&+1..n−1], pentru a obtine MAX-HEAP(a, &),este asemanator celui de inserare ıntr-un max-”heap”:

procedure intrInGr(a, n, &)begin

j ← &esteHeap← falsewhile ((2*j+1 ≤ n-1) and not esteHeap)

k ← j*2+1if((k < n-1) and (a[k] < a[k+1])then k ← k+1if(a[j] < a[k])then swap(a[j], a[k])else esteHeap← truej ← k

end

Etapa II Deoarece initial avem MAX-HEAP(a) rezulta ca pe primul loc se gaseste elementul maximaldin a[0..n − 1]. Punem acest element la locul sau final prin interschimbarea a[0] ↔ a[n − 1]. Acuma[0..n − 2] are proprietatea MAX-HEAP ıncepand cu 1. Refacem MAX-HEAP pentru aceasta secventaprin introducerea lui a[0] ın gramada a[0..n − 2], dupa care ıl punem pe locul sau final cel de-al doileaelement cel mai mare din secventa de sortat. Procedeul continua pana cand toate elementele ajung pelocurile lor finale.

Exemplu: Etapa a doua pentru exemplul anterior este aratata ın fig. 4.2. sfex

Algoritmul de sortare prin selectie sistematica este descris de subprogramul heapSort:

procedure HeapSort(a,n)begin

n1 ←[n− 1

2

]

for & ← n1 downto 0 dointrInGr(a, n, &)

r ← n-1while (r ≥ 1) do

swap(a[0], a[r])intrInGr(a, r, 0)r ← r-1

end

Page 76: algoritmi_tehnici_dorel lucanu - carte

4.1. SORTARE BAZATA PE COMPARATII 79

5

10 7

5

10

1717

→23 7 ,23

5

7

10

→ 17 ,23

7 ,17

10 5

,23 → 10 ,17

7 5

,23 → 5 ,17

7

,2310, →

7 ,17

5

,2310, → 5 ,17,2310,→ 7,5 ,17,2310,7,

Figura 4.2: Etapa a doua

Evaluarea algoritmului heapSort Consideram n = 2k − 1. In faza de construire a proprietatiiMAX-HEAP pentru toata secventa de intrare sunt efectuate urmatoarele operatii:

• se construiesc varfurile de pe nivelele k − 2, k − 3, . . .;

• pentru construirea unui varf de pe nivelul i se viziteaza cel mult cate un varf de pe nivelele i +1, . . . , k − 1;

• la vizitarea unui varf sunt executate 2 comparatii.

Rezulta ca numarul de comparatii executate ın prima etapa este cel mult:

k−2∑i=0

2(k − i− 1)2i = (k − 1)2 + (k − 2)22 + · · ·+ 1 · 2k−1 = 2k+1 − 2(k + 1)

In etapa a II-a, daca presupunem ca a[r] se gaseste pe nivelul i, introducerea lui a[0] ın gramada a[1..r]necesita cel mult 2i comparatii. Deoarece r ia valori de la 1 la n− 1 rezulta ca ın aceasta etapa numarultotal de comparatii este cel mult:

k−1∑i=0

2i2i = (k − 2)2k+1 + 4

Numarul total de comparatii este cel mult:

C(n) = 2k+1 − 2(k + 1) + (k − 2)2k+1 + 4= 2k+1(k − 1)− 2(k − 1)= 2k(2k − 1)− 2(2k − 1)= 2n log2 n− 2n

De unde rezulta ca numarul de comparatii este C(n) = O(n log2 n).

4.1.4 Sortarea rapida

A se vedea sectiunea 10.3.

Page 77: algoritmi_tehnici_dorel lucanu - carte

80 CAPITOLUL 4. SORTARE INTERNA

4.1.5 Sortarea prin interclasare

A se vedea sectiunea 10.2.

4.1.6 Numarul minim de comparatii pentru sortare

Algoritmii de sortare prezentati pana acum se bazeaza pe executarea a doua operatii primitive: comparatiasi interschimbarea a doua elemente. Deoarece orice interschimbare este, ın general, precedata de ocomparatie (prin care se decide daca interschimbarea este necesara) putem spune ca operatiile de com-parare domina calculul oricarui algoritm prezentat pana acum. Ne punem urmatoarele doua ıntrebari:

– care este numarul minim de comparatii executate ın cazul cel mai nefavorabil?

– care algoritmi de sortare realizeaza minimul de comparatii, i.e. care algoritmi sunt optimali?

Pentru a putea raspunde la cele doua ıntrebari trebuie mai ıntai sa precizam formal modelul de calculpeste care sunt construiti acesti algoritmi.

Sa analizam cativa algoritmi pentru ordonarea secventei (a0, a1, a2). Vom ıncerca sa determinam careelemente se compara pentru obtinerea permutarii dorite. O prima observatie pe care o facem este aceeaca daca se compara elementele ai si aj , notat i ? j, atunci multimea comparatiilor care urmeaza a fifacute depinde de raspunsul obtinut prin efectuarea acestei comparatii. Pentru simplitate vom presupuneai = aj daca i = j. Deoarece raspunsul dat de comparatia i ? j are numai doua posibilitati de alegere,rezulta ca putem reprezenta cele doua multimi de comparatii prin intermediul unui arbore binar:

– radacina va contine o comparatie i ? j;

– subarborele din stanga contine comparatiile facute ın cazul ai < aj ;

– subarborele din dreapta contine comparatiile facute ın cazul ai > aj .

Arborii corespunzatori sortarii prin selectie naiva si sortarii prin insertie sunt reprezentati ın fig. 4.3.In varfurile de pe frontiera am trecut permutarile care dau ordinea crescatoare a elementelor. In acest

fel putem asocia fiecarui algoritm de sortare bazat pe comparatii un arbore binar. Vom utiliza acestiarbori pentru a defini modelul de calcul.

Definitia 4.2. Un arbore de decizie de dimensiune n este un arbore binar ın care varfurile interne suntetichetate cu perechi de forma i ? j, iar varfurile de pe frontiera sunt etichetate cu permutari ale multimii0, 1, . . . , n− 1.

Definitia 4.3. Fie t un arbore de decizie de dimensiune n si secventa a = (a0, . . . , an−1). Calculul lui tpentru intrarea a consta ın parcurgerea unui drum de la radacina la un varf de pe frontiera definit astfel:

1. Initial se pleaca din radacina.

2. Presupunem ca varful curent este i ? j. Daca ai < aj atunci fiul din stanga lui i ? j devine varfcurent; altfel fiul din dreapta devine varf curent.

3. Calculul se opreste daca varful curent este pe frontiera.

Definitia 4.4. Fie t un arbore de decizie de dimensiune n. Spunem ca t rezolva problema sortarii dacapentru orice intrare a = (a0, . . . , an−1), calculul lui t pentru a se termina ıntr-un varf cu permutarea πastfel ıncat aπ(0) < · · · < aπ(n−1). Un arbore de decizie care rezolva problema sortarii va mai fi numitsi arbore de decizie pentru sortare iar modelul de calcul va fi numit modelul arborilor de decizie pentrusortare.

Putem defini acum complexitatea minima pentru cazul cel mai nefavorabil prin expresia:

S(n) = mint

maxπ

Lung(π, t)

unde Lung(π, t) reprezinta drumul de la radacina la varful pe frontiera etichetat cu π ın arborele dedecizie pentru sortare t.

Page 78: algoritmi_tehnici_dorel lucanu - carte

4.1. SORTARE BAZATA PE COMPARATII 81

0?1

0?2

0,2,1 2,0,1

1?2

0?1

1,0,2

1?2

1,2,0 2,1,0

0?2

0,1,2

0?1

< >

<

< < <

< >

>>>

>

Sortare prin selectie naiva

0?2

0,2,1 2,0,1

1?2

1,0,2

1?2

1,2,0 2,1,0

0?2

0,1,2

0?1

< >

<

<

<

<

>

>>

>

Sortare prin insertie

Figura 4.3: Arbori de decizie pentru sortare

Page 79: algoritmi_tehnici_dorel lucanu - carte

82 CAPITOLUL 4. SORTARE INTERNA

Teorema 4.6. Problema sortarii are complexitatea timp pentru cazul cel mai nefavorabil Ω(n logn) ınmodelul arborilor de decizie pentru sortare.

Demonstratie. Un arbore de decizie de dimensiune n care rezolva problema sortarii are n! varfuri pefrontiera. Un arbore de ınaltime k are cel mult 2k varfuri pe frontiera. De aici rezulta

2S(n) ≥ n!

care implica S(n) ≥ log2(n!) = Θ(n log2 n) (a se vedea anexa ??). sfdem

Corolar 4.1. Algoritmul HeapSort este optimal ın modelul arborilor de decizie pentru sortare.

4.1.7 Exercitii

Exercitiul 4.1.2. Se considera un tablou de structuri (a[i] | 0 ≤ i < n) si un al doilea tablou (a[i] | 0 ≤i < n) care contine o permutare a multimii 0, 1, . . . , n − 1. Sa se scrie un program care rearanjeazacomponentele tabloului a conform cu permutarea data de b.

Exercitiul 4.1.3. Sa se modifice ShellSort astfel ıncat sa utilizeze ıntotdeauna secventa de incremente(h0, . . . , hk−1) data prin recurenta: h0 = 1;hi+1 = 3hi + 1 si hk−1 cel mai mare increment de acest felmai mic decat n− 1. Apoi se va ıncerca gasirea de alte secvente de incremente care sa produca algoritmide sortare mai eficienti.

Exercitiul 4.1.4. Sa se scrie o varianta recursiva a algoritmului de inserare ıntr-un heap intrInGr.Care dintre cele doua variante este mai eficienta?

Exercitiul 4.1.5. Care este timpul de executie al algoritmului heapSort daca secventa de intrare esteordonata crescator? Dar daca este ordonata descrescator?

Exercitiul 4.1.6. Sa se proiecteze un algoritm care sa determine cel de-al doilea cel mai mare elementdintr-o lista. Algoritmul va executa n+ logn − 2 comparatii.Indicatie. Fie (a0, . . . , an−1) secventa de intrare. Cel mai mare element din lista se poate face prin n− 1comparatii. Se va utiliza urmatoarea metoda pentru determinarea maximului:

• se determina b0 = max(a0, a1), b1 = max(a2, a3), . . ..

• se determina c0 = max(b0, b1), c1 = max(b2, b3), . . ..

• etc.

Metodei de mai sus i se poate atasa un arbore binar complet de marime n, fiecare varf intern reprezentando comparatie iar radacina corespunzand celui mai mare element. Pentru a determina cel de-al doilea celmai mare element este suficient sa se considere numai elementele care au fost comparate cu maximul.Numarul acestora este log2 n − 1. Va trebui proiectata o structura de date pentru memorarea acestorelemente.

Exercitiul 4.1.7. (Selectie.) Sa se generalizeze metoda din exercitiul anterior pentru a determina celde-al k-lea cel mai mare element dintr-o lista. Care este complexitatea timp algoritmului? (Se stie caexista algoritmi care rezolva aceasta problema ın timpul Θ(n+ min(k, n− k) logn)).

Exercitiul 4.1.8. (Sortare prin metoda turneelor.) Sa se utilizeze algoritmul din exercitiul precedentpentru sortarea unei liste. Care este complexitatea algoritmului de sortare?

Exercitiul 4.1.9. Sa se proiecteze programarea unui turneu de tenis la care participa 16 jucatori astfelıncat numarul de meciuri sa fie minim iar primii doi sa fie corect clasati relativ la relatia de ordine “amai bun ca b”, definita astfel:

• daca a ınvinge pe b atunci a mai bun ca b;

• daca a mai bun ca b si b mai bun ca c atunci a mai bun ca c.

Page 80: algoritmi_tehnici_dorel lucanu - carte

4.2. SORTARE PRIN DISTRIBUIRE 83

4.2 Sortare prin distribuire

In aceasta sectiune si ın urmatoarea vom studia algoritmi de sortare pentru cazurile cand se cunoscinformatii suplimentare despre elementele care se sorteaza. Asa cum reiese si din denumire, algoritmii desortare prin distribuire presupun cunoasterea de informatii privind distributia acestor elemente. Acesteinformatii sunt utilizate pentru a distribui elementele secventei de sortat ın “pachete” care vor fi sortateın acelasi mod sau prin alta metoda, dupa care pachetele se combina pentru a obtine lista finala sortata.

4.2.1 Sortarea cuvintelor

Presupunem ca avem n fise iar fiecare fisa contine un nume care identifica ın mod unic fisa (cheia). Sepune problema sortarii manuale a fiselor. Pe baza experientei castigate se procedeaza astfel: se ımpartfisele ın pachete, fiecare pachet continand fisele ale caror cheie ıncep cu aceeasi litera. Apoi se sorteazafiecare pachet ın aceeasi maniera dupa a doua litera, apoi ... . Dupa sortarea tuturor pachetelor, acestease combina astfel ıncat formeaza o lista liniara sortata.

Vom ıncerca sa formalizam metoda de mai sus ıntr-un algoritm de sortare a sirurilor de caractere(cuvinte). Presupunem ca elementele secventei de sortat sunt siruri de lungime fixata m definite pesteun alfabet cu k litere. Echivalent, se poate presupune ca elementele de sortat sunt numere reprezentateın baza k. Din acest motiv, sortarea cuvintelor este denumita ın engleza “radix sort” (cuvantul “radix”traducandu-se prin “baza”).

Daca urmam ideea de la exemplul cu fisele, atunci algoritmul ar putea fi descris recursiv astfel:

1. Se ımpart cele n cuvinte in k pachete, cuvintele din acelasi pachet avand aceeasi litera pe pozitia i(numarand de la stanga la dreapta).

2. Apoi fiecare pachet este sortat ın aceeasi maniera dupa literele de pe pozitiile i+ 1, . . . ,m− 1.

3. Se concateneaza cele k pachete ın ordinea data de literele de pe pozitia i. Lista obtinuta este sortatadupa subcuvintele formate din literele de pe pozitiile i, i+ 1, . . . ,m− 1.

Initial se considera i = 0. Apare urmatoarea problema. Un grup de k pachete nu va putea fi combinat ıntr-o lista sortata decat daca cele k pachete au fost sortate complet pentru subcuvintele corespunzatoare. Estedeci necesara tinerea unei evidente a pachetelor, fapt care conduce la utilizarea de memorie suplimentarasi cresterea gradului de complexitate a metodei. O simplificare majora apare daca ımpartirea cuvintelor ınpachete se face parcurgand literele acestora de la dreapta la stanga. Procedand asa, observam urmatorulfapt surprinzator: dupa ce cuvintele au fost distribuite in k pachete dupa litera de pe pozitia i, cele kpachete pot fi combinate ınainte de a le distribui dupa litera de pe pozitia i− 1.

Exemplu: Presupunem ca alfabetul este 0 < 1 < 2 si m = 3. Cele trei faze care cuprind distribuireaelementelor listei ın pachete si apoi concatenarea acestora ıntr-o singura lista sunt sugerate grafic ın fig.4.4. sfex

Observatie: Atunci cand se face distribuirea cuvintelor ın pachete, ordinea aparitiilor cuvintelor ıntr-un pachet trebuie sa coincida cu ordinea din lista initiala. Adica, daca distribuirea se face dupa cheia isi doua chei au pe pozitia i aceeasi litera, atunci o cheie o va preceda pe cealalta ın pachet daca si numaidaca o precede si ın secventa initiala (cea supusa sortarii). Aceasta proprietate este un caz particular alcelei cunoscute sub numele de stabilitate a algoritmilor de sortare si care se enunta astfel: un algoritmde sortare este stabil daca pastreaza ordinea relativa initiala a elementelor (cu chei) egale. sfobs

Pentru gestionarea pachetelor vom utiliza un tablou de pointeri pachet cu semnificatia ca elementulpachet[i] face referire la primul element din lista ce reprezinta pachetul i. Subetapa de distribuire esterealizata ın modul urmator: Initial se considera listele pachet[i] vide. Apoi se parcurge secvential listasupusa distribuirii si fiecare element al acesteia este distribuit ın pachetul corespunzator. Subetapa decombinare a pachetelor consta ın concatenarea celor k liste pachet[i], i = 0, . . . , k−1. Pentru ca operatiade inserare a unei noi chei ıntr-un pachet sa se realizeze usor, este util sa folosim ınca un tablou de pointeriultim cu semnificatia ca ultim[i] face referire la ultimul element din lista corespunzatoare pachetului i.De asemenea, tabloul ultim va fi utilizat cu succes si la concatenarea listelor. Descrierea procedurala aalgoritmului este urmatoarea:

Page 81: algoritmi_tehnici_dorel lucanu - carte

84 CAPITOLUL 4. SORTARE INTERNA

· · ·

· · · · · · · · ·0 1 2

⇓ Impachetare

pachet 0 pachet 1 pachet 2

· · ·· · ·· · ·

⇓ Despachetare

0 1 2

· · · · · · · · ·0 1 2

⇓ Impachetare

pachet 0 pachet 1 pachet 2

· · ·· · ·· · ·

⇓ Despachetare

0 0 00 1 2

· · · · · · · · ·0 1 2

⇓ Impachetare

pachet 0 pachet 1 pachet 2

· · ·· · ·· · ·

⇓ Despachetare

0 0 00 0 00 1 2

Figura 4.4: Sortare prin distribuire

Page 82: algoritmi_tehnici_dorel lucanu - carte

4.2. SORTARE PRIN DISTRIBUIRE 85

procedure radixSort(a,n)begin

for i ← m-1 downto 0 dofor j ← 0 to k-1 do

pachet[j]← listaVida()while (not esteVida(L)) do

w ← citeste(L, 0)elimina(L, 0)insereaza(pachet[w[i]],lungime(pachet[w[i]]), w)

for j ← 0 to k-1 doconcateneaza(L, pachet[j])

end

Procedura concateneaza(L1, L2) concateneaza listele L1 si L2 si memoreaza rezultatul ın L1.

Evaluarea algoritmului radixSort Distribuirea ın pachete presupune parcurgerea completa a listeide intrare iar procesarea fiecarui element al listei necesita O(1) operatii. Rezulta ca faza de distribuirese face ın timpul O(n), unde n este numarul de elemente din lista. Combinarea pachetelor presupuneo parcurgere a tabloului pachet iar adaugarea unui pachet se face cu O(1) operatii. Astfel, faza decombinare a pachetelor necesita O(k) timp. Rezulta ca algoritmul RadixSort are o complexitate timpO(m ·n). De remarcat ca, atunci cand m are valori foarte mici comparativ cu n O( nm ) = Ω(n)), se obtineo limita inferioara valorii optime pentru modelul arborilor de decizie. Aceasta ımbunatatire este posibiladatorita informatiei suplimentare despre organizarea cheilor supuse sortarii.

4.2.2 Distribuire prin segmentare

Algoritmul de sortare care utilizeaza distribuirea prin segmentare (ın engleza “bucket sort”) folosestefaptul ca secventa de intrare este furnizata de un proces aleator care distribuie elementele uniform pesteintervalul [0, 1). Asadar, presupunem ca elementele de sortat sunt numere din acest interval. Ideeaalgoritmului este urmatoarea:

• Se divide intervalul [0, 1) ın n subintervale de marimi egale.

• Se distribuie cele n intrari ın n pachete, un pachet continand numerele ce apartin unui subinterval.Pachetul la care apartine intrarea ai este determinat de valoarea expresiei n ·ai+1, daca pachetelesunt numerotate de la 1 la n. Deoarece intrarile sunt distribuite uniform peste intervalul [0, 1), estede asteptat ca un pachet sa nu contina prea multe numere.

• Se sorteaza fiecare pachet utilizand o alta metoda, de exemplu sortarea prin insertie directa.

• Se combina cele n pachete ıntr-o lista sortata.

Exercitiul 4.2.1. Presupunem ca lista de intrare este reprezentata de un tablou. Sa se scrie un sub-program BucketSort care descrie algoritmul de sortare de mai sus. Pachetele vor fi gestionate cu listeınlantuite, ca ın cazul algoritmului RadixSort. Sortarea unui pachet se va face prin insertie directa.

Vom arata ca algoritmul BucketSort are complexitatea timp medie O(n). Notam cu ni variabila aleatoarecare, pentru o intrare data, da numarul de elemente apartinand intervalului i. Complexitatea timp aalgoritmului de sortare prin insertie directa este O(n2) si deci complexitatea timp medie pentru sortareapachetului i este M [O(n2

i )] = O(M [n2i ]). Rezulta ca algoritmul BucketSort are complexitatea timp

medie∑n

i=1O(M [n2i ]) = O(

∑ni=1M [n2

i ]). Valorile posibile pentru variabila aleatoare ni sunt 0, 1, . . . , niar probabilitatea ca ni = k este pk = Ck

n( 1n )k(1 − 1n )n−k (distributie binomiala). Rezulta ca media

variabilei aleatoare ni este M [ni] =∑n

i=0 k · pk = n · 1n = 1. Pentru calculul mediei variabilei aleatoaren2

i vom utiliza formula M [n2i ] = D[ni] +M2[ni], unde D[ni] este dispersia variabilei aleatoare ni. Se

stie ca dispersia unei variabile aleatoare cu distributie binomiala este np(1 − p) (a se vedea anexa ??),de unde D[ni] = n 1

n (1 − 1n) = 1 − 1

n . Rezulta M [n2i ] = 2 − 1

n = Θ(1) care implica O(∑n

i=1M [n2i ]) =

O(∑n

i=1 Θ(1)) = O(n). De aici complexitatea timp medie a algoritmului BucketSort este O(n).

Page 83: algoritmi_tehnici_dorel lucanu - carte

86 CAPITOLUL 4. SORTARE INTERNA

4.2.3 Exercitii

Exercitiul 4.2.2. Sa se descrie un algoritm care sorteaza cuvinte astfel ıncat distribuirea ın pachetesa se faca prin parcurgerea cuvintelor de la stanga la dreapta. Se presupune ca lista cuvintelor estereprezentata ın memorie printr-un tablou. Algoritmul va utiliza un singur tablou suplimentar de lungimen si un singur tablou suplimentar de lungime k si va avea complexitatea timp O(m · n).

Exercitiul 4.2.3. Sa se aplice RadixSort la sortarea numerelor ıntregi, tinand cont de reprezentarea lorın memoria calculatorului.Indicatie. Reprezentarea binara a unui numar este divizata, de exemplu, ın patru parti. Astfel un ıntregpoate fi vazut ca o cheie formata din patru “litere” (numere apartinand unui domeniu restrans). Sa setesteze eficienta noului algoritm de sortare cu cele ale algoritmilor bazati pe comparatii.

Exercitiul 4.2.4. [CLR93] Sa se utilizeze inductia pentru a dovedi ca RadixSort rezolva corect problemasortarii. Unde este utilizata proprietatea ca sortarile intermediare sunt stabile?

Exercitiul 4.2.5. Sa se scrie o varianta recursiva a algoritmului RadixSort ın care ordonarea cuvintelordupa literele de pe o anumita pozitie se face prin interschimbare: Se pleaca cu un indice i din stanga sicu un indice j din dreapta si se ınainteaza alternativ pana cand se ıntalneste o inversiune. Se rezolvainversiunea prin interschimbare dupa care procesul continua pana se parcurge toata secventa (a se vedeasi pasul de divizare de la QuickSort din sectiunea 10.3). Mai exista diferente semnificative ıntre cele douamoduri de considerare a literelor dupa care se face ordonarea - de la stanga la dreapta si de la dreapta lastanga?

Exercitiul 4.2.6. [CLR93] Sa se proiecteze un algoritm care sa sorteze n ıntregi din intervalul [0, n2) ıntimpul O(n).Indicatie. Numerele din intervalul [0, n2) pot fi scrise ca secvente de doua cifre ın baza log2 n si se aplicaalgoritmul RadixSort.

Exercitiul 4.2.7. Sa se arate ca algoritmul BucketSort rezolva corect problema sortarii.

Exercitiul 4.2.8. Care este complexitatea timp pentru cazul cel mai nefavorabil a algoritmului BucketSort?Poate fi modificat BucketSort pentru a avea o complexitate timp O(n log n) pentru cazul cel mai nefa-vorabil? (Modificarea va trebui sa pastreze complexitatea medie liniara).

4.3 Sortare prin numarare

Presupunem ca tipul TElement, peste care sunt definite secventele supuse sortarii, contine numai douaelemente: alb < negru. Sortarea unui tablou a:array[1..n] of TElement este foarte simpla: se de-termina numarul n1 de elemente din a egale cu alb si numarul n2 de elemente egale cu negru. Aceastase poate face ın timpul Θ(n). Apoi se pun ın tablou n1 elemente alb urmate de n2 elemente negru. Sicea de-a doua etapa necesita Θ(n) timp. Rezulta un algoritm de sortare cu complexitatea timp Θ(n).Si de aceasta data, obtinerea unui algoritm de sortare liniar a fost posibila datorita faptului ca s-aucunoscut informatii suplimentare despre elementele supuse sortarii, anume ca multimea univers continenumai doua elemente. Algoritmul de sortare prin numarare are ca punct de plecare observatia de maisus si se utilizeaza atunci cand multimea univers contine putine elemente. Prin simplificare, presupunemca U = 0, 1, . . . , k − 1 cu relatia de ordine naturala. Algoritmul de la ınceputul sectiunii are un defect:daca secventa de sortare este una de articole si sortarea se face dupa chei, atunci etapa a doua a algorit-mului devine inefectiva. In plus, algoritmul nu are proprietatea de stabilitate. Vom modifica algoritmulastfel ıncat elementele tabloului de intrare a sa fie transferate direct ın tabloul de iesire b pe locurilelor finale. Cum poate fi utilizata numararea pentru a determina locurile elementelor ın tabloul sortat?Revenim la exemplul de la ınceputul sectiunii. Observam ca elementul negru aflat cel mai la dreapta ına are pozitia n1 + n2 ın b, urmatorul va avea pozitia n1 + n2− 1, si asa mai departe. Elementul alb aflatcel mai la dreapta ın a are pozitia n1 ın b, urmatorul pozitia n1 − 1, si asa mai departe. Presupunemexistenta unui vector p cu valoarea initiala p[alb] = n1, p[negru] = n1 + n2. Etapa a doua a algoritmuluiva parcurge tabloul a de la dreapta la stanga si va pastra invarianta urmatoarea proprietate: p[alb] vafi pozitia primului element alb ce va fi ıntalnit si p[negru] va fi pozitia primului element negru ce va fi

Page 84: algoritmi_tehnici_dorel lucanu - carte

4.4. SORTARE TOPOLOGICA 87

ıntalnit. Aceasta proprietate poate fi pastrata prin decrementarea componentei din p imediat dupa ceelementul corespunzator din a a fost transferat. Prima etapa a algoritmului va determina vectorul p undep[i] = numarul de elemente din a mai mici decat sau egale cu i.

procedure sortNumarare(a, b, n)begin

for i ← 0 to k-1 dop[i] ← 0

for j ← 0 to n-1 dop[a[j]] ← p[a[j]]+1

for i ← 1 to k-1 dop[i] ← p[i-1] + p[i]

for j ← n-1 downto 0 doi ← a[j]b[p[i]-1]← ip[i] ← p[i]-1

end

Determinarea tabloului p necesita O(k + n) timp iar transferul O(n) timp. Rezulta ca algoritmulsortNumarare are complexitatea timp O(n + k). In practica, algoritmul este aplicat pentru k = O(n),caz ın care rezulta o complexitate liniara pentru sortNumarare.

4.3.1 Exercitii

Exercitiul 4.3.1. Sa se arate ca algoritmul SortNumarare este stabil.

Exercitiul 4.3.2. Presupunem ca ın etapa a doua a algoritmului SortNumarare se ınlocuieste forj ← n-1 downto 0 cu for j ← 0 to n-1. Sa se arate ca si noul algoritm rezolva corect problemasortarii. Mai este noul algoritm stabil?

Exercitiul 4.3.3. [CLR93] Sa se proiecteze un algoritm care, pentru o secventa de n ıntregi apartinandintervalului [0, k − 1], preproceseaza secventa ın timpul O(n + k), dupa care raspunde la ıntrebari deforma “cate elemente din secventa sunt ıntr-un interval [a, b]” ın timpul O(1).

Exercitiul 4.3.4. Presupunem ca despre secventa de intrare se cunoaste numai informatia ca elementelesunt distincte doua cate doua. Sa se proiecteze un algoritm bazat pe numarare care sa sorteze o astfelde secventa. Care este complexitatea timp a algoritmului proiectat? Mai este posibila proiectarea unuialgoritm de sortare liniar utilizand numai aceasta informatie suplimentara despre datele de intrare?

4.4 Sortare topologica

Presupunem acum ca relatia de ordine este partiala. Fie de exemplu a1 < a0, a1 < a2 < a3. Problemaconsta ın a crea o lista liniara care sa fie compatibila cu relatia de ordine: daca ai < aj atunci ai vaprecede pe aj ın lista finala. Pentru exemplul nostru, lista liniara finala va putea fi (a1, a0, a2, a3), sau(a1, a2, a0, a3), sau (a1, a2, a3, a0).

Definitia 4.5. Fie (S,≤) o multime partial ordonata finita si a = (a0, a1, . . . , an−1) o liniarizare a sa.Spunem ca secventa a este sortata topologic daca ∀i, j : ai < aj ⇒ i < j.

Teorema 4.7. Orice multime partial ordonata finita (S,≤) poate fi sortata topologic.

Demonstratie. Vom extinde ≤ la o relatie de ordine totala. Fie elementele distincte a, b ∈ S ce nu potfi comparate, i.e. nu are loc nici a < b si nici b < a. Extindem < punand x < y pentru orice x cu x ≤ asi orice y cu b ≤ y. Procedeul continua pana cand sunt eliminate toate perechile incomparabile. sfdem

Exista o stransa legatura ıntre multimile partial ordonate finite si digrafurile aciclice (digrafuri faracircuite numite pe scurt dag-uri). Orice multime partial ordonata (S,≤) defineste un dag D = (S,A)

Page 85: algoritmi_tehnici_dorel lucanu - carte

88 CAPITOLUL 4. SORTARE INTERNA

unde exista arc de la a la b daca a < b si nu exista c ∈ S astfel ıncat a < c < b. Reciproc, orice dagD = (V,A) defineste o relatie de ordine partiala ≤ peste V data prin: u ≤ v daca exista un drum delungime ≥ 0 de la u la v. De fapt, ≤ este ınchiderea reflexiva si tranzitiva a lui A (se mai noteaza≤ = A∗). Sortarea topologica a unui dag consta ıntr-o lista liniara a varfurilor astfel ıncat daca exista arcde la u la v atunci u precede pe v ın lista, pentru oricare doua varfuri u si v. Varfurile care candideazapentru primul loc ın lista sortata topologic au proprietatea ca nu exista arce incidente spre interior (caresosesc ın acel varf) si se numesc surse.

Exista mai multe metode de a sorta topologic un dag. Prima are ca punct de plecare algoritmul deexplorare DFS a unui graf. Reamintim ca ın timpul explorarii DFS, un varf poate fi ıntalnit de maimulte ori. Notam cu f [v] momentul cand varful v este ıntalnit ultima data (cand lista de adiacenta esteepuizata). Algoritmul este descris schematic astfel:

• Apeleaza algoritmul DFS pentru a determina momentele de terminare f [v] pentru orice varf v.

• De fiecare data cand un varf este terminat este adaugat la ınceputul unei listei ınlantuite.

• Lista ınlantuita finala va contine o sortare topologica a varfurilor.

Corectitudinea algoritmului se bazeaza pe urmatorul rezultat.

Lema 4.1 ([CLR93]) Un digraf D este aciclic daca si numai daca explorarea DFS nu produce arceınapoi.

Exercitiul 4.4.1. Sa se scrie un program sortareTopologicaDFS(D, S) care implementeaza algoritmulde mai sus. Sa se arate ca algoritmul are complexitatea Θ(#V + #A).

Cea de-a doua metoda pe care o studiem aici este o generalizare a explorarii BFS. Presupunem capentru dag-ul D sunt create atat listele de adiacenta interioare cat si cele exterioare. Listele de adiacentainterioara vor fi utilizate la determinarea surselor. Ca si BFS, algoritmul de sortare topologica va utilizao coada.

• Initializeaza coada cu varfurile sursa (cele care au listele de adiacenta interioara vide).

• Extrage un varf u din coada pe care-l adauga la lista sortata partial.

• Elimina din reprezentarea (acum partiala) a lui D varful u si toate arcele (u, v). Daca pentru astfelde arc, lista de adiacenta interioara a varfului v devine vida, atunci v va fi adaugat la coada.

• Repeta pasii 2 si 3 pana cand coada devine vida.

Exercitiul 4.4.2. Sa se scrie un program sortareTopologicaBFS(D, S) care implementeaza algoritmulde mai sus. Sa se compare eficienta acestui algoritm cu cea a algoritmului sortareTopologicaDFS. Deasemenea, sa se compare ordinea varfurilor ın listele determinate de cei doi algoritmi.

Exercitiul 4.4.3. Ce se ıntampla cu cei doi algoritmi daca digraful de intrare are circuite?

4.5 Referinte bibliografice

Acest capitol cuprinde numai o parte dintre algoritmii de sortare interna. Alti doi algoritmi importanti,sortarea prin interclasare si sortarea rapida, sunt prezentati ın capitolul dedicat metodei divide-et-impera.O prezentare aproape completa (dar care trebuie actualizata) este [Knu76]. Algoritmii de sortare, datoritaimportantei lor, sunt prezentati ın toate cartile dedicate studierii algoritmilor [Sed88, CLR93, Baa78,Mel84a, AHU74, HS84, LG86]. Aceasta editie nu include algoritmi de sortare externa. Pentru cititorulinteresat recomandam [Knu76, Sed88, Baa78].

Page 86: algoritmi_tehnici_dorel lucanu - carte

Capitolul 5

Cautare

Alaturi de sortare, cautarea ın diferite structuri de date constituie una din operatiile cele mai des utilizateın activitatea de programare. Problema cautarii poate ımbraca diferite forme particulare:

• dat un tablou (s[i] | 0 ≤ i < n) si un element a, sa se decida daca exista i ∈ 0, . . . , n− 1 astfelıncat s[i] = a;

• data o lista ınlantuita (liniara, arbore, etc.) si un element a, sa se decida daca exista un nod ınlista a carui informatie este egala cu a;

• dat un fisier si un element a, sa se decida daca exista o componenta a fisierului care este egala cu a;

• etc.

In plus, fiecare dintre aceste structuri poate avea sau nu anumite proprietati:

• informatiile din componente sunt distincte doua cate doua sau nu;

• componentele sunt ordonate ın conformitate cu o relatie de ordine peste multimea informatiilor saunu;

• cautarea se poate face pentru toata informatia memorata ıntr-o componenta a structurii sau numaipentru o parte a sa numita cheie;

• cheile pot fi unice (ele identifica ın mod unic componentele) sau multiple (o cheie poate identificamai multe componente);

• ıntre oricare doua cautari structura de date nu sufera modificari (aspectul static) sau poate faceobiectul operatiilor de inserare/stergere (aspectul dinamic).

Aici vom discuta numai o parte dintre aceste aspecte. Mai ıntai le consideram pe cele incluse ınurmatoarea formulare abstracta:

Instanta o multime univers U, o submultime S ⊆ U si un element a din U;Intrebare x ∈ S ?

Aspectul static este dat de cazul cand ıntre oricare doua cautari multimea S nu sufera nici o modificare.Aspectul dinamic este obtinut atunci cand ıntre doua cautari multimea S poate face obiectul urmatoareloroperatii:

• Inserare.

Intrare S, x;Iesire S ∪ x.

• Stergere.

Intrare S, x;Iesire S \ x.

Evident, realizarea eficienta a cautarii si, ın cazul aspectului dinamic, a operatiilor de inserare si destergere, depinde de structura de date aleasa pentru reprezentarea multimii S.

89

Page 87: algoritmi_tehnici_dorel lucanu - carte

90 CAPITOLUL 5. CAUTARE

Tip de date Implementare Cautare Inserare StergereLista liniara Tablouri O(n) O(1) O(n)

Liste ınlantuite O(n) O(1) O(1)Lista liniara ordonata Tablouri O(log2 n) O(n) O(n)

Liste ınlantuite O(n) O(n) O(1)

Figura 5.1: Complexitatea pentru cazul cel mai nefavorabil

5.1 Cautare ın liste liniare

Multimea S este reprezentata printr-o lista liniara. Daca multimea U este total ordonata, atunci Spoate fi reprezentata de o lista liniara ordonata. Algoritmii corespunzatori celor trei operatii au fost dejaprezentati ın sectiunile 3.1 si respectiv 3.2. Complexitatea timp pentru cazul cel mai nefavorabil estedependenta de implementarea listei. Tabelul 5.1 include un sumar al valorilor acestei complexitati. Facemobservatia ca valorile pentru operatiile de inserare si steregere nu presupun si componenta de cautare.In mod obisnuit, un element x este adaugat la S numai daca el nu apare ın S; analog, un element xeste sters din S numai daca el apare ın S. Deci ambele operatii ar trebui precedate de cautare. In acestcaz, la valorile complexitatilor pentru inserare si stergere se adauga si valoarea corespunzatoare pentrucautare. De exemplu, complexitatea ın cazul cel mai nefavorabil pentru inserare ın cazul ın care S estereprezentata prin tablouri neordonate devine O(n) iar pentru cazul tablourilor ordonate ramane aceeasi,O(n).

Pentru calculul complexitatii medie vom presupune ca a ∈ S cu probabilitatea q si ca a poate apareaın S la adresa adr cu aceeasi probabilitate q

n . Complexitatea medie a cautarilor cu succes (a este gasitın S) este:

Tmed,s(n) =3q(1 + 2 + · · ·+ n)

n+ 2q =

3q(n+ 1)2

+ 2q

iar ın cazul general avem:

Tmed(n) = 3n− 3nq2

+3q2

+ 2

Cazul cand se ia ın considerare frecventa cautarilor. Presupunem ca xi este cautat cu frecventafi. Se poate demonstra ca se obtine o comportare ın medie buna atunci cand f1 ≥ · · · ≥ fn. Dacaaceste frecvente nu se cunosc aprioric, se pot utiliza tablourile cu auto-organizare. Intr-un tablou cuauto-organizare, ori de cate ori se cauta pentru un a = s[i], acesta este deplasat la ınceputul tabloului ınmodul urmator: elementele de pe pozitiile 1, . . . , i− 1 sunt deplasate la dreapta cu o pozitie dupa care sepune a pe prima pozitie. Daca ın loc de tablouri se utilizeaza liste ınlantuite, atunci deplasarile la dreaptanu mai sunt necesare. Se poate arata [Knu76] ca pentru tablourile cu auto-organizare complexitatea medieeste:

Tmed,s(n) ≈ 2nlog2 n

5.2 Modelul de calcul al arborilor de decizie pentru cautare

In aceasta sectiune definim o clasa de algoritmi bazati pe paradigma “divide-et-impera” si aratam caalgoritmul de cautare binara este optim ın aceasta clasa.

Presupunem ca multimea S este reprezentata de tabloul (s[i] | 0 ≤ i ≤ n− 1). Mai ıntai generalizamproblema presupunand ca se cauta a ın secventa (s[p], . . . , s[q]). Reamintim ca are loc s[p] < · · · <s[q]. Algoritmii de cautare bazati pe paradigma divide-et-impera au o descriere recursiva definita dupaurmatoarea strategie:

• se determina m cu p ≤ m ≤ q;

• daca a = s[m] atunci cautarea se termina cu succes;

• daca a < s[m] atunci cautarea continua cu subsecventa (s[p], . . . , s[m− 1]);

Page 88: algoritmi_tehnici_dorel lucanu - carte

5.2. MODELUL DE CALCUL AL ARBORILOR DE DECIZIE PENTRU CAUTARE 91

• daca a > s[m] atunci cautarea continua cu subsecventa (s[m+ 1], . . . , s[q]);

O schema procedurala nerecursiva care descrie strategia de mai sus este urmatoarea:

function poz(s, n, a)begin

1: p ← 0 q ← n-1

2: alege m ıntre p si q

3: while ((a = s[m]) and (p < q)) do4: if (a < s[m])

then q ← m-1else p ← m+1

5: alege m ıntre p si q

6: if (a = s[m])then return melse return -1

end

In functie de modul de alegere a valorii m prin instructiunile 2 si 5, se disting mai multi algoritmi decautare. Cei mai cunoscuti dintre acestia sunt:

• Cautare liniara. Se alege m = p.

• Cautare binara. Se alege m = p+ q2 .

• Cautare Fibonacci. Se presupune q+1−p = Fib(k)−1 unde Fib(k) este la k-lea numar Fibonacci.Se alege m astfel ıncat m− p = Fib(k − 1)− 1 si q −m = Fib(k − 2)− 1.

Numarul de comparatii pentru cazul cel mai nefavorabil este:

• Cautare liniara: O(n).

• Cautare binara: O(log2 n).

• Cautare Fibonacci: O(log2 n)

Pentru a studia complexitatea medie si criterii de optimalitate este necesar sa precizam formal modelulde calcul. Acesta corespunde arborilor de decizie pentru cautare definiti de schema procedurala de maisus.

Definitia 5.1. Arborele de decizie pentru cautare de dimensiune n atasat unui algoritm bazat pe metodadivide-et-impera este definit dupa cum urmeaza:

• Mai ıntai se defineste recursiv arborele T (p, q) astfel:

– daca p > q atunci T (p, q) este arborele vid;

– altfel, radacina este m calculata de algoritmul utilizate de instructiunea 2 sau 5, iar subarborelestang este T (p,m− 1) si cel drept este T (m+ 1, q).

• Arborele de decizie pentru cautare de dimensiune n este T (0, n − 1) la care se adauga varfurileexterne avand ca etichete intervalele (−∞, X0), (X0, X1), . . . , (Xn−1,+∞) ın aceasta ordine de lastanga la dreapta, unde X0, . . . , Xn−1 sunt n variabile.

Calculul unui arbore de decizie pentru intrarea x0, . . . , xn−1, a, unde x0 < · · · < xn−1, consta ın:

1. etichetarea nodurilor interne cu x0, . . . , xn−1 astfel ıncat lista inordine ne da ordinea crescatoare aetichetelor, si

2. parcurgerea unui drum de la radacina spre frontiera determinat astfel: daca varful curent v esteetichetat cu xm (vom vedea ca m este dat de instructiunea 2 sau 5 din schema procedurala divide-et-impera) atunci:

Page 89: algoritmi_tehnici_dorel lucanu - carte

92 CAPITOLUL 5. CAUTARE

(a) daca v este varf extern etichetat (Xi, Xi+1) atunci a ∈ (xi, xi+1) (variabila Xi este interpretataca avand valoarea xi) si calculul se termina cu insucces;

(b) daca a = xm atunci calculul se termina cu succes;(c) daca a < xm atunci radacina subarborelui stang devine varf curent;(d) daca a > xm atunci radacina subarborelui drept devine varf curent.

Exemplu: Arborele corespunzator cautarii liniare pentru n = 4 este reprezentat ın fig. 5.2 iar celcorespunzator cautarii binare pentru n = 6 este reprezentat ın fig. 5.3. sfex

0

1

2

3

(−∞, X0)

(X0, X1)

(X1, X2)

(X2, X3) (X3,+∞)

Figura 5.2: Arborele corespunzator cautarii liniare

3

1 5

0 2 4

(−∞, X0) (X0, X1) (X1, X2) (X2, X3) (X3, X4) (X4, X5) (X5,+∞)

Figura 5.3: Arborele corespunzator cautarii binare

Varfurile de pe frontiera unui arbore de decizie pentru cautare se mai numesc si varfuri pendante. Incontinuare prezentam cateva proprietati ale arborilor de decizie pentru cautare.

Lema 5.1. Fie t arborele de decizie pentru cautare cu n varfuri corespunzator cautarii binare. Daca2h−1 ≤ n < 2h, atunci ınaltimea lui t este h.

Demonstratie. Procedam prin inductie dupa n. Daca n = 1, atunci sfirmatia din lema este evidentadevarata. Presupunem n > 1. Valoarea m corespunzatoare radacinii este n2 . Din definitia partiiıntregi superioare rezulta urmatoarele inegalitati:

2h−2 ≤ m < 2h−1 + 1. (5.1)

Subarborii radacinii au m si respectiv n − m − 1 varfuri astfel ıncat m − 1 ≤ n − m − 1 ≤ m. Dacam = n − m − 1, atunci m = n− 1

2 . Deoarece n ≤ 2h − 1, rezulta ca m ≤ 2h−1 − 1 < 2h−1. Dacam − 1 = n − m − 1, atunci m = n

2 < 2h−1. Rezulta m < 2h−1 ın toate cazurile. Aplicand ipotezainductiva, rezulta ca subarborele cel mai ınalt (cel cu m varfuri si aflat la stanga radacinii) are ınaltimeah− 1. Din definitia ınaltimii arborelui binar, rezulta ca ınaltimea lui t este h. sfdem

Page 90: algoritmi_tehnici_dorel lucanu - carte

5.2. MODELUL DE CALCUL AL ARBORILOR DE DECIZIE PENTRU CAUTARE 93

Corolar 5.1. Complexitatea timp pentru cazul cel mai nefavorabil al cautarii binare este O(log2 n).

Definitia 5.2. Fie t un arbore de decizie pentru cautare. Lungimea interna a lui t, notata LungInt(t),este suma lungimilor drumurilor de la radacina la varfurile interne. Lungimea externa a lui t, notataLungExt(t), este suma lungimilor drumurilor de la radacina la varfurile de pe frontiera (pendante).

Lema 5.2. Fie t un arbore de decizie pentru cautare cu n varfuri interne. Atunci:

LungExt(t)− LungInt(t) = 2n.

Demonstratie. Procedam prin inductie dupa n. Pentru n = 1 avem LungInt(t) = 0 si LungExt(t) = 2.Presupunem n > 1. Fie i un varf intern cu ambii fii pe frontiera. Inlocuim subarborele:

(X,Y ) (Y, Z)

i

cu subarborele:

(X,Z)

Noul arbore t′ este un arbore de decizie cu n− 1 varfuri interne si conform ipotezei inductive avem

LungExt(t′)− LungInt(t′) = 2(n− 1).

Deoarece LungExt(t) = LungExt(t′) + k + 2 si LungInt(t) = LungInt(t′) + k, unde k este lungimeadrumului de la radacina la i, rezulta:

LungExt(t)− LungInt(t) = LungExt(t′) + k + 2− (LungInt(t′) + k)= 2n− 2 + k + 2− k= 2n.

sfdem

Lema 5.3. Lungimea interna minima a unui arbore de decizie cu n varfuri interne este:

(n+ 1)(h− 1)− 2h + 2

unde h = log2(n+ 1).

Demonstratie. Consideram formula:

x+ x2 + · · ·+ xk =xk+1 − x

x− 1.

Derivam:

1 + 2x+ · · ·+ kxk−1 =kxk+1 − (k + 1)xk + 1

(x− 1)2.

Inmultim cu x:

x+ 2x2 + · · ·+ kxk = x · kxk+1 − (k + 1)xk + 1

(x− 1)2.

Page 91: algoritmi_tehnici_dorel lucanu - carte

94 CAPITOLUL 5. CAUTARE

Luam k = h− 1 si x = 2:

2 + 2 · 22 + · · ·+ (h− 1) · 2h−1 = 2h(h− 2) + 2.

Lungimea interna minima a unui arbore de decizie este suma primilor n termeni din seria:

0 + 1 + 1 + 2 + 2 + 2 + 2 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + · · ·

si corespunde arborelui binar complet. Daca presupunem n+ 1 = 2h atunci aceasta suma este egala cu:

2 + 2 · 22 + · · ·+ (h− 1)2h−1 = 2h(h− 2) + 2.

Pentru cazul general trebuie sa scadem suma drumurilor care unesc radacina cu varfurile de pe nivelul hcare lipsesc:

2h(h− 2) + 2− (2h − 1− n)(h− 1) = (n+ 1)(h− 1)− 2h + 2.

sfdem

Corolar 5.2. Lungimea externa minima a unui arbore de decizie este

(n+ 1)(h+ 1)− 2h.

Demonstratie. Se aplica lemele precedente. sfdem

Teorema 5.1. Problema cautarii are complexitatea timp ın cazul cel mai nefavorabil Ω(logn) ın modelularborilor de decizie pentru cautare.

Demonstratie. Arborele binar cu lungimea interna minima considerat ı lema 5.3 are si ınaltime minima.Acum concluzia teoremei rezulta din faptul ca 2h−1 ≤ n < 2h, unde n este numarul de noduri iar h esteınaltimea arborelui. sfdem

Presupunem ca orice xi este cautat cu aceeasi probabilitate qn si ca a poate apartine la oricare din

intervalele (xi, xi+1) (presupunem x0 = −∞, xn+1 = ∞) cu aceeasi probabilitate 1− qn+ 1. Cu aceste

ipoteze, complexitatile medii sunt date de urmatoarea lema:

Teorema 5.2. Fie t un arbore de decizie pentru cautare. Complexitatea timp medie a cautarilor este:

Tmedt (n) =

2(n+ q)n(n+ 1)

· LungExt(t) + 1− 4q.

Demonstratie. O cautare consta ın parcurgerea unui drum de la radacina spre frontiera. Deoarece ınfiecare nod se fac doua comparatii iar la sfrsit ınca o comparatie, rezulta urmatoarea formula pentrucomplexitatea medie:

Tmedt (n) = 1 + q

n · 2 · LungInt(t) +1− qn+ 1 · 2 · LungExt(t)

= . . .

= 2(n+ q)n(n+ 1) · LungExt(t) + 1− 4q.

sfdem

Teorema 5.3. Cautarea binara este optima din punct de vedere al complexitatii medii ın modelul arbo-rilor de decizie pentru cautare.

Demonstratie. Se observa ca arborele de decizie asociat cautarii binare are lungimea externa minima.sfdem

Corolar 5.3. Complexitatea medie pentru cautarea binara este Θ(log2 n).

Corolar 5.4. Problema cautarii are complexitatea timp medie Ω(logn) ın modelul arborilor de deciziepentru cautare.

Page 92: algoritmi_tehnici_dorel lucanu - carte

5.3. ARBORI BINARI DE CAUTARE 95

5.2.1 Cautare prin interpolare

Sa presupunem ca avem de cautat un cuvant w ıntr-un dictionar. In general procedam astfel: Deschidemdictionarul la ıntamplare. Daca observam ca pagina la care am deschis contine cuvinte mai mici decat w(ın ordinea lexicografica indusa de cea alfabetica) atunci vom sari un numar de pagini suficient de marepentru a ne apropia de cuvantul cautat w. In cazul ın care pagina deschisa contine cuvinte mai marise sare un numar de pagini ınapoi. Procedeul continua pana cand se gaseste pagina care contine pe w.Numarul de pagini sarit la fiecare pas depinde de distanta la care se afla w fata de cuvintele de pe paginacurenta.

Metoda de cautare prin interpolare se bazeaza pe ideea de mai sus. Descrierea algoritmului este datade schema de la metoda divide-et-impera unde m se determina prin formula:

m = (p− 1) +⌈

a− s[p− 1]s[q + 1]− s[p− 1]

(q + 1− p)⌉.

Este necesar de considerat doua elemente artificiale s[−1] si s[n] cu s[−1] < s[0] si s[n− 1] < s[n].De remarcat ca algoritmului de cautare prin interpolare nu-i putem atasa un arbore de decizie care sa

fie determinat numai de numarul n de elemente din S, deoarece acesta depinde si de modul de dispersieal elementelor din S. De aceea, instrumentele prin care se analizeaza aceasta metoda difera de celede la divide-et-impera. Se poate alege S si a astfel ıncat cautarea prin interpolare sa degenereze ıncautare liniara. De aici rezulta ca are o complexitate O(n) ın cazul cel mai nefavorabil. In ipoteza caelementele x0, . . . , xn−1 sunt repartizate uniform ın intervalul [x−1, xn] (x−1 = s[−1], xn = s[n]) rezultao complexitate medie O(log logn) [Mel84a].

5.3 Arbori binari de cautare

Arborii T (0, n−1) din definitia arborilor de decizie pentru cautare sunt transformati ın structuri de dateınlantuite asemanatoare cu cele definite ın sectiunea 5.2. Aceste structuri pot fi definite ıntr-o manieraindependenta:

Definitia 5.3. Un arbore binar de cautare este un arbore binar cu proprietatile:

1. informatiile din noduri sunt elemente dintr-o multime total ordonata;

2. pentru fiecare nod v, elementele memorate ın subarborele stang sunt mai mici decat valoarea mem-orata ın v iar elementele memorate ın subarborele drept sunt mai mari decat valoarea memorata ınv.

In continuare descriem implementarile celor trei operatii peste aceasta structura.

Cautare. Operatia de cautare ıntr-un asemenea arbore este descrisa de urmatoarea procedura:

function poz(t, a)begin

p ← twhile ((p = NULL) and (a = p->elt)) doif (a < p->elt)then p ← p->stgelse p ← p->drpreturn p

end

Functia poz ia valoarea NULL daca a ∈ S si adresa nodului care contine pe a ın caz contrar.Operatiile de inserare si de stergere trebuie sa pastreze invarianta urmatoarea proprietate:

valorile din lista inordine a nodurilor arborelui trebuie sa fie ın ordine crescatoare.

Page 93: algoritmi_tehnici_dorel lucanu - carte

96 CAPITOLUL 5. CAUTARE

Pentru a realiza operatia de inserare se cauta intervalul la care apartine x. Daca ın timpul procesului decautare se gaseste un nod ∗p cu p->elt = x atunci arborele nu sufera nici o modificare (deoarece x ∈ Simplica S ∪ x = S). Fie p adresa nodului de pe frontiera care defineste intervalul. Daca x < p->eltatunci x se adauga ca succesor la stanga; ın caz contrar se adauga ca succesor la dreapta. Un exemplueste aratat ın fig. 5.4.

Algoritmul care realizeaza operatia de inserare are urmatoarea descriere:

procedure insereaza(t, x)begin

if (t = NULL)then t ← nodNou(x)else q ← t

while (q = NULL) dop ← qif (x < q->elt)then q ← q->stgelse if (x > q->elt)

then q ← q->drpelse q ← NULL

if (p->elt = x)then q ← nodNou(x)

if (x < p->elt)then p->stg ← qelse p->drp ← q

end

Funtia nodNou() creeaza un nod al arborelui binar si ıntoarce adresa acestuia:

function nodNou(x)begin

new(p)p->elt ← xp->stg ← NULLp->drp ← NULLreturn p

end

15

823

5 13 20

5 13 20

10

15

8 23

Figura 5.4: Inserare ıntr-un arbore binar de cautare

Operatia de stergere se realizeaza ıntr-un mod asemanator. Se cauta x ın arborele care reprezintamultimea S. Daca nu se gaseste un nod ∗p cu p->elt = x atunci arborele ramane neschimbat (deoarecex ∈ S implica S \ x = S). Fie p referinta la nodul care contine pe x. Se disting urmatoarele trei cazuri:

1. ∗p nu are fii (fig. 5.5a). Se sterge nodul ∗p.

Page 94: algoritmi_tehnici_dorel lucanu - carte

5.3. ARBORI BINARI DE CAUTARE 97

2. ∗p are un singur fiu (fig. 5.5b). Parintele lui ∗p este legat direct la fiul lui ∗p.

3. ∗p are doi fii (fig. 5.5c). Se determina cea mai mare valoare dintre cele mai mici decat x. Fieaceasta y. Ea se gaseste memorata ın ultimul nod ∗q din lista inordine a subarborelui din stanga lui∗p. Se transfera informatia y ın nodul ∗p dupa care se elimina nodul ∗q ca ın primele doua cazuri.

In n cazurile 1 si 2 trebuie prevazute si situatiile cand p = t (∗p este radacina arborelui). Urmatoareaprocedura descrie algoritmul care rezolva aceste doua cazuri:

procedure elimCaz1sau2(prep, p)begin

if (p=t)then if (t->stg = NULL)

then t ← t->stgelse t ← t->drp

else if (p->stg = NULL)then if (predp->stg = p)

then predp->stg← p->stgelse predp->drp← p->stg

else if (predp->stg = p)then predp->stg← p->drpelse predp->drp← p->drp

delete(p)end

Acum algoritmul de cautare are urmatoarea descriere:

procedure elimina(t, x)begin

if (t = NULL)then p ← t

while ((p = NULL) and (x = p->elt)) dopredp ← pif (x < p->elt)then p ← p->stgelse p ← p->drp

if (p = NULL)then if (p->stg = NULL) or (p->drp = NULL)

then elimCaz1sau2(prep, p)else q ← p->stg

predq ← pwhile (q->drp = NULL) do

predq ← qq ← q->drp

p->elt ← q->eltelimCaz1sau2(predq, q)

end

De remarcat ca ambele operatii, inserarea si eliminarea, necesita o etapa de cautare.

Observatie: Structura de date utilizata aici se mai numeste si arbore binar de cautare orientat pe noduriinterne. Aceasta denumire vine de la faptul ca elementele lui S corespund nodurilor interne ale arboreluide cautare. Nodurile externe ale acestuia, care au ca informatie intervalele deschise corespunzatoarecautarilor fara succes, nu au mai fost incluse ın definitia structurii de date din urmatoarele motive:simplitate a prezentarii, economie de memorie si, atunci cand intereseaza, intervalele pot fi determinateın timpul procesului de cautare. Sugeram cititorului, ca exercitiu, sa modifice algoritmul de cautare astfelıncat, ın cazul cautarilor fara succes, sa ofere la iesire intervalul deschis la care apartine a.

Mai exista o varianta a structurii, numita arbore binar de cautare orientat pe frontiera, ın care ele-mentele lui S sunt memorate atat ın nodurile interne cat si ın nodurile de pe frontiera. Informatiile din

Page 95: algoritmi_tehnici_dorel lucanu - carte

98 CAPITOLUL 5. CAUTARE

p x

p y

A By A’ B

p x

p

p x

p

A

A

a) Fara fii

b) Un fiu

c) Doi fii

Figura 5.5: Stergere dintr-un arbore binar de cautare

nodurile de pe frontiera sunt ın ordine crescatoare de la stanga la dreapta si putem gandi ca ele core-spund intervalelor (−∞, x0], (x0, x1], . . . , (xn−1 +∞). Algoritmul de cautare ıntr-o astfel de structurava face testul p->val = a numai daca ∗p este un nod pe frontiera. In caz cand avem egalitate rezultaca a apartine multimii S; altfel a apartine intervalului deschis marginit la dreapta de p->elt. PentruS = 5, 8, 13, 15, 20, 23, structura de date este reprezentata schematic ın fig. 5.6. sfobs

Exercitiul 5.3.1. Sa se descrie proceduri pentru operatiile de cautare, inserare si stergere pentru arboribinari de cautare orientati pe frontiera. Operatiile vor pastra proprietatea ca fiecare nod sa aiba exactdoi fii.

5.4 Tipuri de data avansate pentru cautare

5.4.1 Arbori echilibrati

Consideram arbori binari de cautare. Este posibil ca ın urma operatiilor de inserare si de stergere structuraarborelui binar de cautare sa se modifice foarte mult si operatia de cautare sa nu mai poata fi executataın timpul O(log2 n). Un exemplu ın care cautarea binara degenereaza ın cautare liniara este aratat ınfig. 5.7. Suntem interesati sa gasim algoritmi pentru insertie si stergere care sa mentina o structura“echilibrata” a arborilor astfel ıncat operatia de cautare sa se execute ın timpul O(log n) totdeauna. Maiıntai definim formal astfel de clase. Mentionam ca ın definitiile urmatoare nu este necesar ca arborii safie binari; ei pot fi de diferite aritati.

Reamintim ca ınaltimea unui arbore t, pe care o notam cu h(t), este lungimea drumului maxim de laradacina la un varf de pe frontiera.

Definitia 5.4. Fie C o multime de arbori. C se numeste clasa de arbori echilibrati (balansati) dacapentru orice t ∈ C, ınaltimea lui t este mai mica decat sau egala cu c · logn, unde c este o constanta cepoate depinde de clasa C (dar nu depinde de t) si n este numarul de varfuri din t.

Page 96: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 99

5 8

5

13 15 20 23

8

13

15

20

Figura 5.6: Arbore orientat pe frontiera

Definitia 5.5. O clasa C de arbori echilibrati se numeste O(log n)-stabila daca exista algoritmi pentruoperatiile de cautare, inserare si de stergere care necesita timpul O(log n) si arborii rezultati ın urmaexecutiei acestor operatii fac parte din clasa C.

In continuare prezentam cateva clase O(log n)-stabile.

5.4.1.1 Arbori AVL

Aceasta clasa a fost definita de G.M. Adelson-Velskii si E.M. Landis ın 1962. In aceasta subsectiunene referim la arbori binari de cautare orientati pe noduri interne. Desi nodurile externe ale arboreluide decizie, corespunzatoare intervalelor deschise, nu sunt incluse ın structura de date, le consideram ladeterminarea ınaltimii (fig. 5.8).

Definitia 5.6. Un arbore binar este AVL-echilibrat (pe scurt arbore AVL) daca pentru orice varf,diferenta dintre ınaltimea subarborelui din stanga varfului si cea a subarborelui din dreapta este −1, 0sau 1. Numim aceasta diferenta factor de echilibrare.

Urmatorul rezultat arata ca arborii AVL sunt echilibrati.

Teorema 5.4. Pentru orice arbore AVL t, cu n noduri interne, are loc h(t) = Θ(log2 n).

Demonstratie. Un arbore binar de ınaltime h are cel mult 2h varfuri pe frontiera si cel mult 2h − 1varfuri interne. De aici rezulta:

h ≥ log2(n+ 1) = Ω(log2 n) (5.2)

Pentru a determina cea de-a doua margine, vom afla mai ıntai structura unui arbore AVL de ınaltime hsi cu numar minim de noduri. Notam acest arbore cu tmh . Procedam prin inductie dupa h. Daca h = 1atunci tm1 este format dintr-un singur nod intern corespunzator elementului x1 si doua pe frontiera core-spunzatoare intervalelor (−∞, x0) si (x0,+∞). Daca h = 2 atunci tm2 are 2 noduri interne corespunzatoareelementelor x0 < x1 si 3 varfuri pe frontiera corespunzatoare intervalelor (−∞, x0), (x0, x1), (x1,+∞).Remarcam ca tm1 are Fib(3)− 1 noduri interne iar tm2 are Fib(4)− 1 noduri interne, unde Fib(k) este alk-lea numar Fibonacci. Presupunem h > 2. Presupunem ca subarborele din stanga radacinii lui tmh areınaltimea h− 1 si subarborele din dreapta radacinii are ınaltimea h − 2 (deoarece tmh are numar minimde noduri, rezulta ca nu pot avea ambii ınaltimea h − 1). Deoarece tmh are numar minim de noduri,rezulta ca subarborii radacinii au numar minim de noduri. Fara sa restrangem generalitatea putempresupune ca acesti subarbori sunt tmh−1 si tmh−2. Rezulta ca numarul de varfuri interne ale lui tmh esteFib(h + 1) − 1 + Fib(h) − 1 + 1 = Fib(h + 2) − 1. Deci tmh coincide cu al h + 2-lea arbore Fibonacci.Rezulta:

n ≥ Fib(h+ 2)− 1 = Φh+2

√5

+12 − 1 >

Φh+2

√5− 3

2(5.3)

Page 97: algoritmi_tehnici_dorel lucanu - carte

100 CAPITOLUL 5. CAUTARE

15

8 23

5 13 20

15

8 23

5 13 20

10

15

8

5 13

10

15

8 23

13

10

15

8 23

13

10

12

15

8

13

10

12

23

→ → →

→ → →

Figura 5.7: Degenerarea cautarii binare ın cautare liniara

1

2

3

4

1

h(t) = 1 h(t) = 3

Figura 5.8: Calculul ınaltimii arborilor AVL

unde1 Φ = 1 +√5

2 . Din (5.3) obtinem:

h <1

log2 Φ· log2

(√5(n+

32))− 2 = O(log2 n). (5.4)

Relatiile (5.2) si (5.4) implica concluzia din teorema. sfdem

Teorema 5.5. Clasa arborilor AVL este O(log n)-stabila.

Demonstratie. In urma efectuarii unei operatii de inserare sau de stergere singurele noduri care-simodifica factorii de echilibrare sunt cele aflate pe drumul de la radacina la varful inserat/sters. Se mem-oreaza acest drum ıntr-o stiva ın timpul etapei de cautare. Dupa efectuarea operatiei, se parcurge acest

1Numarul 1 +√

52 este cunoscut sub numele de “numarul de aur” (golden ratio), el fiind important atat ın diferite ramuri

ale matematicii cat si ın lumea artei. El a fost notat cu litera greceasca φ ın memoria lui Phidias, despre care se spune caa utilizat acest numar la realizarea sculpturilor sale.

Page 98: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 101

x

A y

B C

y

x

A B

C

Rotatie simpla

x

Ay

z

B C

D

z

x y

A B C D

Rotatie dubla

Figura 5.9: Operatii utilizate la reechilibrare

drum ın sens invers si se reface factorul de echilibru pentru nodurile dezechilibrate. Aceasta presupuneca structura de date sa memoreze si ınaltimile subarborilor pentru fiecare nod. Refacerea factorilor deechilibru se realizeaza cu ajutorul uneia din operatiile din fig. 5.9 sau simetricele acestora. sfdem

Consideram un exemplu. Deoarece ınaltimile subarborilor se modifica cu cel mult 1, rezulta ca factorulde echilibru al unui nod dezechilibrat este -2 sau 2. Presupunem ca varful dezechilibrat x are factorul-2 (fig. 5.10). Din h1 − [max(h2, h3) + 1] = −2 rezulta h1 = max(h2, h3) − 1. Aplicand o rotatsimpla,distingem urmatoarele cazuri:

• ε = −1. Avem:h2 = h3 − 1, h1 = h3 − 1 = h2

α = h1 − h2 = 0β = h2 + 1− h3 = 0

• ε = 0. Avem:h2 = h3, h1 = h2 − 1α = h1 − h2 = −1β = h2 + 1− h3 = 1

• ε = +1. Avem:h2 = h3 + 1, h1 = h2 − 1 = h3

α = h1 − h2 = −1β = h2 + 1− h3 = 2

Deci pentru ultimul caz rotatia simpla nu este potrivita pentru refacerea echilibrului si deci trebuieaplicata o rotatie dubla (fig. 5.11). Din max(h′

2, h′′2) + 1 − h3 = 1 rezulta max(h′

2, h′′2) = h3. Din

−1 ≤ h′2 − h′′

2 ≤ 1 rezulta −1 ≤ h3 − h′′2 ≤ 1. De aici α = h1 − h′

2 ∈ −1, 0, 1, −1 ≤ β = h′′2 − h3 ≤ 1 si

γ = h1 + 1− (h3 + 1) = 0.

Page 99: algoritmi_tehnici_dorel lucanu - carte

102 CAPITOLUL 5. CAUTARE

x

A y

B C

y

x

A B

C

h1

h2

h3

-2

ε

β

α→

Figura 5.10: Reechilibrare cu rotatie simpla

x

Ay

z

B C

D

z

x y

A B C D

-2

+1

γ

α β

h1

h′2 h′′

2

h3

Figura 5.11: Reechilibrare cu rotatie dubla

5.4.1.2 Arbori BB[α]

Definitia 5.7. Fie t un arbore binar de cautare orientat pe noduri interne. Balanta radacinii ρ(t) estedefinita astfel:

• daca t are un singur nod atunci ρ(t) = 12 ;

• altfel, ρ(t) = nstg + 1n+ 1 unde nstg reprezinta numarul de noduri din subarborele din stanga radacinii

iar n este numarul de noduri din t.

Un exemplu cum se calculeaza ρ(t) este aratat ın fig. 5.12.

1

3

5

ρ(t) = 12

ρ(u) = 13 , ρ(v) = 3

7 , ρ(w) = 12

u

v

w1

2

4

6

Figura 5.12: Calculul balantei pentru arbori orientati pe noduri interne

Consideram α o constanta fixata cu 14 < α ≤ 1−

√22 .

Definitia 5.8. Un arbore binar de cautare t este cu balanta marginita de α (pe scurt arbore BB[α])daca:

• α ≤ ρ(t) ≤ 1− α si

• sau t are un singur nod sau ambii subarbori ai radacinii sunt cu balanta marginita de α.

Page 100: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 103

Vom mai scrie t ∈ BB[α] pentru a nota faptul ca t este cu balanta marginita de α.

Urmatorul rezultat arata ca arborii cu balanta marginita sunt echilibrati.

Teorema 5.6. Fie t ∈ BB[α]. Atunci ınaltimea h(t) satisface:

h(t) ≤ 1 +log2(n+ 1)− 1

log2

11− α

unde n este numarul de noduri din t.

Demonstratie. Fie v1, . . . , vh un drum de lungime h = h(t). Notam cu ni numarul de noduri dinsubarborele cu radacina vi. Presupunem ca vi+1 este fiu la stanga lui vi. Atunci:

ρ(vi) =ni+1 + 1ni + 1

≤ 1− α

Daca vi+1 este fiu la dreapta atunci:

ρ(vi) =ni − ni+1

ni + 1≥ α

In ambele situatii rezultani+1 + 1 ≤ (1 − α)(ni + 1)

Rezulta:

2 = nh + 1 ≤ (1− α)(nh−1 + 1) ≤ · · · ≤ (1− α)h−1(n1 + 1) = (1− α)h−1(n+ 1)

care implica1 ≤ (h− 1) log2(1− α) + log2(n+ 1)

Deoarece log2(1− α) < 0 rezulta

(h− 1) log2

11− α

− log2(n+ 1) ≤ −1

care implica concluzia teoremei. sfdem

Urmatoarele rezultate arata ca arborii BB[α] formeaza o clasa O(log n)-stabila [Mel79].

Lema 5.4 (Blum si Melhorn) Fie 0 ≤ δ ≤ 0.01. Atunci exista o functie monoton crescatoare c cu

c(0) = 0, c(0.01) = 0.0045 astfel ıncat daca 14 < α < 1 −

√22 − c(δ) atunci rotatiile simple si duble sunt

suficiente pentru a rebalansa un arbore BB[α] dupa efectuarea unei operatii de inserare sau de stergere aunui varf.

Algoritmul de rebalansare este asemanator cu cel de la arbori AVL. Se parcurge ın sens invers drumul dela radacina la varful inserat/sters si, pentru fiecare varf u, se executa una din operatiile:

1. ρ(u) ∈ [α, 1− α] : se trece la varful tata;

2. ρ(u) < α : fie v fiul aflat la dreapta lui u. Daca

ρ(v) <1

(2− α)+

δ

[1 + (1 + δ)(1− α)](2 − α)

atunci se executa o rotatie simpla; altfel se executa o rotatie dubla. Dupa care are loc ρ′(u), ρ′(v), ρ′(w) ∈[(1+δ)α, 1−(1−δ)α], unde ρ′ noteaza balanta dupa efectuarea rotatiei duble si u, v, w sunt varfurileimplicate ın rotatie.

3. ρ(u) > 1− α; este simetric cazului 2.

Teorema 5.7 (Nievergelt si Reingold, Blum si Melhorn) Clasa arborilor BB[α] este O(log n) sta-bila.

Se poate da chiar si o functie de marginire pentru numarul de operatii de rebalansare.

Teorema 5.8. Fie 211 < α < 1−

√22 −c(δ), 0 ≤ δ ≤ 0.01, unde c este functia definita ın lema precedenta.

Atunci exista o constanta d astfel ıncat sunt suficiente d ·m operatii de rebalansare pentru orice secventade m operatii de inserare sau stergere asupra unui arbore BB[α], care initial este vid.

Page 101: algoritmi_tehnici_dorel lucanu - carte

104 CAPITOLUL 5. CAUTARE

6

8

11

14

15

18

23

Figura 5.13: Arbore bicolor

5.4.1.3 Arbori bicolori

In aceasta subsectiune consideram o clasa de arbori pentru cautare ın care echilibrarea este mentinuta cuajutorul unei colorari adecvate ale nodurilor. De fapt, sunt suficiente numai doua culori pentru a puteadefini o clasa O(log n)-stabila. Deoarece aceste culori au fost initial rosu si negru, arborii sunt cunoscutisub numele de “red-black trees”.

Definitia 5.9. Un arbore bicolor este un arbore binar de cautare care satisface urmatoarele proprietati:

1. Nodurile sunt colorate. Un nod are sau culoarea rosie sau culoarea neagra.

2. Nodurile pendante (acestea sunt considerate ca facand parte din structura) sunt colorate cu negru.

3. Daca un nod este rosu atunci fiii sai sunt colorati cu negru.

4. Pentru orice nod, drumurile de la acel nod la nodurile de pe frontiera au acelasi numar de noduricolorate cu negru.

Un exemplu de arbore bicolor este reprezentat ın fig. 5.13. Nodurile reprezentate cu cercuri albe reprezintanodurile colorate cu rosu. Daca v este un nod ıntr-un arbore bicolor t atunci notam cu hn(v) numarulde noduri negre aflate pe un drum de la v la un nod de pe frontiera, excluzand v. Definitia lui hn nudepinde de alegerea drumului datorita conditiei 4 din definitie.

Lema 5.5. Fie t un arbore bicolor. Orice subarbore al lui t are cel putin 2hn(v)− 1 noduri interne, undev este radacina subarborelui.

Demonstratie. Procedam prin inductie dupa ınaltimea h a subarborelui. Daca h = 0 atunci v estesingurul nod al subarborelui si este un nod pendant. Numarul de noduri interne este 0 si coincide cu2hn(v) − 1 = 20 − 1. Presupunem h > 0. Distingem doua situatii.

1. v este rosu. Atunci fiii lui v sunt negri. Fie x si y fiii lui v. Avem hn(v) = hn(x) + 1 = hn(y) + 1.Din ipoteza inductiva, fiecare subarbore al lui v are cel putin 2hn(v)−1 − 1 noduri interne. Rezultaca t are cel putin 2 · (2hn(v)−1 − 1) + 1 = 2hn(v) − 1 noduri interne.

2. v este negru. Daca x si y sunt ambii rosii atunci hn(v) = hn(x) = hn(y). Din ipoteza inductiva,fiecare subarbore al lui v are cel putin 2hn(v) − 1 noduri interne. Rezulta ca t are cel putin 2 ·(2hn(v) − 1) + 1 > 2hn(v) − 1. Celelalte cazuri se trateaza asemanator.

sfdem

Teorema 5.9. Un arbore bicolor cu n noduri interne are ınaltimea cel mult 2 log2(n+ 1).

Demonstratie. Fie t un arbore bicolor cu radacina v si ınaltimea h. Din lema 5.5 rezulta ca t are celputin 2hn(v)−1 de noduri interne. Din conditia 3 din definitia arborilor bicolori, rezulta ca pe orice drumde la v la un nod de pe frontiera cel putin jumatate din noduri sunt negre. Avem hn(v) ≥ h

2 care implica

n ≥ 2hn(v) − 1 ≥ 2h2 − 1. De aici h ≤ 2 log2(n+ 1). sfdem

Page 102: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 105

B

v

C

u

A

x

D

B

v

C

u

A

x

D

y

E

B

v

C

u

A

x

D

y

E

u

A B

v

C

x

D

x

C D

u

A B

v→

a)

b)

Figura 5.14: Inserarea ıntr-un arbore bicolor – restabilirea proprietatilor

Teorema 5.10. Clasa arborilor bicolori este O(log n)-stabila.

Demonstratie. Din teorema 5.9 rezulta ca operatia de cautare, care se face exact ca la arborii de cautareobnuiti, se realizeaza ın timpul O(log n). Mai trebuie sa aratam ca operatiile de inserare si de stergerepot fi realizate ın timpul O(logn) si ın urma realizarii acestor operatii rezulta arbori bicolori .Inserarea. Este realizata ın doua etape. In prima etapa se face inserarea noului nod exact ca ın cazul

arborilor de cautare obisnuiti. Nodul inserat va primi culoarea rosie. In urma inserarii este posibil caproprietatea 3 din definitie sa nu mai fie respectata de noul arbore. In etapa a doua se restabilesteproprietatea 3 cu ajutorul operatiilor din fig. 5.14 sau a simetricelor lor. Aceste operatii constau ınrecolorari de noduri sau combinatii de rotatii simple.Stergerea. Si aceasta operatie este realizata ın doua etape. Prima etapa seamana cu cea de la arborii decautare obisnuiti dar, acum trebuie tinut cont de faptul ca nodurile pendante fac parte din structura. Inurma stergerii este posibil ca proprietatea 4 din definitie sa nu mai fie respectata de noul arbore. In parteaa doua se restabileste aceasta proprietate cu ajutorul operatiilor din fig. 5.15. Nodurile reprezentate cucercuri duble pot fi rosii sau negre. Cazul a) este transformat ıntr-unul din cazurile b), c), d) printr-orotatie. In cazul b) nodul pentru care nu are loc proprietatea 4 este deplasat spre radacina cu un nivelprin recolorarea unui nod. Cazul c) este transformat ın d) printr-o interschimbare de culori si o rotatie.Aparitia cazului d) si rezolvarea lui conduce la restabilirea proprietatii pentru ıntregul arbore. sfdem

5.4.1.4 2-3 arbori

2-3 arborii constituie o clasa de structuri de date arborescente O(log n)-stabila ce generalizeaza arboriibinari de cautare.

Definitia 5.10. Un 2-3 arbore este un arbore de cautare care satisface urmatoarele proprietati:

Page 103: algoritmi_tehnici_dorel lucanu - carte

106 CAPITOLUL 5. CAUTARE

x

C D

y

A B

v

z

FE

u

x

DC

v

FE

y

u

A B

z

x

C D

y

A B

v

z

FE

u

x

C D

y

A B

v

z

FE

u

a)

b)

Figura 5.15: Stergerea ıntr-un arbore bicolor – restabilirea proprietatilor

1. Fiecare nod intern este de aritate 2 sau 3 (are 2 sau 3 fii). Un nod ∗v de aritate 2 memoreaza osingura valoare v->eltStg, iar un nod de aritate 3 memoreaza doua valori: v->eltStg si v->eltMijcu v->eltStg < v->eltMij.

2. Fiii unui nod ∗v ıi vom numi fiu stanga (notat ∗(v->stg)), mijlociu (∗(v->mij)) si dreapta (∗(v->drp)).Un nod de aritate 2 are fiii stanga si mijlociu.

3. Pentru orice nod intern ∗v de aritate 2, valorile memorate ın subarborele cu radacina ın ∗(v->stg)sunt mai mici decat v->eltStg si valorile din subarborele cu radacina ın ∗(v->mij) sunt mai maridecat v->eltStg.

4. Pentru orice nod intern ∗v de aritate 3 are loc:

• valorile din subarborele cu radacina v->stg sunt mai mici decat v->eltStg;

• valorile din subarborele cu radacina v->mij sunt mai mari decat v->eltStg si mai mici decatv->eltMij;

• valorile din subarborele cu radacina ∗(v->drp) sunt mai mari decat v->eltMij.

5. Toate nodurile de pe frontiera se afla pe acelasi nivel.

Un exemplu de 2-3 arbore este reprezentat grafic ın fig. 5.16. Nodurile reprezentate grafic prin patratenu intra ın definitia reprezentarii, ele avand rolul numai de a sugera mai bine structura de 2-3 arbore. Sepoate stabili o corespondenta ıntre aceste noduri si elementele multimii reprezentate. Facem presupunereaca ın cazul nodurilor de aritate 2, campul v->eltMij sa memoreze o valoare artificiala MaxV al mai maredecat orice element din multimea univers.

Page 104: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 107

x

C D

y

A B

v

z

FE

u

C

D

yA B

v

z

FE

u

c)

x

x

DC

v

FE

y

u

A B

z

x

C D

y

A B

v

z

FE

u

d)

(procesul se termina)

Figura 5.15: Stergerea ıntr-un arbore bicolor – restabilirea proprietatilor (continuare)

Operatia de cautare se realizeaza ıntr-o maniera asemanatoare cu cea de la arborii binari de cautare.Procesul de cautare pentru a ın arborele t pleaca din radacina si ın fiecare nod vizitat ∗v se compara acu valorile memorate ın ∗v:

• daca a = v->eltStg sau a = v->eltMij atunci cautarea se termina cu succes;

• daca subarborele ın care se cauta este vid atunci cautarea se termina cu insucces;

• daca a < v->eltStg atunci procesul de cautare continua ın subarborele cu radacina ın v->stg;

• daca v->eltStg < a < v->eltMij atunci procesul de cautare continua ın subarborele cu radacinaın v->mij;

• daca a > v->eltMij atunci procesul de cautare continua ın subarborele cu radacina ın v->drp.

Algoritmul care realizeaza toate acestea este urmatorul:

function poz(t, a)begin

p ← twhile (p = NULL)

if ((p->eltStg = a) or (p->eltMij = a))then return pelse if (a < p->eltStg)

Page 105: algoritmi_tehnici_dorel lucanu - carte

108 CAPITOLUL 5. CAUTARE

3;∞

1;2 4;5

Figura 5.16: Exemplu de 2-3 arbore

then p ← p->stgelse if (a < p->eltMij)

then p ← p->mijelse p ← p->drp

end

Operatia de inserare este un pic mai complicata si se realizeaza dupa urmatorul scenariu:

1. Se cauta ın arborele t elementul ce urmeaza a fi inserat x. Drumul de la radacina la frontieraparcurs ın timpul cautarii este memorat ıntr-o stiva. Daca x este memorat deja ın t atunci operatiade inserare se termina fara a modifica arborele.

2. In continuare se parcurge ınapoi drumul memorat ın stiva si la fiecare pas se realizeaza o reuniunede doi arbori: unul care are radacina y de aritate 1 si subarborele lui t cu radacina ın nodul ∗vmemorat ın varful stivei. Initial avem y = x si subarborele sau vid. Intalnim urmatoarele cazuri:

(a) Nodul ∗v este de aritate 2. Atunci nodurile y si ∗v fuzioneaza formand un singur nod de aritate3 (fig. 5.17). In acest caz operatia de inserare se termina.

(b) Nodul ∗v este de aritate 3. Notam cu A subarborele lui y, cu B,C,D subarborii lui ∗v si cux1, x2 valorile memorate ın ∗v. Pentru simplitatea prezentarii notam cei doi subarbori prin[y](A) respectiv prin [x1;x2](B,C,D). Nodul ∗v se multiplica ın doua noduri de aritate 2, alecaror roluri ın continuare difera pentru fiecare din urmatoarele subcazuri:

• y < x1. Functie de ce fel de fiu este ∗v, se formeaza urmatoarele perechi de subarbori (fig.5.18):– fiu stanga: [x1]([y](A,B)) si [x2](C,D).– fiu mijlociu sau dreapta: [y](A,B) si [x1]([x2](C,D).

In continuare se considera y = x1.• y > x2. Similar cazului precedent.• x1 < y < x2. Functie de ce fel de fiu este la randul sau tatal lui ∗v, se formeaza urmatoareleperechi de subarbori (fig. 5.19):– fiu stanga: [y]([x1](B,C)) si [x2](A,D).– fiu mijlociu sau dreapta: [x1](B,C) si [y]([x2](A,D).

In continuare y ramane neschimbat.

Daca v = t (∗v este radacina) atunci se creeaza un nou nod care va avea ca fii pe y si ∗v.

Page 106: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 109

A

y x1

B C

∪ → y; x1

A B C

a) y < x1

x1

B C

A

y∪ → x1; y

B C A

b) y > x1

Figura 5.17: Inserare ıntr-un 2-3 arbore: cazul cand v are aritatea 2

A

y x1; x2

B C

∪ → y

A B

x2

C D

D

x1 ∪

A

y x1; x2

B C

∪ → y

A B

x2

C D

D

x1 ∪

A

y x1; x2

B C

∪ → y

A B

x2

C D

D

x1

Figura 5.18: Inserare ıntr-un 2-3 arbore: v de aritate 3 si y < v->eltStg

B C A

→ x1

B C

x2

A D

D

y ∪

x1; x2

∪y

B C A

→ x1

B C

x2

A D

D

y ∪

x1; x2

∪y

B C A

→ x1

B C

x2

A D

D

y ∪

x1; x2

∪y

Figura 5.19: Inserare ıntr-un 2-3 arbore: v de aritate 3 si v->eltStg < y < v->eltMij

Page 107: algoritmi_tehnici_dorel lucanu - carte

110 CAPITOLUL 5. CAUTARE

Stergerea se poate realiza prin urmatoarea strategie:

1. Se cauta ın arborele t elementul ce urmeaza a fi sters x. Drumul de la radacina la frontiera parcursın timpul cautarii este memorat ıntr-o stiva. Daca x nu este ın t atunci operatia de stergere setermina fara a modifica arborele.

2. Fie ∗v nodul unde este memorat x. Distingem situatiile:

(a) ∗v nod pe frontiera (fig: 5.20).

i. ∗v are aritate 3: daca x = v->eltStg atunci se transfera valoarea dinv->eltMij ın v->eltStg si se pune MaxV al ın v->eltMij, iar daca x = v->eltMij atuncise memoreaza MaxV al ın v->eltMij.

ii. ∗v de aritate 2. Putem presupune ca dupa stergere ∗v devine de aritate 1 (are numaisubarborele stanga). Acest tip de nod va fi “deplasat” pe drumul ınapoi spre radacinapana cand este unit cu un frate de aritate 2, sau va avea tatal de aritate 3 sau devineradacina. Deplasarea spre radacina a lui v se face aplicand operatii de tipul celor din fig.5.22. Daca tatal lui ∗v are aritatea 3 atunci se aplica operatia din fig. 5.23 si operatiase termina. La fel, daca la un moment dat ∗v are un frate de aritate 3 atunci se aplicaoperatia din fig. 5.21 si operatia se termina. Daca nodul ∗v de aritate 1 ajunge radacinaatunci se sterge.

(b) ∗v este nod intern. Daca x = v->eltStg atunci se ınlocuieste x cu cea mai mare valoaredin subarborele cu radacina ın v->stg (sau cea mai mica valoare din subarborele cu radacinaın v->mij), iar daca x = v->eltMij atunci se ınlocuieste x cu cea mai mare valoare dinsubarborele cu radacina ın v->mij (sau cea mai mica valoare din subarborele cu radacina ınv->drp). Valoarea care va ınlocui pe x este memorata ıntr-un nod de pe frontiera si, dupaınlocuire, va fi eliminata ca ın primul caz.

Teorema 5.11 ([Cro92]) Clasa 2-3 arborilor este O(log n) stabila.

x;x1 → x1

a) x < x1

x1; x x→ →x1

b) x1 < x c)

Figura 5.20: Stergere ıntr-un 2-3 arbore: x este memorat ıntr-un nod pe frontiera

Page 108: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 111

E

x3; x4

B C D

x1; x2

A D

x3

B C E

x1; x4

A

x2

A

A

x2; x3

x2; x3

D

B

B

C

C

D

x1 :?

x1 :?

E

E

A

A

x1

x3

C

C

D

D

B

B

x3; ?

x2; ?

E

E

x2

x1

Figura 5.21: Stergere ıntr-un 2-3 arbore: rotatii cand v are aritatea 3

A

x2

B C

x1

A

x1; x2

CB

→→

A

x2; x1

CB

A

x2

CB

x1

Figura 5.22: Stergere ıntr-un 2-3 arbore: combinarea nodurilor cand v si tatal sau au aritatea 2

Page 109: algoritmi_tehnici_dorel lucanu - carte

112 CAPITOLUL 5. CAUTARE

E

x4

C D

x1; x2

A

x4; x2

C DB

x1→

x3

A

A

x3

x3

C

B

B

C

x1; x2

x1; x2

A

A

x2; x4

x4

C

C

D

D

B

B

x1

x2

x3

x1; x3

x4

x4

D

D

E

E

x3

A B

E

E

E

Figura 5.23: Stergere ıntr-un 2-3 arbore: combinarea nodurilor cand v are aritatea 2 iar tatal sau aritatea3

5.4.1.5 Exercitii

Exercitiul 5.4.1. Sa se scrie subprograme complete care sa realizeze operatiile de inserare si de stergereıntr-un 2-3 arbore.

Exercitiul 5.4.2. [HSAF93] Sa se defineasca o alternativa orientata pe frontiera la definitia 2-3 arborilor.Fiecare nod de pe frontiera contine exact un element iar semnificatiile valorilor din nodurile interne sunt:v↑.valstg este cea mai mare valoare memorata ıntr-un nod de pe frontiera subarborelui din stanga siv↑.valdrp este cea mai mare valoare memorata ıntr-un nod de pe frontiera subarborelui din mijloc. Deasemenea, toate nodurile de pe frontiera se vor afla pe acelasi nivel.

1. Sa se defineasca o structura de date care sa reprezinte un 2-3 arbore orientat pe frontiera.

2. Sa se scrie subprograme care sa realizeze operatiile de cautare, inserare si stergere ıntr-un 2-3 arborereprezentat ın acest fel.

3. Sa se arate ca noua definitie pastreaza proprietatea de clasa O(log n)-stabila.

Exercitiul 5.4.3. Sa se scrie programe care sa construiasca reprezentarea orientata pe frontiera a unui 2-3 arbore pornind de la reprezentarea pe noduri interne si, reciproc, sa construiasca reprezentarea orientatape noduri interne a unui 2-3 arbore pornind de la reprezentarea pe frontiera.

5.4.2 Dispersia (hashing)

Dispersia este o tehnica aplicata ın implementarea tabelelor de simboluri. O tabela de simboluri esteun tip de date abstract ın care obiectele sunt perechi (nume, atribute) si asupra carora se pot exe-cuta urmatoarele operatii: cautarea unui nume ın tabela, regasirea atributelor unui nume, modificareaatributelor unui nume, inserarea unui nou nume si a atributelor sale si stergerea unui nume si a atributelorsale. Exemple tipice pentru tabelele de simboluri sunt dictionarele de sinonime (tezaurele) (nume =

Page 110: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 113

cuvant si atribute = sinonime) si tabela de simboluri a unui compilator (nume = identificator si atribute= (valoare initiala, lista liniilor ın care apare, etc.)).

Intrucat operatia de cautare se realizeaza dupa nume, notam cu U multimea tuturor numelor. Imple-mentarea tabelelor de simboluri prin tehnica dispersiei presupune:

• un tablou (T[i] | 0 ≤ i ≤ p − 1), numit si tabela de dispersie (hash), pentru memorarea numelor sia referintelor la multimile de atribute corespunzatoare;

• o functie h : U→ [0, p− 1], numita si functie de dispersie (hash), care asociaza unui nume o adresaın tabela.

O submultime S ⊆ U este reprezentata ın modul urmator: pentru fiecare x ∈ S se determina i = h(x) sinumele x va fi memorat ın componenta T [i]. Valoarea functiei de dispersie se mai numeste si index sauadresa ın tabela. Daca pentru doua elemente diferite x si y avem h(x) = h(y), atunci spunem ca ıntrecele doua elemente exista coliziune. Pentru ca operatia de dispersie sa fie eficienta, trebuiesc rezolvatecorect urmatoarele doua probleme: alegerea functiei de dispersie si rezolvarea coliziunilor.

5.4.2.1 Alegerea functiei de dispersie

Prezentam sumar cateva tehnici elementare de alegere a functiei de dispersie.

Trunchierea Se ignora o parte din reprezentarea numelui. De exemplu daca numele sunt reprezen-tate prin secvente de cifre si p = 1000 atunci f(x) poate fi numarul format din ultimele trei cifre alereprezentarii: f(62539194) = 194.

“Folding” Reprezentarea numelui este partitionata ın cateva parti si apoi aceste parti sunt combinatepentru a obtine indexul. De exemplu, reprezentatarea 62539194 este partitionata ın partile 625, 391 si 94.Combinarea partilor ar putea consta, de exemplu, ın adunarea lor: 625+ 391+ 94 = 1110. In continuarese poate aplica si trunchierea:1110 → 110. Deci f(62539194) = 110.

Aritmetica modulara Se converteste reprezentarea numelui ıntr-un numar si se ia ca rezultat restulımpartirii la p. Este de preferat ca p sa fie prim, pentru a avea o repartizare cat mai uniforma a elementelorın tabela.

Exemplu: Presupunem ca un nume este reprezentat printr-un sir de caractere de lungime cel mult 30.

function hash(x)begin

h ← 0for i ← 0 to lung(x) do

h ← h + ord(x)return h%p

end

sfex

Multiplicare Fie w cel mai mare numar ce poate fi memorat ıntr-un cuvant al calculatorului (deexemplu w = 232 daca cuvantul are 32 de biti). Functia de dispersie prin multiplicare este data de

h(x) =⌊p ·

A

w

unde y = y− y si A este o constanta convenabil aleasa. De obicei se ia A prim cu w si p putere a lui2.

5.4.2.2 Coliziunea

Exista doua tehnici de baza pentru rezolvarea coliziunii: ınlantuirea si adresarea deschisa.

Page 111: algoritmi_tehnici_dorel lucanu - carte

114 CAPITOLUL 5. CAUTARE

Dispersie cu ınlantuire Numele cu aceeasi adresa sunt memorate ıntr-o lista liniara simplu ınlantuita(fig. 5.24). Notam cu s.nume campul care memoreaza numele unui simbol s si cu s.latr campul cememoreaza lista (sau adresa listei) de atribute a lui s.

• begin

• for end

• if • array type

case

T

0

1

2

3

4

lista de atribute pentru begin

Figura 5.24: Dispersie cu ınlantuire

Cautarea unui nume ın tabela se realizeaza ın doua etape: mai ıntai se calculeaza adresa ın tabelacorespunzatoare numelui si apoi se cauta secvential ın lista simplu ınlantuita.

function poz(x, T)begin

i ← hash(x)p ← T[i]while (p = NULL) do

if (p->nume = x)then return pelse p ← p->succ

return NULLend

Regasirea atributelor unui nume presupune mai ıntai cautarea numelui in tabela:

function atribute(x, T)begin

p ← poz(x, T)if (p = NULL)then return p->latrelse return NULL

end

Operatia de adaugare a unui element x ın tabela presupune calculul lui i = h(x) si inserarea acestuiaın lista T [i]. Pentru ca operatia de adaugare sa se realizeze cu cat mai putine operatii, inserarea se vaface la ınceputul listei.

procedure insereaza(x, xatr, T)begin

i ← hash(x)new(p)p->nume ← xp->latr ← xatrp->succ ← T[i]

Page 112: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 115

T[i] ← pend

Operatia de stergere a numelui x presupune cautarea pentru x ın lista T [h(x)] si eliminarea noduluicorespunzator. Odata cu eliminarea numelui sunt eliminate si atributele acestuia.

procedure elimina(x, T)begin

i ← hash(x)p ← T[i]predp ← NULLwhile ((p = NULL) and (p->nume = x) do

predp ← pp ← p->succ

if (p = NULL)then delete(p->latr) /* elimina toata lista */

if (p = T[i])then T[i] ← p->succelse predp->succ← p->succ

delete(p)end

Exercitiul 5.4.4. Sa se scrie subprograme care sa realizeze modificari ale atributelor corespunzatoareunui nume. Aceste modificari vor include adaugarea de noi atribute, stergerea de atribute sau ınlocuireade atribute.

Teorema 5.12. Presupunem ca tabela T contine elementele multimii S ⊂ U. Operatiile de adaugare side stergere au complexitatea timp pentru cazul cel mai nefavorabil egala cu O(#S).

Pentru a calcula complexitatea medie, facem presupunerea ca functia de dispersie distribuie uniformelementele din U si ca numele apar cu aceeasi probabilitate ca argumente ale operatiilor de cautare.

Teorema 5.13. Numarul mediu de comparatii pentru o cautare cu succes este aproximativ 1 + β2 , unde

β = #Sp este factorul de ıncarcare al tabelei.

Demonstratie. Metoda 1. Stim ca o cauatare cu succes ıntr-o lista liniara de lungime m necesita ın mediem+ 1

2 . Lungimea medie a unei liste este β iar probabilitatea ca elementul cautat sa apartina unei liste

este 1p (se presupune o dispersie uniforma). Numarul mediu de comparatii pentru o cautare cu succes

este:

1 +p−1∑i=0

β + 12· 1p= 1 +

β + 12

Metoda 2. Presupunem pentru moment ca inserarile elementelor se fac la sfarsitul listelor. Cautareapentru al i-lea element inserat necesita un numar de comparatii egal cu 1 plus lungimea listei la sfarsitulcareia a fost adaugat. La momentul inserarii elementului i, lungimea medie a listelor este i− 1

p . Rezultaca numarul mediu de comparatii pentru o cautare cu succes este:

1n

n∑i=1

(1 +

i− 1p

)= 1 +

β

2− 1

2p

unde n = #S. sfdem

Exercitiul 5.4.5. Sa se realizeze o implementare a dispersiei cu ınlantuire utilizand arbori binari decautare ın loc de liste liniare simplu ınlantuite.

Page 113: algoritmi_tehnici_dorel lucanu - carte

116 CAPITOLUL 5. CAUTARE

Dispersie cu adresare deschisa Pentru un nume x ∈ U se defineste o secventa h(x, i), i = 0, 1, 2, . . .,de pozitii ın tabela. Aceasta secventa, numita si secventa de ıncercari, va fi cercetata ori de cate oriapare o coliziune. De exemplu, pentru operatia de adaugare, se cauta cel mai mic i pentru care locatiade la adresa h(x, i) este libera. O metoda uzuala de definire a secventei h(x, i) consta dintr-o combinatieliniara:

h(x, i) = (h1(x) + c · i) mod p

unde h1(x) este o functie de dispersie iar c o constanta. Se pot considera si forme patratice:

h(x, i) = (h1(x) + c1 · i+ c2 · i2) mod p

O alta secventa de ıncercari des utilizata este urmatoarea:

h(x), h(x) − 1, . . . , 0, p− 1, p− 2, . . . , h(x) + 1

unde h este o functie de dispersie.

Teorema 5.14. Pentru dispersia cu adresare deschisa, numarul mediu de ıncercari pentru o cautarefara succes este cel mult 1

1− β(β < 1).

Demonstratie. Vom presupune ca h(x, 0), h(x, 1), h(x, 2), . . . , h(x, p−1) realizeaza o permutare a multimii0, 1, 2, . . . , p − 1. Aceasta asigura faptul ca o inserare se realizeaza cu succes ori de cate ori exista opozitie libera ın tabela. Notam cu X variabila aleatoare care ıntoarce numarul de ıncercari ın pozitiiocupate si cu pi probabilitatea Pr(X = i). Evident, daca i > n (n = #S) atunci pi = 0. Numarul mediude ıncercari M ın pozitii ocupate este:

1 +n∑

i=0

i · pi =

1 +∞∑

i=0

i · pi =

1 +∞∑

i=0

i · Pr(X = i) =

1 +∞∑

i=0

i · (Pr(X ≥ i)− Pr(X ≥ i+ 1)) =

1 +∞∑

i=1

Pr(X ≥ i) =

1 +∞∑

i=1

qi

Avem q1 = np , q2 = n

p ·n− 1p− 1 ≤

(np

)2

, . . . de unde rezulta

M = 1 +∞∑

i=1

βi =1

1− β

sfdem

Corolar 5.5. [Knu76] Pentru dispersia cu adresare deschisa liniara, numarul mediu de ıncercari pentruo cautare cu succes 1

2

[1 + 1

1− β

].

5.4.2.3 Exercitii

Exercitiul 5.4.6. [HSAF93] Sa se proiecteze o reprezentare a unei tabele de simboluri care sa permitacautarea, inserarea si stergerea unui nume ıntreg x ın timpul O(1). Se presupune 0 ≤ x < m si ca suntdisponibile n+m registre de memorie, unde n este numarul de inserari.Indicatie. Se vor utiliza doua tablouri (a[i] | 0 ≤ i < n) si (b[j] | 0 ≤ j < m) cu semnificatiile: daca xeste cel de-al i-lea nume inserat atunci a[i] = x si b[x] = i . Se va evita initializarea tablourilor deoareceaceasta necesita timpul O(n+m).

Page 114: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 117

Exercitiul 5.4.7. [HSAF93] Fie S = x0, . . . , xn−1 si T = y0, . . . , yr−1. Se presupune 0 ≤ xi < m,0 ≤ i < n, si 0 ≤ yj ≤ m, 0 ≤ j < r. Utilizand ideea de la exercitiul 5.4.6 sa se scrie un algoritm caresa determine daca S ⊆ T . Complexitatea timp a algoritmului va fi O(n + r). Deoarece S = T daca sinumai daca S ⊆ T si T ⊆ S, rezulta ca se poate testa daca doua multimi sunt echivalente ın timp liniar.Care este complexitatea spatiu a algoritmului?

Exercitiul 5.4.8. [Knu76] Pentru scrierea unui compilator FORTRAN se utilizeaza o tabela de simboluripentru memorarea numelor de variabile care apar ın programul FORTRAN ce se compileaza. Aceste numepot avea cel mult 8 caractere. S-a luat decizia ca dimensiunea tabelei sa fie 128 si functia de dispersie safie h(x) = “caracterul cel mai semnificativ al numelui x”. Este o idee buna? Justificati raspunsul.

Exercitiul 5.4.9. [Knu76] Fie h(x) o functie de dispersie si q(x) o functie de argument x astfel ıncat x sapoata fi determinat daca se cunosc h(x) si q(x). De exemplu, ın cazul ımpartirii modulare avem h(x) =x mod p si q(x) = xp , iar ın cazul dispersarii prin multiplicare vom lua h(x) rangurile semnificative

ale lui A · xw si q(x) celelalte ranguri (cand p este putere a lui 2). Sa se arate ca daca se utilizeazaınlantuirea atunci este suficient sa se memoreze ın fiecare ınregistrare q(x) ın loc de x.

Exercitiul 5.4.10. [CLR93] O tabela de dispersie de dimensiune p este utilizata pentru a memora nelemente, n ≤ p

2 . Se presupune ca se utilizeaza adresarea deschisa pentru rezolvarea coliziunilor.

1. Presupunand ca dispersia este uniforma, aratati ca, pentru i = 0, 1, . . . , n− 1, probabilitatea ca ai-a inserare sa necesite mai mult de k ıncercari este cel mult 2−k.

2. Notam cu Xi variabila aleatoare care ıntoarce numarul de ıncercari necesare la a i-a inserare si prinX variabila aleatoare maxi Xi. Sa se arate ca:

(a) Pr(X > logn) ≤ 1n .

(b) M(X) = O(log n).

5.4.3 Arbori digitali (tries)

Pana acum am studiat numai structuri de date pentru reprezentarea multimilor S astfel ıncat pentruoperatiile de cautare, inserare si stergere sa existe algoritmi eficienti din punct de vedere al complexitatiitimp. In aceasta subsectiune vom studia o structura de date care, ın anumite situatii, reduce semnificativspatiul de memorie necesar reprezentarii multimii S. Consideram exemplul cand S este un dictionar. Sepoate reduce spatiul necesar pentru memorarea dictionarului daca pentru cuvintele cu radacina comuna,aceasta este reprezentata o singura data. Definitia arborilor digitali au ca punct de plecare aceasta idee.

Un arbore digital este o structura de date care se bazeaza pe reprezentarea digitala (cu cifre) aelementelor din multimea univers. Denumirea de tri (ın unele carti trie) a fost data de E. Fredkin(CACM,3,1960,490-500) si constituie o parte din expresia din limba engleza “information retrieval”. Unarbore digital este de fapt un arbore cu radacina ordonat k-ar (fiecare varf are cel mult k succesori),unde k este numarul de cifre (litere dintr-un alfabet) necesare pentru reprezentarea elementelor multimiiunivers. Se presupune ca toate elementele sunt reprezentate prin secvente de cifre (litere) de aceeasilungime m. Astfel, multimea univers contine mk elemente.

Exemplu: Presupunem ca elementele multimii univers sunt codificate prin secvente de trei cifre dinalfabetul 0, 1, 2. Multimea de chei S = 121, 102, 211, 120, 210, 212 este reprezentata prin arborele dinfig. 5.25. sfex

Reprezentarea cuvintelor prin arbori digitali aduce o economie de memorie numai ın cazul cand existamulte prefixe comune. In fig. 5.26 este reprezentat un exemplu cand spatiul ocupat de arborele digitaleste mai mica decat cel ocupat de lista liniara a cuvintelor.

Un arbore tri poate fi reprezentat ın memoria calculatorului printr-o lista ınlantuita ın care fiecarenod v are k campuri de legatura, (v.succ[j] | 0 ≤ j < k), ce memoreaza adresele fiilor lui v. Pentrusimplitatea prezentarii, presupunem ca alfabetul este 0, . . . , k−1. Arborele din fig. 5.25 este reprezentatprin structura din fig. 5.27. Elementele din multimea S sunt gandite ca fiind chei iar nodurile de pefrontiera memoreaza informatiile asociate acestor chei.

Page 115: algoritmi_tehnici_dorel lucanu - carte

118 CAPITOLUL 5. CAUTARE

1 2

0 2 1

2 1 0 1 2

102 121 210 211 212

120

Figura 5.25: Arbore digital

Figura 5.26: Cazul cand exista multe prefixe comune

Cautarea. Cautarea pentru un element a ın structura t consta ın ıncercarea de a parcurge drumul ınarbore descris de secventa (a[0], . . . , a[m − 1]). Parcurgerea completa a drumului ınseamna cautare cusucces (a ∈ S) iar parcurgerea partiala - cautare fara succes.

function poz(a, T)begin

i ← 0p ← twhile ((p = NULL) and (i < m) do

p ← p->succ[a[i]]i ← i+1

return pend

Complexitatea timp pentru cazul cel mai nefavorabil este O(m). De notat ca aceasta nu depinde denumarul cuvintelor n. Pentru ca aceasta cautare sa fie mai eficienta decat cautarea binara trebuie can > 2m.

Inserarea. Programul care realizeaza operatia de inserare a unui cuvant x la structura t simuleaza par-curgerea drumului descris de secventa (x[0], . . . , x[m− 1]). Pentru acele componente x[i] pentru care nuexista noduri ın t se va adauga un nou nod ca succesor celui corespunzator lui x[i− 1].

Page 116: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 119

2

0 1 2

0 1 2

0 1 2 0 1 2

0 1 2

0 1

Figura 5.27: Structura de date pentru arborele din fig.5.25

Eliminarea. Consideram mai ıntai un exemplu. Daca din structura din fig. 5.25 elimina elementulreprezentat de 102, atunci este necesara si eliminarea a doua noduri (cele corespunzatoare componentelor0 si 2), iar stergerea elementului 210 presupune eliminarea unui singur nod (cel corespunzator lui 0).Deci un element care urmeaza a fi eliminat este ımpartit ın doua parti: un prefix care este comun si altorelemente care exista ın structura si deci nu trebuie distrus, si un sufix care nu mai apartine la nici unelement si deci poate fi sters. Astfel, strategia pe care o urmeaza programul descris aici este urmatoarea:

• se parcurge drumul descris de elementul x ce urmeaza a fi sters si se memoreaza acest drum ıntr-ostiva;

• parcurge acest drum ınapoi, utilizand stiva, si daca pentru un nod de pe acest drum toti succesoriisunt egali cu nil atunci se elimina acel nod.

Observatie: Se poate elimina utilizarea stivei daca la parcurgerea “dus” se determina ultimul nod careare mai mult de un succesor si litera corespunzatoare acestui nod. Rezulta ca stergerea se poate realizacu O(1) spatiu suplimentar. sfobs

Atat inserarea cat si eliminarea se realizeaza ın timpul cel mai nefavorabil O(n).

5.4.3.1 Cazul cheilor cu lungimi diferite

Exista multe situatii practice cand cheile nu aceleasi lungime. De exemplu, pentru un dictionar desinonime, cheile sunt cuvinte si, evident, acestea au lungimi diferite. In plus, este foarte posibil ca uncuvant sa fie prefix al altui cuvant. In acest caz se pune problema evidentierii nodurilor care corespundcheilor. Solutia cea mai la ındemana este de adauga un nou camp la structura unui nod. Noul campva avea urmatoarea semnificatie: daca nodul corespunde unei chei, atunci campul va referi informatiaasociata cheii (de exemplu, lista sinonimelor); altfel, campul va avea valoarea NULL. Un fragment deastfel de structura este reprezentat ın fig. 5.28. Algoritmii de cautare, inserare si eliminare se obtindin cei descrisi ın cazul cheilor de lungimi egale prin adagarea operatiilor de testare si de actualizare acampului nou adaugat.

5.4.3.2 Compactarea lanturilor

O structura rara este o structura care memoreaza putine chei. Intr-o structura rara apar multe lanturiformate din noduri intermediare cu un singur succesor. Un exemplu de structura rara este reprezentataın fig. 5.29. Atat spatiul de memorie cat si timpul de realizare a operatiilor pot fi ımbunatatite prineliminarea acestor lanturi. Astfel, ın structura vor fi pastrate numai nodurile intermediare care au celputin doi succesori. Aceste noduri sunt utilizate pentru a distinge ıntre cheile cu un prefix comun, descrisde drumul de la radacina la nod ın arborele initial, si care difera prin litera de la pozitia corespunzatoarenodului. Deoarece aceasta pozitie nu mai este egala cu lungimea drumului de la radacina la nod, trebuie caea sa fie memorata ın nod. In plus, pentru ca procesul de cautare a unei chei nu mai implica o parcurgere

Page 117: algoritmi_tehnici_dorel lucanu - carte

120 CAPITOLUL 5. CAUTARE

b aarc

arca

a

r

a c

ar

ara

Figura 5.28: Arbore digital memorand chei cu lungimi diferite

completa a cheii, exista posibilitatea ca acelasi nod de pe frontiera sa fie atins cu chei diferite. Aceastaeste eliminata prin memorarea cheii ın nodurile de pe frontiera; atingerea nodului de pe frontiera esteınsotita de testarea daca cheia memorata coincide cu cea cautata. Asadar, pretul platit este un camp nouın structura nodului, camp care memoreaza pozitia din cheie testata pentru a decide succesorul pe carese continua procesul de cautare, si memorarea cheilor ın nodurile de pe frontiera. Rezultatul compactariistructurii din 5.29 este reprezentat ın fig. 5.30.

1

0 1

0 1

0 1

0 10 10 1

0 1 0 1 0

Figura 5.29: Structura rara

Cautarea. Operatia de cautare este similara cazului necompactat, cu deosebirea ca ın fiecare nod estetestata pozitia din memorata de acel nod iar atingerea unui nod de pe frontiera este ınsotita de testareacheii. De exemplu, cautarea cheii a = 1010 ın structura din fig. 5.30 se realizeaza astfel: Se pleaca dinradacina. Pozitia memorata ın radacina este 0. Deoarece a[0] = 1, urmatorul nod interogat este fiuldrept. Pozitia memorata de acesta este 1 si pentru ca a[1] = 0, urmatorul nod este fiul stang. Pozitiamemorata aici este 3 si pentru ca a[3] = 0, urmatorul nod este fiul stang. Acest nod este pe frontierasi testam daca a coincide cu cheia memorata ın nod. Deoarece avem egalitate, cautarea se termina cusucces. De notat ca acelasi nod de pe frontiera poate fi atins si cu cheia 1000.

Page 118: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 121

1

0 1

0 1

0 1

0 1

0100 0101 1010 1011 1110

0

3 3

Figura 5.30: Structura din 5.29 compactata

Inserarea. Presupunem ca dorim inserarea cheii a = 0111 ın structura din fig. 5.30. In primul pas serealizeaza o operatie de cautare a acestei chei. Cautarea se termina ın nodul ce memoreaza cheia 0101.Cele doua chei difera pe pozitia 2. Trebuie sa inseram un nou nod care sa distinga dupa aceasta pozitie.Deoarece 0 < 2 < 3 acest nod va fi fiu stanga pentru radacina si nod tata pentru nodul care distingedupa pozitia 3. Acesta din urma va fi fiu stanga pentru nodul nou inserat. Mai adaugam un nou nodcare memoreaza noua cheie a si care va fi fiu dreapta pentru nodul ce face distinctie dupa pozitia 2.Rezultatul este reprentat ın fig. 5.31.

0111

0 1

0 1

1010 1011 1110

3

1

0 1

3

0 1

0

01010100

0 1

2

Figura 5.31: Adaugarea cheii 0111

Eliminarea. Se realizeaza ıntr-o maniera asemanatoare cazului necompactat. De exemplu, eliminareacheii 1011 din structura din fig. 5.30 se realizeaza astfel. Se cauta nodul care memoreaza aceasta cheie.In procesul de cautare se memoreaza drumul de la radacina la acest nod ıntr-o stiva. Stiva ne ajutala parcurgerea drumului ınapoi. Nodul care memoreaza cheia este eliminat si se merge ın nodul tata.Deaoarece acest nod a ramas cu un singur succesor, nodul 1010, este eliminat si se merge ın nodul tata.Deaorece acest are doi succesori, operatia de eliminare se termina.

5.4.3.3 Structuri Patricia

Un arbore digital binar este un arbore digital peste alfabetul 0, 1. Exemplele din subsectiunea 5.4.3.2sunt arbori digitali binari. Intr-un arbore digital binar, fiecare nod intern are exact doi fii. Acestiarbori au urmatoarea proprietate: numarul nodurilor de pe frontiera este cu 1 mai mare dcat numarulnodurilor interne. Daca mai adaagam un nod intern, atunci putem sa memoram cheile ın nodurile interne,

Page 119: algoritmi_tehnici_dorel lucanu - carte

122 CAPITOLUL 5. CAUTARE

1

0 1

0 1

0 1

0100 0101 1010 1110

0

3

Figura 5.32: Eliminarea cheii 1011

reducand astfel numarul nodurilor. Nodul pe care-l adauga ıl punem ca radacina. Astfel radacina va aveatotdeauna un singur fiu, anume pe cel stang (stabilit conventional). Pozitia corespunzatoare radaciniieste -1. Memorarea cheilor ın nodurile interne se face astfel ıncat pozitia nodului care va memora cheiaeste mai mica decat sau egala cu pozitia nodului tataın arborele initial. Dupa eliminarea nodurilorde pe frontiera, legaturile se refac pe principiul “legatura urmeaza cheia”. Noua structura obtinuta senumeste Patricia (Practical Algorithm To Retrieve Information Coded In Alphanumeric). O structuraPatricia corespunzatoare arborelui 5.30 este reprezentata ın fig. 5.33. Unul din marele avantaje aleacestei structuri este acela ca avem un singur tip de nod. In continuare, sunt explicate operatiile pe acestexemplu. Aceasta structura va fi luata ca exemplu pentru explicarea operatiilor.

f0 1

2

0 1

3

0 1

0 1

3

1

0 1

0

-10100

0101

0111

1010

1110

1011

a

b

c

d e

Figura 5.33: Structura Patricia

Cautarea. Presupunem ca se cauta cheia x = 1010. Din radacina a se coboara direct ın fiul stang b.Deoarece pozitia din b este 0 si x[0] = 1, se coboara ın fiul drept f . Cum x[1] este 0, urmatorul nod estee. Pozitia din e este 3 si pentru cax[3] = 0, ne deplasam din nou ın b. Pentru ca pozitia din b este 0 careeste mica decat ultima pozitie testata 3, procesul de parcurgere a structurii se termina. Se compara x cucheia memorata ın b. Deoarece avem egalitate, cautarea se termina cu succes.

Inserarea. Inserarea cheii x = 1100 presupune urmatorii pasi. Ca de obicei, mai ıntai se cauta cheia ınstructura. Opertia de cautare se termina ın nodul f . Prima poziti pe care cheia din f si x difera estej = 2. Se repeta cautarea pentru cheia scurta formata cu primele j − 1 = 1 caractere din x. Aceastacautare se termina ı b si ultima mutare facuta pe fiul drept. Vom insera un nou nod ca fiu drept al lui b.

Page 120: algoritmi_tehnici_dorel lucanu - carte

5.4. TIPURI DE DATA AVANSATE PENTRU CAUTARE 123

Noul nod va memora cheia x, va face distinctie pentru pozitia j = 2. Deoarece x[j] = 0, legatura pe fiulstang va fi la el ınsusi. Legatura pe fiul drept va fi la b, nodul pe care s-a oprit cautarea. Rezultatul estereprezentat ın fig. 5.34.

2

0 1

11110

0 1

2

0 1

3

0 1

3

0 1

0

-10100

0101

0111

1010

1011

a

b

c

d e

f

0 11100

Figura 5.34: Inserarea cheii 1100

Eliminarea. Eliminarea cheii 0111 presupune mai ıntai cautarea sa. Aceasta se termina ın nodul c.Deoarece ultima mutare a fost tot din nodul c pe fiul drept, rezulta ca acest nod poate fi eliminat foartesimplu. Legatura de la nodul tata b este dusa direct la fiul stang al lui c, d. Rezultatul este reprezentatın fig. 5.35.

f

0 1

3

0 1

0 1

3

1

0 1

0

-10100

0101

1010

1110

1011

a

b

c

d e

Figura 5.35: Eliminarea cheii 0111

Teorema 5.15. Presupunem ca, pornind de la structura vida, se creeazua o structura Patricia prin ninserari de chei generate aleator. Atunci operatia de cautare necesita O(log n) comparatii ın medie.

5.4.3.4 Exercitii

Exercitiul 5.4.11. (Extinderea tipului de data.) Fie t un arbore digital. Notam cu M(t) multimeareprezentata de acest arbore. Sa se scrie urmatoarele subprograme:

(i) reuniune(t1,t2) care realizeaza operatia M(t) = M(t1) ∪M(t2).

Page 121: algoritmi_tehnici_dorel lucanu - carte

124 CAPITOLUL 5. CAUTARE

(ii) intersectie(t1,t2) care realizeaza operatia M(t) = M(t1) ∩M(t2).

(iii) minus(t1,t2) care realizeaza operatia M(T ) = M(t1) \M(t2).

Exercitiul 5.4.12. Sa se scrie o procedura triInLista(t, L) care avand la intrare un arbore digitalt construieste lista liniara L care contine toate elementele din multimea reprezentata de t, ın ordinelexicografica.

Exercitiul 5.4.13. Sa se descrie ın limbaj algoritmic operatiile pentru arborii digitali cu chei de lungimidiferite.

Exercitiul 5.4.14. Sa se descrie ın limbaj algoritmic operatiile pentru arborii digitali compactati.

Exercitiul 5.4.15. Explicati modul ın care se elimina cheia 1010 din structura Patricia 5.33.

Exercitiul 5.4.16. Sa se descrie ın limbaj algoritmic operatiile pentru structurile Patricia.

5.5 Referinte bibliografice

Desi scrisa ın 1973, [Knu76] ramane o carte de referinta ın domeniu. Multe aspecte ale cautarii studiateın acest capitol sunt inspirate de aici. Completari la structurile de date studiate aici, precum si altestructuri, mai pot fi gasite ın [Mel84a, Sed88, HSAF93]. Pentru aspectele teoretice privind structurile decautare recomandam [Knu76, Mel84a, Mel79].

Page 122: algoritmi_tehnici_dorel lucanu - carte

Capitolul 6

“Pattern matching”

Consideram sirurile ca tipuri de data abstracte ın care:

• obiectele sunt secvente x0 · · ·xn−1 cu componentele xi apartinand unui tip abstract ale carui ele-mente le numim caractere,

• setul de operatii include inserarea si stergerea de caractere, concatenarea a doua siruri si regasireaunui sir ca subsir al altuia.

Sistemele de procesare a textelor utilizeaza acest tip pentru editarea textelor. Un text poate fi privit caun sir de litere, cifre, si caractere speciale. Tipul String si fisierele text constituie reprezentari ale tipuluiabstract sir. Un caz particular ıl constituie sirurile binare, construite peste alfabetul 0, 1. Acesteasunt utilizate la memorarea imaginilor grafice, de exemplu. In acest capitol prezentam algoritmi pentruo singura operatie peste siruri si anume regasirea unui sir ca subsir al altuia, cunoscuta si sub numele de”pattern matching”.

Fie tipul abstract Character ın care obiectele sunt caracterele. Fara sa restrangem generalitatea,presupunem ca sirurile sunt reprezentate prin tablouri unidimensionale de caractere. Problema de “pat-tern matching” poate fi formulata astfel: fiind date doua siruri s = s0 · · · sn−1 (subiectul sau textul) sip = p0 · · · pm−1 (”pattern”-ul), sa se proiecteze un algoritm eficient care sa decida daca p este subsir allui s. In cazul cand ”pattern”-ul apare de mai multe ori ın text, intereseaza pozitia unei aparitii (deregula, prima). De exemplu, ın textul s = aabaccabaac ”pattern”-ul p = bbaabbcc nu apare niciodata ,iar ”pattern”-ul aba apare de doua ori.

Algoritmii care rezolva problema de ”pattern matching” au o istorie interesanta [Sed88]. In 1970, S.A.Cook a demonstrat un rezultat teoretic despre un anumit tip abstract de masina, unde se presupuneaexistenta unui algoritm de ”pattern matching” ce necesita un timp proportional cu n + m ın cazul celmai nefavorabil. D.E. Knuth si V.R. Pratt au utilizat constructia laborioasa din teorema lui Cook siau elaborat un algoritm care, mai apoi, a fost rafinat ıntr-un algoritm practic si simplu. J.H. Morris adescoperit acelasi algoritm ın timpul implementarii unui editor de texte. Este unul dintre numeroaseleexemple cand un rezultat pur teoretic poate conduce la rezultate cu aplicabilitate imediata. Algoritmuldat de Knuth, Morris si Pratt a fost publicat de abia ın 1976. Intre timp, R.S. Boyer si J.S. Moore (siindepedent W. Gosper) au descoperit un algoritm care este mult mai rapid ın multe situatii. In 1980,R.M. Karp si M.O. Rabin au proiectat un algoritm cu o descriere foarte simpla si care poate fi extins latexte si ”pattern”-uri bidimensionale, deci foarte util la procesarea imaginilor grafice.

6.1 Cautarea naiva

Un algoritm simplu dar, dupa cum vom vedea, ineficient este urmatorul: pentru fiecare pozitie posibilaın text se testeaza daca ”pattern”-ul se potriveste peste subtextul care ıncepe la acea pozitie.

function PMNaiv(s, n, p, m)begin

i ← 0while (i < n-m) do

125

Page 123: algoritmi_tehnici_dorel lucanu - carte

126 CAPITOLUL 6. “PATTERN MATCHING”

i ← i+1j ← ik ← 1whiile (s[j] = p[k]) do

if (k = m-1)then return i /* a gasit prima aparitie a lui p*/else j ← j + 1

k ← k + 1return -1 /* p nu apare in s */

end

Procedura PMNaiv va ıntoarce valoarea 0 daca ”pattern”-ul nu este subsir al subiectului (textului),sau pozitia i de la care ıncepe prima aparitie a ”pattern”-ului ın subiect (text). Complexitatea timp aalgoritmului O(n ·m).

6.2 Algoritmul Knuth-Morris-Pratt

Ideea algoritmului este urmatoarea: Atunci cand s-a ıntalnit o nepotrivire, i.e. caracterul curent pj din”pattern” este diferit de caracterul curent si din text, caracterele si−1, . . . , si−j+1 din text sunt cunoscutedeoarece ele exista ın ”pattern”. Pozitia de start pentru urmatoarea comparatie dintre ”pattern” si textpoate fi determinata exploatand aceasta informatie. Ca urmare, ıntoarcerile ın text sunt eliminate. Astfelca algoritmul va consta din doua etape:

1. Se proceseaza mai ıntai ”pattern”-ul ın O(m) si se creeaza o structura de date.

2. Folosind structura de date creata la prima etapa, se proceseaza textul fara a mai executa ıntoarceri.

text

pattern

0 j

i

=

· · ·

· · · · · ·· · ·

· · ·

Figura 6.1: Reprezentarea grafica a nepotrivirii si = pj

text

pattern

0 j

i− k

=

· · ·

· · · · · ·· · ·

· · · · · ·

i

· · ·

k j − k

Figura 6.2: si = pk ⇒ F [i, j] = F [i, k]

Exista doua moduri de a preciza o aparitie a unui ”pattern” ın text:

• prin pozitia de start: spunem ca p se potriveste ın s la pozitia de start i;

• prin pozitia de sfarsit: spunem ca p se potriveste ın s la pozitia de sfarsit i.

Page 124: algoritmi_tehnici_dorel lucanu - carte

6.2. ALGORITMUL KNUTH-MORRIS-PRATT 127

O nepotrivire o reprezentam grafic ca ın fig. 6.1. Avem si−j = p0, . . . , si−1 = pj−1, si = pj . Vom utilizaaceasta informatie pentru a determina cel mai lung prefix propriu al lui p care se potriveste ın s la pozitiade sfarsit i. Notam acest prefix cu F [i, j]. Determinarea functiei F [i, j] se face ıntr-o maniera recursiva.Pentru moment presupunem p = p0 · · · pj.

1. F [i, 0] este sirul vid (de lungime zero).

2. Presupunem j > 0. Se considera cel mai mare prefix q al lui p care se potriveste ın s la pozitiade sfarsit i − 1. Presupunem q = p0 · · · pk−1 (fig. 6.2) si notam p′ = qpk. Daca pk = si atunciF [i, j] = p′. Altfel, p′ se afla ın aceeasi situatie ca p si deci avem F [i, j] = F [i, k].

Presupunem ca pentru ”pattern”-ul p s-a determinat F [i, j] pentru orice prefix p0 · · · pj al lui p. Inmomentul aparitiei unei nepotriviri pj = si, F [i, j] = p0 · · · pk este cel mai mare prefix al lui p0 · · · pj carese potriveste ın s la pozitia de sfarsit i si deci se poate continua cu comparatia dintre si+1 si pk+1.

Convenim sa notam F [i, j] = k ın loc de F [i, j] = p0 · · · pk (orice prefix este identificat ın mod unicde pozitia sa de sfarsit ın ”pattern”).

Cum poate fi calculata eficient functia F [i, j]? Notam cu f [j] valoarea k determinata ın pasul inductivdin definitia lui F [i, j]. Cunoscand f , F [i, j] poate fi calculata foarte simplu:

k ← f[j]while (k = 0) and (p[k] = s[i]) do

k ← f[k]F[i,j] ← k

Functia f poate fi calculata explorand numai ”pattern”-ul: daca f [j] = k atunci p0 · · · pk−1 este de faptcel mai lung prefix al lui p care se potriveste ın p la pozitia de sfarsit j − 1. Ca si F , functia f poate fidefinita recursiv:

• Daca j = 0 atunci f [0] = −1 (putem presupune ca p0 · · · p−1 desemneaza sirul vid);

• Presupunem j > 0. Fie k = f [j − 1] (care este definita). Rezulta ca p0 · · · pk−1 este cel mai lungprefix al lui p0 · · · pj care se potriveste ın p la pozitia de sfarsit j − 2. Daca pk = pj−1 atuncif [j] = k + 1. Altfel, se cauta cel mai lung prefix al lui p0 · · · pk care se potriveste ın p la pozitia desfarsit j − 2. Adica se face k = f [k] si se repeta rationamentul de mai sus.

Datorita rolului pe care-l joaca ın timpul cautarii, functia f se numeste functie esec (failure function).Subprogramul Pascal care calculeaza f are o structura foarte simpla:

procedure Determina f (p, m, f)begin

f[0] ← -1for j ← 1 to m-1 do

k ← f[j-1]while ((k = -1) and (p[j-1] = p[k])) do

k ← f[k]f[j] ← k+1

end

Notam cu KMP (de la initialele celor trei autori) subprogramul care realizeaza efectiv operatia de“pattern matching”:

function KMP(s, n, p, m, f)begin

i ← 0j ← 0while (i < n) do

while (j = -1) and (p[j] = s[i]) doj ← f[j]

if (j = m-1)

Page 125: algoritmi_tehnici_dorel lucanu - carte

128 CAPITOLUL 6. “PATTERN MATCHING”

then return i-m+1 /* gasit p in s */else i ← i+1

j ← j+1return -1 /* p nu apare in s */end

Functia failure pentru ”pattern”-ul abaabaaabc este reprezentata ın fig. 6.3. Privind mai atentaceasta functie se observa ca algoritmul poate fi ımbunatatit. De exemplu daca apare o nepotrivire ıntreun caracter si din text si al cincilea caracter din ”pattern” atunci algoritmul continua cu comparatiadintre si si al doilea caracter din ”pattern”. Dar noi stim ca ıntre acestea exista nepotrivire pentru ca aldoilea si al cincilea caracter din ”pattern” sunt identice.

a b a a b a a b ca

Figura 6.3: Functia esec pentru algoritmul KMP

Teorema 6.1. Algoritmul KMP executa totdeauna cel mult n + m comparatii de caractere.

Desi algoritmul KMP executa mai putine comparatii de cat cel naiv, ın practica KMP nu se dovedeste afi mai rapid ın mod semnificativ pentru ca sunt foarte rare situatiile cand ”pattern”-ul are o structurarepetitiva.

6.3 Algoritmul Boyer-Moore

V I S U L U N E I N O P T I D E I A R N AI A R

I A RI A R

I A RI A R

I A RI A R

I A R

Figura 6.4: Algoritmul Boyer-Moore

Caracterele ”pattern”-ului sunt explorate de la dreapta la stanga. Un exemplu ce arata modul de lucrual algoritmului este reprezentat ın figura 6.4. Prima data se compara R (ultimul caracter din ”pattern”)cu S (al treilea caracter din text). Deoarece S nu apare ın ”pattern”, se deplaseaza ”pattern”-ul cu treipozitii (lungimea sa) la dreapta. Apoi se compara R cu caracterul spatiu. Nici caracterul spatiu nu apareın ”pattern” asa ca acesta se deplaseaza din nou la dreapta cu trei pozitii. Procesul continua pana candR este comparat cu I (al 21-lea caracter din text). Deoarece I apare ın ”pattern” pe prima pozitie sedeplaseaza ”pattern”-ul la dreapta cu doua pozitii. Apoi se compara R cu R, deci exista potrivire. Secontinua comparatia cu penultimul caracter din ”pattern” (de fapt al doilea) si precedentul din text (al22-lea). Se obtine din nou potrivire si se compara urmatoarele doua caractere de la stanga (primul din”pattern” si al 21-lea din text). Deoarece exista potrivire si ”pattern”-ul a fost parcurs complet, rezultaca s-a determinat prima aparitie a ”pattern”-ului ın text.

Ca si ın cazul algoritmului KMP, exista o etapa de preprocesare a ”pattern”-ului. Aceasta preproce-sare construieste o functie care, pentru fiecare caracter din alfabet, precizeaza cate pozitii este deplasat”pattern”-ul la dreapta atunci cand apare o nepotrivire. Notam cu detSalt(p, salt) procedura carecalculeaza functia salt. Pentru ”pattern”-ul IAR avem salt[′R′] = 0, salt[′A′] = 1 si salt[′I ′] = 2.

Page 126: algoritmi_tehnici_dorel lucanu - carte

6.4. ALGORITMUL RABIN-KARP 129

In ipoteza cautarii repetate pentru acelasi ”pattern”, este preferabil ca functia salt sa fie calculata osingura data si apoi transmisa ca parametru algoritmului de cautare. Descrierea algoritmului este foartesimpla:

function BM(s, n, p, m, salt)begin

i ← m-1j ← m-1repeat

if (s[i] = p[j])then i ← i-1

j ← j-1else if (m-j > salt[s[i]])

then i ← i+m-jelse i ← i+salt[s[i]]j ← m-1

until ((j<0) or (i>n-1))if (j < 0)then return i+1else return -1

end

In cazul unei nepotriviri de forma

i· · · R A R · · ·

I A Rj

valoarea lui i este incrementata cu 3− j = 3 > 0 = salt[′R′].

Teorema 6.2 ([Sed88]) Algoritmul BM executa totdeauna cel mult m + n comparatii de caractere siaproximativ n

m salturi cand alfabetul nu este mic si ”pattern”-ul nu este prea lung.

Observatie: Daca alfabetul are numai doua caractere (cazul sirurilor binare), atunci performantelealgoritmului BM nu sunt cu mult mai bune decat cele ale cautarii naive. In acest caz se recomandaımpartirea sirurilor ın grupe cu un numar fixat de biti. Fiecare grupa reprezinta un caracter. Dacadimensiunea unei grupe este k atunci vor exista 2k caractere, i.e. dintr-un alfabet mic obtinem unul cumulte caractere. Totusi, k va trebui ales suficient de mic pentru ca dimensiunea tabelei de salturi sa nufie prea mare. sfobs

6.4 Algoritmul Rabin-Karp

Acest algoritm utilizeaza tehnica tabelelor de dispersie (hash). Un simbol este o secventa de m caractere.Sa ne imaginam ca toate simbolurile posibile sunt memorate ıntr-o tabela de dispersie foarte mare, astfelıncat nu exista coliziune. A testa daca ”pattern”-ul p coincide cu un subsir de lungime m din texteste echivalent cu testa daca functia de dispersie h da aceeasi valoare pentru ambele simboluri. Existaavantajul ca pentru ”pattern” functia de dispersie este calculata o singura data. Pentru ca algoritmul safie eficient, functia de dispersie trebuie definita ın asa fel ıncat, atunci cand se face o deplasare la dreaptaın text, calculul valorii functiei pentru urmatorul simbol sa fie cat mai simplu. Timpul necesar efectuariiacestui calcul trebuie sa fie cu mult mai mic decat cel necesar compararii a doua siruri de lungime m.

Un mod de a defini functia de dispersie este urmatorul: Se considera fiecare sir de m caractere ca fiindreprezentarea unui numar ıntreg ın baza d, unde d este numarul maxim de caractere. Numarul zecimalcorespunzator sirului s[i..i + m− 1] este:

x = s[i]dm−1 + s[i + 1]dm−2 + · · ·+ s[i + m− 1]

Page 127: algoritmi_tehnici_dorel lucanu - carte

130 CAPITOLUL 6. “PATTERN MATCHING”

Functia de dispersie h va fi definita prin h(s[i..i+m−1]) = x mod q, unde q este un numar prim foartemare. O deplasare la dreapta ın text corespunde ınlocuirii lui x cu:

(x − s[i]dm−1)d + s[i + m]

In formulele de mai sus s-a presupus caracterele 0, . . . , d− 1. Pentru a interpreta caracterele textului cafiind cifre, consideram o functie index care asociaza fiecarui caracter numarul sau de ordine ın alfabet(similar functiei Ord din Pascal). Toate acestea conduc la urmatorul algoritm foarte simplu:

functiom RK(s, n, p, m,)begin

dlam1 ← 1 /* calculeaza d la puterea m-1 */for i ← 1 to m-1 do

dlam1 ← (d*dlam1) mod qhp ← 0 /* h(p) */for i ← 0 to m-1 do

hp ← (hp*d+index(p[i])) mod qhs ← 0 /* h(s[1..m] */for i ← 0 to m-1 do

hs ← (hs*d+index(s[i])) mod qi ← 0while ((hp = hs) and (i <= n-m)) do

hs ← (hs+d*q-index(s[i])*dlam1) mod qhs ← (hs*d+index(s[i+m])) mod qi ← i+1

if (hp = hs)then return ielse return -1

end

Adunarea cu d∗ q la recalculul lui hs se face pentru a fi siguri ca se obtine un numar pozitiv. Alegeread = 32 s-a facut pentru ca operatia de ınmultire sa se efectueze foarte simplu (ıntregii din Longint suntreprezentati pe 32 biti). Merita notat faptul ca datorita eventualelor coliziuni, testul final mai trebuiedublat de verificarea p = s[i..i + m− 1].

Desi teoretic, ın cazul cel mai nefavorabil, algoritmul RK are o complexitate timp proportionala cun ·m, ın practica s-a dovedit a executa aproximativ n + m pasi.

6.5 Expresii regulate

In aceasta sectiune consideram cazul cand ”pattern”-ul constituie doar o specificatie a ceea ce se cauta ınsensul ca el desemneaza o multime de siruri pentru care se cauta. Numim o astfel de specificatie ”pattern”generalizat. Un exemplu de ”pattern” generalizat ıl constituie utilizarea caracterului “wildcard” (a sevedea si exercitiul 6.2). Un wildcard este un caracter special, sa zicem “?”, care se potriveste peste orice altcaracter. De exemplu, ”pattern”-ul generalizat “ab?a” specifica de fapt multimea abaa, abba, abca, abda, . . ..Orice subsir al textului care apartine acestei multimi se va potrivi peste acest ”pattern”. Un alt mod dea specifica ”pattern”-uri generalizate ıl constituie expresiile regulate.

Definitia 6.1. Multimea expresiilor regulate peste alfabetul A este definita recursiv astfel:

• orice caracter din A este o expresie regulata;

• daca e1, e2 sunt expresii regulate, atunci (e1e2), (e1 + e2) si e∗1 sunt expresii regulate.

Multimea de siruri (limbajul) L(e) definit de o expresie regulata e este definit recursiv astfel:

• daca e este un caracter atunci L(e) = e;

• daca e = (e1e2) atunci L(e) = L(e1)L(e2) = w1w2 | w1 ∈ L(e1), w2 ∈ L(e2);

Page 128: algoritmi_tehnici_dorel lucanu - carte

6.5. EXPRESII REGULATE 131

• daca e = (e1 + e2) atunci L(e) = L(e1) ∪ L(e2);

• daca e = e∗1 atunci L(e) = ∪kL(ek1), unde L(e0

1) = ε, L(ek+11 ) = L(ek

1)L(e1) (ε este sirul vid (delungime zero)),

Exemplu: Fie alfabetul A = a, b, c. Avem L(a(b+a)c) = abc, aac si L((ab)∗) = ε, ab, abab, ababab, . . . =(ab)k | k ≥ 0. sfex

Deoarece L(e1(e2e3)) = L((e1e2)e3), vom scrie e1e2e3 pentru a desemna una din cele doua expresii. Vomaplica astfel de conventii de omitere a parantezelor ori de cate ori este posibil.

In continuare ne vom ocupa de modul ın care expresiile regulate pot fi utilizate ın procesul de cautareıntr-un text. Mai ıntai plecam de la observatia ca ”pattern”-ul si functia esec de la algoritmul KMP pot figandite ca reprezentand un automat. In fig. 6.5 este reprezentat automatul corespunzator ”pattern”-uluisi functiei esec din fig. 6.3. Acest automat este reprezentat ca un digraf ın care varfurile reprezinta starileautomatului iar arcele relatia de tranzitie. Tranzitiile descriu comportarea automatului. De exemplu,daca automatul din fig. 6.5 se afla ın starea 3 si caracterul curent din text este “b” atunci automatulva trece ın starea 4. Altfel va trece ın starea 1. Daca automatul ajunge ın starea finala (desenata prinpatrat) atunci s-a determinat o aparitie a ”pattern”-ului ın text.

a b a a b a a a b

-1 0 1 2 3 4 5 6 7 8 9

c

10

Figura 6.5: ”Pattern” si functia esec ca automat

Notiunea de automat o extindem la expresii regulate dupa cum urmeaza:

1. Automatul definit de un caracter a este:

a

2. Fie e1 si e2 doua expresii regulate ale caror automate A1 si A2 sunt reprezentate ca mai jos:

A1

A1

Atunci:

(a) automatul corespunzator compunerii e1e2 este

A1

A1

(b) automatul corespunzator sumei e1 + e2 este

A1

A1

Page 129: algoritmi_tehnici_dorel lucanu - carte

132 CAPITOLUL 6. “PATTERN MATCHING”

(c) automatul corespunzator ınchiderii e∗1 este

A1

(d)

Exemplu: Automatul corespunzator expresiei e = a(b∗a + cd) este reprezentat ın fig. 6.6a (cateva arcesi stari redondante au fost eliminate). sfex

1 2

3 4

6 7

8

5a

cd

a

b

1 a

2

3

5 a

6 c

7 d

4 b

8

a) b)

Figura 6.6: Automatul corespunzator expresiei a(b∗a + cd)

Intalnim doua tipuri de stari (varfuri ın digraf) ın definitia unui automat asociat unei expresii: staridin care ies un singur arc etichetat cu un caracter si stari din care ies doua arce neetichetate. Aceastaproprietate este evidentiata mai bine prin reprezentarea automatelor ca ın fig. 6.6b. Notam totusi faptulca aceasta proprietate rezulta din modul particular ın care am construit automatul. In general, automatulasociat unei expresii nu este unic determinat dar, toate automatele corespunzatoare acleeasi expresii suntizomorfe (din punct de vedere al comportarii). Reprezentarea particulara de aici permite reprezentarea au-tomatelor printr-un tablou unidimensional de structuri, unde o componenta a tabloului are trei campuri:unul pentru memorarea caracterului iar celelalte doua pentru memorarea starilor urmatoare. Facemconventia ca -1 sa reprezinte starea invalida si 0 starea initiala. De exemplu, A.stare[s].st urm2 = −1poate semnifica faptul ca din starea s pleaca un singur arc.

Exercitiul 6.5.1. Sa se scrie un program care construieste automatul asociat unei expresii regulate.Indicatie. Se construieste notatia postfixata a expresiei (a se vedea exercitiul 3.5.12) si apoi se aplicaalgoritmul de evaluare a unei expresii (a se vedea exercitiul 3.5.13), unde evaluarea consta acum ınconstruirea automatului.

Algoritmul de cautare a unui sir desemnat de o expresie regulata are urmatoarea descriere sumara.Utilizam o coada cu restrictii la iesire D (a se vedea si exercitiul 3.4.2), unde inserarile se pot face si laınceput si la sfarsit iar stegerile/citirile numai la ınceput. Fie q starea curenta a automatului, j pozitiacurenta ın textul s, i pozitia ın textul s de ınceput a ”pattern”-ului curent. Simbolul # va juca rolul dedelimitator (el poate fi ınlocuit cu starea invalida -1). Initial avem D = (#), q = 1 (prima stare dupastarea initiala 0), i = j = 1. La pasul curent se executa urmatoarele operatii:

1. Daca

(a) din q pleaca doua arce neetichetate atunci insereaza la ınceput ın D destinatiile celor douaarce;

(b) din q pleaca un singur arc etichetat cu s[j] atunci insereaza la sfarsitul lui D destinatia arcului;

(c) q este delimitatorul # atunci:

i. daca D = ∅ atunci incrementeaza i, j devine noul i, insereaza # ın D si atribuie 1 lui q(aceasta corespunde situatiei cand au fost epuizate toate posibilitatile de a gasi ın text oaparitie a unui sir specificat de ”pattern” care ıncepe la pozitia i);

Page 130: algoritmi_tehnici_dorel lucanu - carte

6.6. MAI MULTE ”PATTERN”-URI SI INLOCUIRE 133

ii. daca D = ∅ atunci incrementeaza j si insereaza # la sfarsitul lui D;

(d) daca q este starea finala atunci s-a gasit o aparitie a unui sir specificat de ”pattern” care ıncepela pozitia i.

2. Extrage starea de la ınceputul lui D si o memoreaza ın D, dupa care reia pasul curent.

Exercitiul 6.5.2. Sa se exemplifice executia algoritmului de mai sus pentru automatul din fig. 6.6 sitextul abcacde.

Exercitiul 6.5.3. Sa se scrie un program care implementeaza algoritmul de mai sus.

Exercitiul 6.5.4. Fie e o expresie regulata, A automatul corespunzator lui e si s un subiect.

1. Sa se scrie un subprogram recursiv PozSf(q,i):Integer care, pentru o stare q ın A si o pozitie iın subiect date, ıntoarce -1, daca nu exista drum de la q la starea finala descris de un subsir al luis ce ıncepe la pozitia i, si pozitia de sfarsit al subsirului descris de un astfel de drum, atunci candexista.

2. Sa se scrie un program care utlizeaza PozSf pentru a determina o aparitie ın s a unui sir desemnatde e.

3. Sa se modifice PozSf(q,i) astfel ıncat sa determine toate drumurile de la q la starea finala descrisede subsiruri ale lui s care ıncep la pozitia i.

6.6 Mai multe ”pattern”-uri si ınlocuire

Consideram doua modificari ale problemei studiate ın sectiunile anterioare: ın loc de un singur ”pat-tern” presupunem ca se cauta simultan pentru mai multe ”pattern”-uri, iar aparitia fiecarui ”pat-tern” este ınlocuita cu un alt sir. Aceasta noua versiune este tratata ın [AS84]. Notam cu K =(x0, y0), (x2, y2), . . . , (xk−1, yk−1) multimea perechilor (”pattern”, sir ınlocuitor). Covenim ca sirurilexi si yi sa le numim cuvinte cheie. Presupunem (xi = ε), pentru orice i cu 0 ≤ i < k. Cautarea simultanapentru mai multe chei si ınlocuirea acestora presupune rezolvarea problemei suprapunerii cheilor: cand ocheie se suprapune peste alta cheie. In acest caz se va ınlocui direct cheia mai lunga (evident, cele douachei au aceeasi pozitie de start).

Algoritmul prezentat este o generalizare a algoritmului KMP si presupune parcurgerea a trei etape. Inprima etapa se memoreaza cheile ıntr-o structura arborescenta asemanatoare arborilor digitali. O astfelde structura este reprezentata ın fig. 6.7 pentru

K = (ABCDE, α), (CDE, β), (BC, γ).

Varfurile arborelui le numim stari (de la terminologia automatelor) si le identificam prin numere ıntreginenegative. Mai consideram ın plus starea -1 care joaca rolul starii nedefinite. Radacina este starea 0totdeauna. Arborele ıl reprezentam printr-o functie g[s, c] cu semnificatia g[s, c] = s′ daca si numai dacaexista un arc de la starea s la starea s′ etichetat cu caracterul c (ın terminologia automatelor, actiuneanotata de c transforma starea s ın starea s′). Altfel g[s, c] = Nedefinit. Aceasta reprezentare este foartesimpla, dar are dezavantajul ca multe intrari ıntr-un tabel au valoarea Nedefinit. Structura arborescentao completam cu o functie partial definita out[s] care, pentru o stare corespunzatoare terminarii unei chei,ınregistreaza sirul ınlocuitor. Pentru exemplul din fig. 6.7 avem out[5] = α, out[8] = β, out[10] = γ.Definitia functiei out urmeaza a fi completata ın etapa a doua. Subprogramul care construieste arboreleutilizeaza o procedura de inserare a unei perechi de chei, similara celei de la arbori digitali:

procedure adaugaCheie(x, y)begin

m ← lung(x)stare ← 0j ← 1while (g[stare,x[j]] = nedefinit) do

stare ← g[stare,x[j]]

Page 131: algoritmi_tehnici_dorel lucanu - carte

134 CAPITOLUL 6. “PATTERN MATCHING”

j ← j+1for i ← j to m do

starenoua← starenoua+1for c ← primulCaracter to ultimulCaracter do

g[starenoua,c]← nedefinitout[starenoua]← NULL

g[stare,x[i]]← starenouastare ← starenoua

out[stare]← yend

procedure constrGraf(chei, k, g, out)begin

starenoua← 0for c ← primulCaracter to ultimulCaracter do

g[0,c] ← nedefinitfor i ← 1 to k do

adaugaCheie(chei[i,1],chei[i,2])for c ← primulCaracter to ultimulCaracter do

if (g[0,c] = nedefinit) then g[0,c] ← 0end

S-a presupus chei[i, 1] = xi si Chei[i, 2] = yi.

0

1 2 3 4 5

6 7 8

9 10

B C D E

A

C D E

B C

¬A, B, C

Figura 6.7: Arborele cheilor

In etapa a doua se construieste functia esec f [s] cu semnificatia ca daca apare nepotrivire ın starea satunci urmatoarea stare va fi f [s]. Algoritmul care construieste functia esec este similar celui de la KMP,numai ca acum ordinea de determinare a valorilor functiei este cea data de explorarea BFS a arborelui.Functia esec pentru exemplul de mai sus este reprezentata ın fig. 6.8. Tot ın aceasta etapa este completatasi definitia functiei out care va ınregistra, pentru fiecare stare, sirul ce urmeaza a fi scris ın textul rezultat,corespunzator acelei stari. Pentru starile s = g[0, c] punem out[s] = ′c′. Pentru exemplul nostru avemout[1] = ′A′, out[6] = ′C′ si out[9] = ′B′. In continuare, functia out se calculeaza odata cu functiaesec. Avem out[2] = out[3] = ′A′, out[7] = ′CD′, out[4] = ′A′γ′D′. Valorile out[5] = α, out[8] = βsi out[10] = γ au fost calculate la prima etapa. Programul Pascal care realizeaza etapa a doua esteurmatorul:

procedure constrFctEsec(g, out, f)begin

q ← coadaVida()for c ← primulCaracter to ultimulCaracter do

stare1 ← g[0,c]if ((stare1 = 0) and (stare1 = nedefinit))then insereaza(q,stare1)

f[stare1]← 0if (out[stare1] = NULL)then new(out[stare1])

Page 132: algoritmi_tehnici_dorel lucanu - carte

6.6. MAI MULTE ”PATTERN”-URI SI INLOCUIRE 135

out[stare1]← cwhile (not esteCoadaVida(q)) do

stare3 ← citeste(q)elimina(q)for c ← primulCaracter to ultimulCaracter do

stare1 ← g[stare3,c]if ((stare1 = Nedefinit) and (stare1 =0))then insereaza(q, stare1)

if out[stare1] = NULLthen f[stare1]← 0else stare2 ← f[stare3]out[stare1]← out[stare3]while (g[stare2,c] = nedefinit) do

stare2 ← f[stare2]concatenate(out[stare1], out[stare2])

f[stare1]← g[stare2,c]if (f[stare1] = 0)then concatenate(out[stare1],c)

end

0

1 2 3 4 5

6 7 8

9 10

B C D E

A

C D E

B C

¬A, B, C

Figura 6.8: Functia esec

A treia etapa consta ın procesarea textului, gasirea si ınlocuirea cheilor.

procedure MPMR(g, out, f, s, n)begin

stare ← 0for i ← 1 to n do

while (g[stare,s[i]] = nedefinit) doscrie(out[stare])stare ← f[stare]

stare ← g[stare,s[i]]if (stare = 0) then scrie(s[i])while (stare = 0) do

scrie(out[stare])stare ← f[stare]

end

Exercitiul 6.6.1. Sa se aplice algoritmul MPMR pentru textul ’BABCDEXABCAB’ si multimea de cheidin exemplu.

Algoritmii de preprocesare necesita un timp proportional cu suma lungimilor cheilor, iar algoritmulde cautare si ınlocuire realizeaza cel mult 2n tranzitii de stari [AS84].

Page 133: algoritmi_tehnici_dorel lucanu - carte

136 CAPITOLUL 6. “PATTERN MATCHING”

6.7 Referinte bibliografice

Acest capitol, exceptand sectiunea dedicata pattern-urilor multiple, urmeaza linia din [Sed88]. Pattern-urile multiple si ınlocuirea este tratata ın [AS84]. Mai pot fi consultate [Baa78, CLR93, AHU74].

6.8 Exercitii

Exercitiul 6.1. Sa se implementeze un algoritm de cautare naiva care sa cerceteze pattern-ul de ladreapta la stanga.

Exercitiul 6.2. Sa se modifice algoritmii de pattern matching pentru cazul ın care pattern-ul contineun caracter “wild-card” (orice caracter din text se potriveste peste el).

Exercitiul 6.3. Sa se implementeze o versiune a algoritmului Rabin–Karp pentru pattern-uri ın textebidimensionale. Se presupune ca atat pattern-ul cat si textul sunt dreptunghiuri de caractere.

Exercitiul 6.4. Sa se proiecteze un algoritm liniar care determina daca un text T este o rotatie ciclicaa altui text T ′. De exemplu, tara si rata sunt rotatii ciclice unul altuia.

Exercitiul 6.5. ([CLR93]) Cu wi notam concatenarea sirului w cu el ınsusi de i ori. De exemplu,(abc)4 = abcabcabcabc. Numim factor de repetitie al sirului w un numar r cu w = ur, unde u este unsir si r > 0. Notam cu ρ(w) cel mai mare factor de repetitie al sirului w. Sa se proiecteze un algoritmeficient care, pentru un sir w[1..n] dat, determina ρ(w[1..i]) pentru i = 1, 2, . . . , n.

Exercitiul 6.6. Sa se modifice algoritmii de pattern matching simplu astfel ıncat sa fie determinatetoate aparitiile pattern-ului ın text si sa fie ınlocuite cu un alt sir dat.

Page 134: algoritmi_tehnici_dorel lucanu - carte

Capitolul 8

Despre paradigmele de proiectare aalgoritmilor

8.1 Aspecte generale

Descrierea unui algoritm care rezolva o problema presupune ca etapa intermediara constructia modeluluimatematic corespunzator problemei (a se vedea fig. 8.1). Necesitatea constructiei modelului matematiceste impusa de urmatoarele motive:

• Eliminarea ambiguitatilor si inconsistentelor. De multe ori problema este descrisa informal(verbal). De aici, anumite aspecte ale problemei pot fi omise sau formulate ambiguu. Constructiamodelului matematic evidentiaza toate aceste lipsuri si, ın acest fel, conduce la eliminarea lor.

• Utlizarea instrumentelor matematice de investigare. Posibilitatea utilizarii instrumentelorde investigare matematica pentru gasirea solutiei si pentru determinarea structurii analitice a aces-teia.

• Diminuarea efortului la scrierea programului. Descrierea solutiei ın termenii modeluluimatematic usureaza foarte mult munca de descriere a algoritmului (programul).

O paradigma de proiectare a algoritmilor se bazeaza pe un anumit tip de model matematic si pune ladispozitie procedee prin care se poate construi si implementa (descrie ca program) un model particularcorespunzator unei probleme. Descrierea unui model matematic cuprinde urmatoarele trei aspecte [BD62]:

1. conceptual: presupune identificarea si definirea conceptelor care descriu componentele din domeniulproblemei;

2. analitic: presupune gasirea tuturor relatiilor ıntre concepte care conduc la gasirea si descriereasolutiei;

3. computational: presupune evaluarea calitativa a algoritmului ce construieste solutia.

Model matematic• aspect conceptual• aspect analitic• aspect computational

ProgramProblema

Figura 8.1: Drumul de la problema la program

143

Page 135: algoritmi_tehnici_dorel lucanu - carte

144 CAPITOLUL 8. DESPRE PARADIGMELE DE PROIECTARE

Cele trei aspecte se reflecta ın etapele ce trebuie parcurse ın rezolvarea unei probleme si pe care le-amdiscutat ın capitolul de introducere.

Urmatoarele patru capitole prezinta cele mai cunoscute patru paradigme de proiectare: greedy, divide-et-impera, programare dinamica si backtracking. Pentru fiecare paradigma sunt prezentate modelulmatematic si un set de studii de caz. In acest capitol prezentam, ca exemplu, paradigma eliminariipentru a evidentia aspectele enumerate mai sus.

8.2 Un exemplu simplu de paradigma: eliminarea

8.2.1 Primul studiu de caz: problema celebritatii

8.2.1.1 Descrierea problemei

Se considera o colectivitate formata din n persoane. O celebritate este o persoana care este cunoscuta deoricare alta persoana si nu cunoaste pe nimeni. Problema consta ın a scrie un program care sa determinedaca exista o celebritate ın cadrul colectivitatii prin ıntrebari de forma: “Persoana i cunoaste persoanaj?”. Programul va pune cel mult 3 · n ıntrebari.

8.2.1.2 Modelul matematic

Aspectul conceptual. Fara sa restrangem generalitatea, presupunem ca persoanele colectivitatii suntidentificate prin numerele 1, 2, . . . , n. O ıntrebare de forma “Persoana i cunoaste persoana j?” va fireprezentata de urmatoarea functie:

cunoaste : 1, 2, . . . , n × 1, 2, . . . , n → true, false.

Aspectul analitic. Notam cu CAND multimea persoanelor care pot candida la calitatea de celebritate.Initial, orice persoana poate candida la aceasta calitate. Dupa primirea raspunsului la o ıntrebare existaurmatoarele doua posibilitati:

• Raspunsul este adevarat, i.e. persoana i cunoaste pe j. Atunci i nu poate fi celebritate si poate fieliminat din CAND.

• Raspunsul este fals. Atunci j nu poate fi celebritate si deci poate fi eliminat din CAND.

In ambele cazuri se observa ca este eliminat un posibil candidat. Procesul de eliminare poate fi repetatpana cand ramane un singur candidat.

Aspectul computational. Obtinerea unui singur candidat se poate realiza prin n−1 ıntrebari. Notamca nu putem trage concluzia ınca daca singurul candidat ramas este celebritate sau nu. Mai trebuie puseıntrebari suplimentare pentru a afla acest lucru. Aceasta verificare se poate face prin cel mult 2 · (n− 1)ıntrebari. Rezulta ca determinarea celebritatii se poate face punand cel mult 3 · (n− 1) ıntrebari.

8.2.1.3 Implementare

Deoarece la sfarsit CAND va avea un singur element, ea poate fi gestionata de o variabila de tip ıntregcand. Se pleaca de la ipoteza ca persoana candidat este 1 si apoi se pun ıntrebari ıntre posibilul candidat sipersoana urmatoare pentru a afla noul candidat. Pentru ultimul candidat se verifica daca este celebritateprin ıntrebari duble ıntre el si fiecare dintre celelalte n− 1 persoane.

Functia Celebritate ıntoarce valoarea 0 daca nu exista celebritate, altfel ıntoarce numarul core-spunzator celebritatii.

function celebritate(n)begin

cand ← 1for j ← 2 to n do

if (cunoaste(i, j))then cand ← j

Page 136: algoritmi_tehnici_dorel lucanu - carte

8.2. UN EXEMPLU SIMPLU DE PARADIGMA: ELIMINAREA 145

i ← 1while (cand > 0) and (i ≤ n) do

if (cunoaste(i, cand))then cand ← 0else if (cunoaste(cand, i)

then cand ← 0i ← i+1

return candend

8.2.1.4 Exercitii

Exercitiul 8.2.1. In timpul executiei subprogramului Celebritate, ın partea care verifica daca uniculcandidat este celebritate este posibil ca anumite ıntrebari sa se repete, ele mai fiind puse la determinareacandidatului. Este posibila eliminarea acestei redondante si ın acelasi timp pastrarea complexitatilortimp si spatiu?

Exercitiul 8.2.2. Problema celebritatii poate fi modelata cu ajutorul digrafurilor. Varfurile digrafuluisunt persoanele si arcele reprezinta relatia de cunoastere: exista arc de la i la j daca si numai daca icunoaste pe j. In terminologia grafurilor, varful corespunzator celebritatii se numeste groapa (sink).Problema poate fi reformulata dupa cum urmeaza: dat un digraf D, sa se decida daca D are o groapasau nu.

1. Ce reprezentare este cea mai potrivita pentru a determina daca un digraf are groapa sau nu?

2. Ce se poate spune despre complexitatile timp si spatiu pentru problema reformulata ın limbajulgrafurilor?

8.2.2 Al doilea studiu de caz: permutarea maximala

8.2.2.1 Prezentarea problemei

Se considera o colectivitate formata din n persoane. Fiecare persoana din colectivitate are un singurpreferat ın colectivitate. Este posibil ca o persoana se poate prefera pe sine ınsasi. Un grup de persoanedin colectivitate se numeste omogen daca fiecare membru al grupului este preferatul exact al unui singurmembru din acel grup . Se pune problema alegerii unui grup omogen cu numar maxim de persoane.

8.2.2.2 Modelul matematic

Aspectul conceptual. Notam cu A multimea finita reprezentand colectivitatea de persoane si cuf : A → A functia care reprezinta relatia de preferinta. Problema consta ın a determina o submultimeX a lui A cu proprietatile:

(i) f(X) ⊆ X ;

(ii) f |X este injectiva;

(iii) X are numar maxim de elemente peste clasa submultimilor lui A care satisfac (i) si (ii).

Prin f |X am notat restrictia functiei f la submultimea X . Remarcam faptul ca primele doua conditii,(i) si (ii), sunt echivalente cu faptul ca f |X : X → X este bijectie (permutare).

Aspectul analitic. Vom aplica o strategie asemanatoare cu cea din problema celebritatii: se vorelimina pe rand din A elementele nedorite pana cand se va obtine X . Ramane de determinat criteriul deeliminare. Pornim cu analiza problemei initiale. Distingem urmatoarele doua cazuri:

• f(A) = A. Atunci X = A.

• Exista j ∈ A astfel ıncat pentru orice i ∈ A avem f(i) = j. Problema P ′ cu instanta A′ =A \ j, f |A′ si problema initiala au aceeasi solutie.

Asadar, putem porni cu CAND = A si la fiecare pas sa eliminam un j care nu apartine imaginei functieif |CAND. Procesul de eliminare continua atat cat este posibil si la sfarsit vom avea X = CAND.

Page 137: algoritmi_tehnici_dorel lucanu - carte

146 CAPITOLUL 8. DESPRE PARADIGMELE DE PROIECTARE

Aspectul computational. Vom arata mai ıntai ca testul de eliminare pentru un j fixat poate fi efectuatın timpul O(1). Presupunem, fara sa restrangem generalitatea, ca A = 0, 1, . . . , n−1. Multimea CANDpoate fi reprezentata prin vectorul caracteristic:

x[i] =

1 , daca i ∈ CAND0 , altfel

Cu o mica modificare, vectorul x poate fi utilizat si pentru reprezentarea functiei f |CAND:

x[i] =

f(i) , daca i ∈ CAND−1 , altfel

Cu aceasta reprezentare, verificarea conditiei ∃i ∈ CAND : f(i) = j, pentru un j fixat, necesita ıncazul cel mai nefavorabil n comparatii. Acest numar poate fi redus la 1 daca vom considera un tablousuplimentar b cu urmatoarea semnificatie:

b[j] = #i ∈ CAND | f(i) = j

Acum, verificarea conditiei f(CAND) = CAND se poate realiza printr-o singura parcurgere a tabloului b:daca exista j cu x[j] ≥ 0 si b[j] = 0 atunci j va fi eliminat din CAND. Rezulta ca problema determinariipermutarii maximale poate fi rezolvata ın timpul O(n2).

8.2.2.3 Implementare

Programul permMax are urmatoarea descriere:

procedure permMax(f, n, x)begin

for j ← 0 to n-1 dob[j] ← 0

for i ← 0 to n-1 dob[f[i]] ← b[f[i]] + 1

for i ← 0 to n-1 dox[i] ← f[i]

existaj ← truewhile (existaj) do

existaj← falsej ← 0while ((j < n) and not existaj) doif ((x[j] ≥ 0) and (b[j] = 0))

then existaj ← truex[j] ← 0b[f[i]] ← b[f[i]] - 1

j ← j+1end

8.2.2.4 Exercitii

Exercitiul 8.2.3. Functia f poate fi reprezentata printr-un digraf: exista arc de la i la j daca si numaidaca f(i) = j. Sa se arate ca determinarea permutarii maximale este echivalenta cu determinarea tuturorcircuitelor ın digraful asociat.

Exercitiul 8.2.4. Sa se proiecteze un algoritm care sa determine toate circuitele ın digraful asociatfunctiei f . Sa se precizeze complexitatile timp si spatiu pentru algoritmul proiectat.

Exercitiul 8.2.5. Poate fi utilizat algoritmul de la exercitiul 8.2.4 la determinarea tuturor circuitelorıntr-un digraf oarecare?

Page 138: algoritmi_tehnici_dorel lucanu - carte

8.3. ALTE CONSIDERATII PRIVIND PARADIGMELE DE PROIECTARE 147

8.2.3 Prezentarea generala a paradigmei

Strategiile aplicate ın studiile de caz precedente sunt foarte asemanatoare. Aici vom arata cum acestestrategii pot fi generalizate la nivel de paradigma.

8.2.3.1 Modelul matematic

Aspectul conceptual Problemele pentru care poate fi aplicata strategia eliminarii sunt modelate dupaurmatoarea schema:

Se considera o multime S cu n elemente. Se pune problema determinarii existentei unui x ∈ Scare satisface o conditie C(x) ce poate fi testata ın timpul O(nk), k ≥ 1.

Aspectul analitic. Scopul tehnicii de eliminare este de a determina o submultime CAND a lui S cu unnumar cat mai mic de elemente ce pot candida la terminarea cu succes a algoritmului. Initial, multimeacandidatilor CAND este S. Se stabileste un “criteriu de eliminare” care poate fi testat ın timpul O(1)si prin care se poate decide daca un element y nu satisface C(y). Acesta va fi eliminat din CAND.Procesul de eliminare continua pana cand CAND contine destul de putine elemente astfel ıncat testareaconditiei C(x) pentru toate elementele x ∈ CAND se poate face ıntr-un timp acceptabil.

Aspectul computational. Daca n#CAND = Ω(n) atunci complexitatea timp a algoritmului dat de

strategia eliminarii este O(nk). Un alt algoritm foarte simplu, dar a carui complexitate timp este O(nk+1),este urmatorul: se alege pe rand cate un x din S si se testeaza conditia C(x). Daca exista elemente cesatisfac conditia C atunci algoritmul se termina cu succes la primul element ıntalnit cu aceasta proprietate.In caz contrar, algoritmul se termina cu insucces.

8.2.3.2 Implementare.

Programul care descrie solutia data de strategia eliminarii este foarte simplu si are urmatoarea descriereschematica:

function sol(S)begin

CAND ← Sy ← primul element din CANDfor fiecare y din CAND do

if (y satisface criteriul de eliminare)then CAND ← CAND \ yy ← urmatorul element din CAND

for fiecare y din CAND doif (C(y)) then return y

end

8.3 Alte consideratii privind paradigmele de proiectare

Asa cum s-a observat deja din cele doua studii de caz prezentate, constructia modelului matematic nu sepoate face totdeauna cu o delimitare neta ıntre cele trei aspecte: conceptual, analitic si computational.De fapt, ın [BD62] nici nu se recomanda o astfel de delimitare. Este mult mai natural si mai eficient cacele trei aspecte sa fie dezvoltate simultan. Este posibil ca dezvoltarea relatiilor analitice ıntre conceptesa evidentieze anumite aspecte ale problemei care nu au fost complet sau corespunzator conceptualizate.In acest caz o revizuire a conceptelor este necesara. De asemenea, anumite performante computationalepot fi imbunatatite prin gasirea unor reprezentari echivalente conceptual dar mai performante.

De multe ori nici cele doua faze ale rezolvarii problemei - modelul matematic si implementarea - nupot fi considerate separat. O implementare defectuoasa poate reduce performantele solutiei descrise demodel, sau, dimpotriva, o implementare buna poate ımbunatati performantele solutiei analitice. In altecazuri, aspectul computational poate fi realizat numai dupa descrierea implementarii.

Page 139: algoritmi_tehnici_dorel lucanu - carte

Capitolul 9

Algoritmi “greedy”

9.1 Un exemplu simplu: Memorarea eficienta a programelor

9.1.1 Descrierea problemei

N programe (fisiere) urmeaza a fi memorate pe o banda magnetica. Citirea unui program presupunecitirea tuturor programelor aflate ınaintea sa si deci timpul de regasire este suma timpilor de citire atuturor acestor programe (inclusiv cel cautat). Timpul mediu de regasire este media aritmetica a celor ntimpi de regasire. Problema consta ın gasirea unei aranjari a celor n programe astfel ıncat timpul mediude regasire sa fie minim.

9.1.2 Modelul matematic

Problema poate fi descrisa ın urmatoarea maniera mai abstracta. Consideram n obiecte notate cu0, 1, . . . , n− 1 de dimensiuni L0, . . . , Ln−1, respectiv, care urmeaza a fi aranjate ıntr-o lista liniara. Dacaobiectele sunt aranjate ın ordinea (π(0), . . . , π(n− 1)) atunci timpul tk de regasire a obiectului π(k) este

k∑j=0

Lπ(j) si timpul mediu de regasire a tuturor obiectelor este TM = 1n

n−1∑k=0

tk. Problema consta ın de-

terminarea unei permutari π = (π(0), . . . , π(n− 1)) astfel ıncat, aranjand obiectele ın ordinea data de π,timpul mediu de regasire sa fie minim.

Scriem suma SUMA(π) =n−1∑k=0

tk detaliat:

SUMA(π) = Lπ(0)+ (k = 0)Lπ(0) + Lπ(1)+ (k = 1)Lπ(0) + Lπ(1) + Lπ(2)+ (k = 2). . .Lπ(0) + Lπ(1) + · · ·+ Lπ(n−1) (k = n− 1)

Timpul mediu depinde direct de aceasta suma. Este usor de vazut ca obiectele de la ınceputul listeicontribuie de mai multe ori la suma. Intuitia ne spune ca suma este cu atat mai mica cu cat elementelede la ınceputul listei sunt mai mici. De aici rezulta urmatoarea strategie de aranjare a obiectelor ın listaliniara:

• daca pına la momentul i − 1 s-a construit deja permutarea partiala (π(0), . . . , π(i − 1)), atunci lamomentul i se va alege obiectul π(i) = k cu dimensiunea Lk minima peste multimea obiectelornearanjate ın lista.

Algoritmul corespunzator strategiei de mai sus este descris de schema procedurala memprog:

procedure memprog(L, n, π)begin

S ← 0, . . . , n− 1

149

Page 140: algoritmi_tehnici_dorel lucanu - carte

150 CAPITOLUL 9. ALGORITMI “GREEDY”

while (S = ∅) doalege k ∈ S astfel ıncıt L[k] = minL[j] | j ∈ SS ← S \ kπ[i] ← k

end

Corectitudinea algoritmului este data de urmatoarea teorema:

Teorema 9.1. Daca Lπ(0) ≤ Lπ(1) ≤ · · · ≤ Lπ(n−1) atunci

SUMA(π) = minSUMA(π′) | π o permutare a multimii 0, 1, . . . , n− 1

Demonstratie. Aplicam metoda reducerii la absurd. Fie π o permutare optima pentru care exista i < jastfel ıncat Lπ(i) > Lπ(j). Notam cu π′ permutarea π ınmultita cu transpozitia (i, j). Facand calculele,se obtine SUMA(π) > (SUMA(π′). Contradictie. sfdem

9.1.3 Implementare

O ordonare a obiectelor ın ordinea crescatoare a dimensiunilor este una dintre cele mai simple imple-mentari ale strategiei de mai sus. Rezulta ca problema poate fi rezolvata ın timpul cel mai nefavorabilO(n log n).

9.2 Prezentare intuitiva a paradigmei

Principalele ingrediente ale paradigmei algoritmilor “greedy” sunt urmatoarele:

1. Clasa de probleme la care se aplica include probleme de optim. Convenim sa luam ca exempluurmatoarea descriere schematica:

Intrare: O multime S.Iesire: O submultime B ⊆ S care optimizeaza o functie f : P(S)→ R.

In subsectiunea 9.9 vom vedea ca trebuie adau gate anumite conditii suplimentare. Pentru moment,aceasta descriere sumara este suficienta pentru scopul nostru.

Pentru problema memorarii programelor, consideram S ca fiind relatia S = i → j | 0 ≤ i, j < nsi B o submultime a lui S care este permutare (relatie totala bijectiva) si minimizeaza cantitatea

f(B) = 1n

n−1∑k=0

k∑i=0

(Lj | i → j ∈ B) (daca B desemneaza permutarea π atunci i → j ∈ B este

echivalent cu π(i) = j).

2. Paradigma se bazeaza pe urmatoarele doua proprietati:

(a) Proprietatea de alegere locala. Solutia problemei se obtine facand alegeri optime locale(de aici si denumirea de “greedy”=lacom). O alegere optima locala poate depinde de alegerilede pana atunci dar nu si de cele viitoare. Alegerile optime locale nu asigura automat ca solutiafinala realizeaza optimul global, adica constituie o solutie a problemei. Trebuie demonstratacest fapt. De regula, aceste demonstratii nu sunt foarte simple. In subsectiunea 9.9 vomprezenta un cadru formal pentru aceste demonstratii.O alegere optima locala (alegere “greedy”) pentru problema memorarii programelor consta ınselectarea la pasul i a unei perechi i → j astfel ıncat Lj este minim peste Lj′ | j′ neales.Observam ca aceasta alegere depinde numai de alegerile facute pana atunci. In final a trebuitsa demonstram ca aceste alegeri produc o permutare optima.

(b) Proprietatea de substructura optima. Solutia optima a problemi contine solutiile optimeale subproblemelor.Pentru problema memorarii programelor, daca B este o permutare optima, atunci orice submultimeB′ ⊆ B este o permutare optima pentru submultimea de obiecte i cu i → j ∈ B.

Page 141: algoritmi_tehnici_dorel lucanu - carte

9.3. ARBORI PONDERATI PE FRONTIERA OPTIMI 151

9.3 Studiu de caz: Arbori ponderati pe frontiera optimi

Studiul de caz prezentat ın aceasta sectiune are un grad de generalitate destul de mare astfel ca poatefi considerat mai degraba ca fiind o subparadigma. Vom vedea ca multe dintre problemele prezentate ınsectiunile urmatoare sunt de fapt cazuri particulare de arbori ponderati pe frontiera optimi. Din acestmotiv prezentarea este facuta direct la nivelul abstract.

9.3.1 Modelul matematic

Consideram arbori binari cu proprietatea ca orice varf are 0 sau 2 succesori si care au ca informatii(etichete) ın varfurile de pe frontiera numere. Convenim sa numim acesti arbori ca fiind ponderati pefrontiera. Pentru un varf v din arborele t notam cu dv lungimea drumului de la radacina lui t la varfulv. Lungimea externa ponderata a arborelui t este

LEP(t) =∑

v pe frontiera lui t

dv · inf(v)

Modificam acesti arbori etichetand varfurile interne cu numere ce reprezinta suma etichetelor din celedoua varfuri fii. Adica pentru orice varf intern v avem inf(v) = inf(v1) + inf(v2), unde v1, v2 sunt fiiilui v (a se vedea si fig. 9.1).

Lema 9.1. Fie t un arbore binar ponderat pe frontiera. Atunci

LEP(t) =∑

v intern ın t

inf(v)

Demonstratie. Se procedeaza prin inductie dupa n, numarul de varfuri de pe frontiera lui t.Baza inductiei. Presupunem n = 2. Relatia este evidenta.Pasul inductiv. Presupunem ca t are n + 1 varfuri pe frontiera. Fie v1 si v2 doua varfuri de pe frontieracu acelasi predecesor imediat (tata) v3. Avem dv1 = dv2 = d si inf(v3) = inf(v1)+ inf(v2). Consideramarborele t′ obtinut din t prin eliminarea varfurilor v1 si v2. Acum varful v3 se afla pe frontiera lui t′.Conform ipotezei inductive avem :

LEP(t′) =∑

v intern ın t′

inf(v) (9.1)

Utilizam 9.1 pentru a calcula lungimea externa ponderata a lui t:

LEP(t) =∑

v pe frontiera lui t

dv · inf(v)

=∑

v pe frontiera lui t′,v =v1,v2

dv · inf(v) + d · inf(v1) + d · inf(v2)

=∑

v pe frontiera lui t′,v =v1,v2

dv · inf(v) + (d− 1)(inf(v1)+inf(v2))+inf(v3)

= LEP(t′) + inf(v)=

∑v intern ın t′

inf(v) + inf(v3)

=∑

v intern ın t

inf(v)

S-a tinut cont de faptul ca interiorul lui t este egal cu interiorul lui t′ reunit cu v3. sfdem

Exemplu: Fie arborele din fig. 9.1. Lungimea externa ponderata a arborelui t este egala cu 80 + 70 +180 + 100 = 10 · 2 + 20 · 3 + 50 · 3 + 30 · 2 + 70 · 2 = 430. sfex

In continuare ne ocupam de urmatoarea problema:

Fie data x = (x0, . . . , xn−1) o secventa (lista liniara) de numere. Problema consta ın deter-minarea unui arbore binar ponderat pe frontiera care are ca informatii ın cele n varfuri de pefrontiera numerele x0, . . . , xn−1 si cu lungimea externa ponderata minima.

Page 142: algoritmi_tehnici_dorel lucanu - carte

152 CAPITOLUL 9. ALGORITMI “GREEDY”

20 50

70

10

80

30 70

100

180

20 50

10

30 70

Figura 9.1: Arbore ponderat pe frontiera, ınainte si dupa modificare

O metoda total ineficienta ar putea fi generarea tuturor arborilor binari cu n varfuri pe frontieraetichetate cu elementele secventei x si alegerea unuia cu lungimea externa ponderata minima.

Pentru a obtine un algoritm eficient este necesar sa studiem mai mult proprietatile arborilor cu LEPminima. Prin T (x) notam multimea arborilor binari care au ca informatii ın varfurile de pe frontieranumerele din secventa x.

Lema 9.2. Fie t un arbore din T (x) cu LEP minima si v1, v2 doua varfuri pe frontiera lui t. Dacainf(v1) < inf(v2) atunci dv1 ≥ dv2 .

Demonstratie. Presupunem dv1 < dv2 . Notam d1 = dv1 si d2 = dv2 . Fie t′ arborele obtinut din t prininterschimbarea varfurilor v1 si v2. Avem:

LEP(t′) =∑

v pe frontiera lui t′dv · inf(v)

=∑

v pe frontiera lui t′,v =v1,v2

dv · inf(v) + d1 · inf(v2) + d2 · inf(v1)

=∑

v pe frontiera lui t

dv · inf(v)− d1 · inf(v1)− d2 · inf(v2) + d1 · inf(v2) + d2 · inf(v1)

= LEP(t)− (d1 − d2) · (inf(v1)− inf(v2)< LEP(t)

Contradictie: s-a obtinut un arbore cu lungime externa ponderata mai mica. Rezulta d1 ≥ d2. sfdem

Lema 9.3. Presupunem x0 ≤ x1 ≤ · · · ≤ xn−1. Exista un arbore ın T (x) cu LEP minima si ın carevarfurile x0 si x1 sunt varfuri frate.

Demonstratie. Fie t un arbore cu LEP minima. Fie vi varful etichetat cu xi (inf(vi) = xi) si di distantade la radacina la varful vi, i = 0, . . . , n− 1. Deoarece xi ≤ xi+1 rezulta, conform lemei 9.2, di ≥ di+1 (ıncaz de egalitate consideram pe locul i varful mai departat de radacina). Fie vi varful frate al varfuluiv0. Avem d1 ≥ di (deoarece x1 ≤ xi) si d1 ≤ d0 = di (deoarece x1 ≥ x0 si v0 si vi sunt varfuri frate)care implica d1 = di. In arborele t interschimbam varfurile v1 si vi si obtinem un arbore t′ care satisfaceconcluzia lemei. sfdem

Lema 9.3 ne conduce direct la ideea algoritmului. Presupunem x0 ≤ x1 ≤ · · · ≤ xn−1. Stim caexista un arbore optim t ın care x0 si x1 sunt memorate ın varfuri frate. Tatal celor doua varfuri vamemora x0 + x1. Stergand cele doua varfuri ce memoreaza x0 si x1 se obtine un arbore t′. Fie t1′ unarbore optim pentru secventa y = 〈x0 + x1, x2, . . . , xn−1〉 si t1 arborele obtinut din t1′ prin “agatarea”a doua varfuri cu informatiile x0 si x1 de varful ce memoreaza x0 + x1. Avem LEP(t1′) ≤ LEP(t′) care

Page 143: algoritmi_tehnici_dorel lucanu - carte

9.4. ARBORI HUFFMAN 153

implica LEP(t1) = LEP(t1′) + x0 + x1 ≤ LEP(t′) + x0 + x1 = LEP(t). Dar cum t este optim, rezultaLEP(t1) = LEP(t) si de aici t′ este optim pentru secventa y. Consideram ın loc de secvente de numeresecvente de arbori si obtinem algoritmul:

procedure lep(x, n)begin

B ← t(x0), . . . , t(xn−1)while (#B > 1) do

alege t1, t2 din B cu inf(rad(t1)),inf(rad(t2)) minimeconstruieste arborele t ın care subarborii radacinii

sunt t1, t2 si inf(rad(t))=inf(rad(t1))+inf(rad(t2))B ← (B \ t1, t2)∪ t

end

In procedura lep, t(xi) desemneaza arborele format dintr-un singur varf etichetat cu xi iar rad(t) radacinaarborelui t. Initial se considera n arbori cu un singur varf, care memoreaza numerele xi, i = 0, . . . , n− 1.Pasul de alegere “greedy” consta ın selectarea a doi arbori cu etichetele din radacina minime si construireaunui nou arbore ce va avea radacina etichetata cu suma etichetelor din radacinile celor doi arbori si pecei doi arbori ca subarbori ai radacinii (fig. 9.2).

n1

n2

n n = n1 + n2

Figura 9.2: Constructia arborelui din pasul de alegere “greedy”

Discutia de mai sus conduce la urmatorul rezultat:

Teorema 9.2. Fie tm(x) unicul element din multimea calculata de schema procedurala din fig. ??.Arborele tm(x) are proprietatea:

LEP(tm(x)) = minLEP(t)|t ∈ T (x) (9.2)

Exercitiul 9.3.1. Sa se scrie un program care sa implementeze eficient schema procedurala ??. Sa sedetermine complexitatea timp a implementarii.

9.3.2 Implementare

Descrierea ca program a algoritmului de mai sus nu are prea mare importanta practica. De fapt, asacum vom vedea si ın sectiunile urmatoare, solutia de mai sus constituie mai mult un submodel ce va fiutilizat la rezolvarea unor probleme practice.

9.4 Studiu de caz: Arbori Huffman

9.4.1 Descrierea problemei

N mesaje M0, . . . , Mn−1 sunt receptionate cu frecventele f0, . . . , fn−1. Mesajele sunt codificate cu siruri(cuvinte) construite peste alfabetul 0, 1 astfel ıncat pentru orice i = j, codul mesajului Mi nu este unprefix al codului lui Mj . O astfel de codificare se numeste independenta de prefix (“prefix-free”). Notamcu di lungimea codului mesajului Mi. Lungimea medie a codului este

∑n−1i=0 fi · di. Problema consta ın

determinarea unei codificari cu lungimea medie minima.

Page 144: algoritmi_tehnici_dorel lucanu - carte

154 CAPITOLUL 9. ALGORITMI “GREEDY”

9.4.2 Modelul matematic

Unei codificari ıi putem asocia un arbore binar astfel ıncat mesajele corespund nodurilor de pe frontieraiar un cod descrie drumul de la radacina la mesajul corespunzator: 0 ınseamna deplasarea la fiul stangiar 1 deplasarea la fiul drept. Nodurile de pe frontiera arborelui sunt etichetate cu frecventele mesajelorcorespunzatoare: drumul de la radacina la un nod de pe frontiera descrie exact codul mesajului asociatacestui nod. Acum este usor de vazut ca determinarea unui cod optim coincide cu determinarea unuiarbore ponderat pe frontiera optim.

Exemplu: Codurile Huffman sunt utilizate la scrierea comprimata a textelor. Consideram textulHARABABURA. Mesajele sunt literele din text iar frecventele sunt date de numarul de aparitii alefiecarei litere ın text:

Litera FrecventaH 1A 4R 2B 3U 1

Constructia arborelui Huffman este reprezentata ın fig. 9.3. Codurile obtinute sunt:

Litera CodH 010A 1R 000B 001U 011

sfex

9.4.3 Implementare

Presupunem ca intrarea este memorata ıntr-un tabel T de structuri astfel ıncat T[i].mes reprezintamesajul i iar T[i].f frecventa mesajului i. Pentru implementare recomandam reprezentarea arborilorprin tablouri. Notam cu H tabloul reprezentand arborele Huffman. Semnificatia campului H[i].elt esteurmatoarea: daca i este nod intern atunci H [i].elt reprezinta informatia calculata din nod iar daca ieste pe frontiera (corespunde unui mesaj) atunci H [i].elt este adresa din T a mesajului corespunzator. Inultimul caz informatia din nod este T [H [i].elt].f . Notam am cu val(i) functia care intoarce informatiadin nodul i, calculata ca mai sus. Tabloul H, care ın final va memora arborele Huffman corespunzatorcodurilor optime, va memora pe parcursul constructiei acestuia colectiile intermediare de arbori. Astfelca, ın timpul executiei algoritmului de constructie a arborelui, H are trei parti (fig. 9.4): Prima parte atabloului va fi un “heap” care va contine radacinile arborilor din colectie. Partea de mijloc va continenodurile care nu sunt radacini. Cea de-a treia parte este vida si constituie zona ın care partea din mijloc sepoate extinde. Un pas al algoritmului de constructie ce realizeaza selectia greedy presupune parcurgereaurmatoarelor etape:

1. Muta radacina cu informatia cea mai mica pe prima pozitie libera din zona a treia, sa zicem k.Aceasta este realizata de urmatoarele operatii:

(a) copie radacina de pe prima pozitie din heap pe pozitia k:

H[k] ← H[1]k ← k + 1

(b) aduce ultimul element din heap pe prima pozitie:

H[1] ← H[m]m ← m - 1

Page 145: algoritmi_tehnici_dorel lucanu - carte

9.4. ARBORI HUFFMAN 155

4

A

2

R

2

B1

H1

U

2

4

A

4

A

2

R

2

B

1

U

1

1

H1

U

2

2

R

2

B

4

6

1

H1

U

2 4

A2

R

2

B

4

4

A

1

H1

U

2

2

R

2

B

4

6

1

H

0

0

0 01

1

1

1

c) d)

b)a)

e)

Figura 9.3: Constructia arborelui Huffman pentru HARABABURA

(c) reface heap-ul apeland subprogramul de introducere ın heap (gramada) de la HeapSort, adap-tat pentru structura de date de aici.

2. Muta din nou radacina cu informatia cea mai mica pe prima pozitie libera din zona a treia, darfara a o elimina din heap:

H[k] ← H[1]k ← k + 1

3. Construieste noua radacina si o memoreaza pe prima pozitie ın heap (ın locul celei mutate mai sus).

4. Reface heap-ul apeland subprogramul de introducere ın heap.

heap-ul radacinilornoduri care nu

nu sunt radacini zona vida

Figura 9.4: Organizarea tabloului H

Algoritmul rezultat are complexitatea timp O(n log n).

Page 146: algoritmi_tehnici_dorel lucanu - carte

156 CAPITOLUL 9. ALGORITMI “GREEDY”

9.5 Studiu de caz: Interclasare pe doua cai optima

9.5.1 Descrierea problemei

Se considera m liste liniare sortate a0, . . . , am−1 care contin n0, . . . , nm−1, respectiv, elemente dintr-o multime total ordonata. Interclasarea pe doua cai a celor m secvente consta ın executia repetata aurmatorului proces: se extrag din multime doua liste si se pune ın locul lor lista obtinuta prin interclasareaacestora. Procesul se continua pana cand se obtine o singura lista sortata cu cele n0+· · ·+nm−1 elemente.Problema consta ın determinarea unei alegeri pentru care numarul total de transferuri de elemente sa fieminim.

9.5.2 Modelul matematic

Mai ıntai consideram problema interclasarii a doua liste sortate:

Fie date doua liste sortate x = (x0, . . . , xm−1) si y = (y0, . . . , yn−1) ce contin elemente dintr-o multime total ordonata. Sa se construiasca o lista sortata z = (z0, . . . , zn+m−1) care sacontina cele m + n elemente ce apar ın x si y.

Utilizam notatia z = merge(x, y) pentru a nota faptul ca z este rezultatul interclasarii listelor x si y.Ideea algoritmului de interclasare, pe care-l prezentam aici, este urmatoarea:

– Se parcurg simultan, dar cu “viteze” diferite, cele doua liste x si y si se compara elementele xi siyj vizitate curent:

– daca xi ≤ yj atunci se transfera ın z elementul xi si se ınainteaza ın lista x (i := i + 1).

– daca xi > yj atunci se transfera ın z elementul yj si se ınainteaza ın lista y (j := j + 1).

– la epuizarea unei liste se introduc ın z elementele nevizitate ınca din cealalta lista.

Numarul de comparatii executate de algoritm este cel mult m+n−1 iar numarul de elemente transferateeste m + n.

Revenim la problema interclasarii a m liste. Mai ıntai consideram un exemplu. Fie m = 5, n0 =20, n1 = 60, n2 = 70, n3 = 40, n4 = 30. Un mod de alegere a listelor pentru interclasare este urmatorul::

b0 = merge(a0, a1)b1 = merge(b0, a2)b2 = merge(a3, a4)b = merge(b1, b2)

Numarul de transferuri al acestei solutii este (20 + 60) + (80 + 70) + (40 + 30) + (150 + 70) = 80 + 150 +70 + 220 = 520. Exista alegeri mai bune? Raspunsul este afirmativ si invitam cititorul sa gaseasca oastfel de alegere.

Unei alegeri i se poate atasa un arbore binar ın modul urmator:

– informatiile din varfuri sunt lungimi de secvente,

– varfurile de pe frontiera corespund secventelor initiale a0, . . . , am−1,

– varfurile interne corespund secventelor intermediare.

Pentru solutia de mai sus avem arborele din fig. 9.5a. Se observa usor ca acestia sunt arbori ponderatipe frontiera si numarul de transferuri de elemente corespunzator unei alegeri este egala cu LEP a ar-borelui asociat. Asadar, alegerea optima corespunde arborelui cu LEP minima. Algoritmul greedy careinterclaseaza optim cele m liste este urmatorul:

procedure interclOpt(x, n)begin

B ← a0, . . . , an−1while (#B > 1) do

Page 147: algoritmi_tehnici_dorel lucanu - carte

9.5. INTERCLASARE PE DOUA CAI OPTIMA 157

alege x1, x2 din B cu lungimi minimeintercl2(x1, x2, y)B ← (B \ x1, x2)∪ y

end

Pentru exemplul de mai sus, solutia optima data de algoritmul greedy este:

b0 = merge(a0, a4)b1 = merge(a3, b0)b2 = merge(a1, a2)b = merge(b1, b2)

si are asociat arborele cu lungime externa ponderata minima din fig. 9.5b. Numarul de comparatii este50 + 90 + 130 + 220 = 490.

20 60

70

80

150

40 30

70

220

20 30

40

50

90

60 70

130

220

a) b)

Figura 9.5: Arbori asociati algoritmilor de interclasare

9.5.3 Implementare

Presupunem ca listele sunt reprezentate prin tablouri. Urmatorul subprogram descrie strategia de inter-clasare a doua liste:

procedure intercl2(x, m, y, n, z)begin

i ← 0j ← 0k ← -1while ((i < m) and (j < n)) do

k ← k+1if (x[i] ≤ y[j])then z[k] ← x[i]

i ← i+1else z[k] ← y[j]

j ← j+1while (i < m) do

k ← k+1z[k] ← x[i]i ← i+1

while (j < n) dok ← k+1z[k] ← y[j]j ← j+1

end

Page 148: algoritmi_tehnici_dorel lucanu - carte

158 CAPITOLUL 9. ALGORITMI “GREEDY”

Exercitiul 9.5.1. Sa se rescrie algoritmul intercl2 pentru cazul cand cele doua liste sunt reprezentateprin liste liniare simplu ınlantuite. Noul algoritm va trebui sa fie mai eficient decat cel corespunzatortablourilor. De ce?

Programul care realizeaza interclasarea optima pe doua cai cele m liste liniare este foarte simplu sidescrierea sa o lasam ca exercitiu.

9.6 Studiu de caz: Problema rucsacului I (varianta continua)

9.6.1 Descrierea problemei

Se considera n obiecte notate cu 0, 1, . . . , n − 1 de dimensiuni (greutati) w0, w1, . . . , wn−1, respectiv, siun rucsac de capacitate M . Daca ın rucsac se pune o parte fractionara xi, 0 ≤ xi ≤ 1, din obiectul i,atunci se obtine un profit pi · xi (pi > 0). Umplerea rucsacului cu fractiunile (cantitatile) x0, . . . , xn−1

aduce profitul total∑n−1

i=0 pixi. Problema consta ın a determina partile fractionare x0, . . . xn−1 care aducun profit total maxim.

9.6.2 Modelul matematic

Problema ar putea fi formulata si ca o problema de optim, ın modul urmator:

– functia obiectiv:

maxn−1∑i=0

pixi

– restrictii:n−1∑i=0

wixi ≤M

0 ≤ xi ≤ 1 pentru i = 0, . . . , n− 1

Daca∑n−1

i=0 wi ≤ M atunci se va lua xi = 1, 0 ≤ i ≤ n − 1 pentru a obtine solutia optima. De aceeavom presupune ca

∑n−1i=0 wi > M . In acest caz, nu toate fractiunile xi pot fi egale cu 1. In plus, rucsacul

poate fi umplut exact, i.e. putem alege xi astfel ıncat∑n−1

i=0 wixi = M .Vom prezenta doua strategii greedy: una care nu determina totdeauna solutia optima – pentru a

evidentia ca nu totdeauna alegerea locala cea mai lacoma conduce la solutia optima – si una care datotdeauna solutia optima.

9.6.2.1 Solutia 1

La fiecare pas se va introduce ın rucsac obiectul care aduce profit maxim. La ultimul pas, daca obiectulnu ıncape ın totalitate, se va ıntroduce numai o parte fractionara a sa. Descrierea algoritmului este datade schema procedurala rucsac I1:

procedure rucsac I1(w, p, x, n)begin

S ← 0, . . . , n− 1for i ← 0 to n-1 do

x[i] ← 0while ((C < M) and (S = ∅)) do

alege i ∈ S care maximizeaza profitul peste SS ← S \ iif (C + w[i] ≤ M)then C ← C + w[i]

x[i] ← 1else C ← M

x[i] ← M− Cw[i]

end

Page 149: algoritmi_tehnici_dorel lucanu - carte

9.6. PROBLEMA RUCSACULUI I (VARIANTA CONTINUA) 159

Exercitiul 9.6.1. Sa se formuleze algoritmul rucsac I1 ın termenii sectiunii ??.

Procedura rucsac_I1 are dezavantajul ca nu determina optimul ıntodeauna. Consideram urmatorul

Exemplu: Presupunem n = 3, M = 10, iar dimensiunile si profiturile obiectelor date de urmatorultabel:

0 1 2wi 6 4 8pi 3 4 6

Algoritmul rucsac_I1 va determina solutia x = (0, 12 , 1) care produce profitul

∑pixi = 1

2 · 4 + 1 · 6 = 8.

Se observa ca vectorul x′ = (0, 1, 34) produce un profit mai bun:

∑pix

′i = 1 · 4 + 3

4 · 6 = 172 > 8. sfex

9.6.2.2 Solutia 2

La fiecare pas va fi introdus ın rucsac obiectul care aduce profit maxim pe unitatea de capacitate (greutate)utilizata, adica obiecul care maximizeaza fractia pi

wipeste multimea obiectelor neintroduse ınca (a se vedea

schema procedurala din fig. ??). In loc de actualizarea variabilei C care reprezinta capacitatea partialaa rucsacului, s-a preferat variabila CR care reprezinta capacitatea ramasa de completat.

procedure rucsac I2(w, p, x, n)begin

S ← 0, . . . , n− 1for i ← 0 to n-1 do

x[i] ← 0while ((C < M) and (S = ∅)) do

alege i ∈ S care maximizeaza profitul pe unitatea de greutate peste SS ← S \ iif (C + w[i] ≤ M)then C ← C + w[i]

x[i] ← 1else C ← M

x[i] ← M− Cw[i]

end

Corectitudinea strategiei este data de urmatorul rezultat.

Teorema 9.3. Procedura rucsac_I2 determina solutia optima (cu profit maxim).

Demonstratie. Presupunem p0w0≥ · · · ≥ pn−1

wn−1. Fie x = (x0, · · · , xn−1) solutia generata de procedura

Rucsac_I2. Daca xi = 1, 0 ≤ i < n, atunci evident ca aceasta solutie este optima. Altfel, fie j primulindice pentru care xj = 1. Din algoritm, se observa ca xi = 1 pentru orice 0 ≤ i < j si xi = 0 pentrui > j. Fie y = (y0 · · · yn−1) o solutie optima (care maximizeaza profitul). Avem

∑n−1i=0 yiwi = M . Fie k

cel mai mic indice pentru care xk = yk. Exista urmatoarele posibilitati:

(i) k < j. Rezulta xk = 1 si de aici yk = xk implica yk < xk.

(ii) k = j. Deoarece∑

xi · wi = M si xi = yi, 1 ≤ i < j, rezulta ca yk < xk (altfel∑

yi · wi > M careconstituie o contradictie).

(iii) k > j. Rezultan−1∑i=0

yi · wi >j∑

i=0

xi · wi = M . Contradictie.

Page 150: algoritmi_tehnici_dorel lucanu - carte

160 CAPITOLUL 9. ALGORITMI “GREEDY”

Deci, toate situatiile conduc la concluzia yk < xk si k ≤ j. Marim yk cu diferenta pana la xk si scoatemaceasta diferenta din secventa (yk+1, . . . , yn−1) astfel ıncat capacitatea utilizata sa ramına tot M . Rezultao noua solutie z = (z0, . . . , zn−1) care satisface:

zi = xi, 0 ≤ i ≤ k

∑k<i≤n−1

(yi − zi) · wi = (xk − yk) · wk

Avem:

n−1∑i=0

zi · pi =n−1∑i=0

yi · pi +∑

0≤i<k

zi · pi + zk · pk +∑

k<i<n

zipi −∑

0≤i<k

yipi − yk · pk−

−∑

k<i<n

yipi

=n∑

i=0

yi · pi + (zk − yk) · pk · wkwk−

∑k<i<n

(yi − zi) · pi · wiwi

≥n−1∑i=0

yi · pi + (zk − yk) · wkpkwk−

∑k<i<n

(yi − zi) · wi · pkwk

=n−1∑i=0

yi · pi

Deoarece y este solutie optima, rezulta∑n−1

i=0 zipi =∑n−1

i=0 yipi. Solutia z are urmatoarele doua pro-prietati:

• este optima, si

• coincide cu x pe primele k pozitii (y coincidea cu x numai pe primele k − 1 pozitii).

Procedeul de mai sus este repetat (considerand z ın loc de y) pana cand se obtine o solutie optima carecoincide cu x. sfdem

Implementare Complexitatea timp a algoritmului rucsac_I2 este O(n2). Dar daca intrarile satisfacp0w0≥ · · · ≥ pn−1

wn−1, atunci algoritmul rucsac_I2 necesita timpul O(n). La acesta trebuie adaugat timpul

de preprocesare (ordonare) care este O(n log n).

9.7 Studiu de caz: Secventializarea optima a activitatilor cutermen de realizare si profit

9.7.1 Descrierea problemei

Consideram n activitati numerotate cu 0, 1, . . . , n−1. Presupunem ca realizarea fiecarei activitati dureazao unitate de timp si ca prima activitate ıncepe la timpul zero. Realizarea activitatii i aduce un profitp(i) > 0, i = 0, . . . , n − 1. Exista constrangerea ca fiecare activitate i sa fie terminata la termenullimita d(i) (d(i) reprezinta durata maxima care este la dispozitie pentru a executa i). Problema consta ındeterminarea unei liste liniare (s(0), . . . , s(k−1)), care constituie o secventializare a realizarii activitatilor,astfel ıncıt orice activitate este realizata ın termen, i.e. d(s(i)) ≥ i, si profitul dat de aceasta este maxim.

Exemplu: Presupunem n = 4. Termenele de excutie si profiturile sunt date ın urmatorul tabel:

i 0 1 2 3d(i) 2 3 1 2p(i) 20 35 35 25

O solutie este (1, 4, 2) cu profitul 20+25+35 = 80 iar o alta solutie este (3, 4, 2) cu profitul 35+25+35 = 95.Exista secventializari ce aduc un profit mai mare? sfex

Page 151: algoritmi_tehnici_dorel lucanu - carte

9.7. SECVENTIALIZAREA OPTIMA A ACTIVITATILOR 161

9.7.2 Modelul matematic

Numim secventa acceptabila o lista (s(0), . . . , s(k − 1)) cu proprietatea d(s(i)) ≥ i, i = 0, . . . , k − 1, i.e.orice activitate i este realizata ın termen. Suntem interesati ın a gasi o lista liniara s∗ cu proprietatea:

∑i

p(s∗(i)) = max

∑i

p(s(i)) | s solutie acceptabila

Aceste secvente le numim solutii optime. Urmatorul rezultat arata ca, pentru o solutie acceptabila, dacaordonam activitatile dupa termenele de predare, atunci se obtine tot o solutie acceptabila.

Teorema 9.4. Fie s = (s(0), . . . , s(k − 1)) o secventializare a k lucrari. Daca s este acceptabila siπ = (π(0), . . . , π(k − 1)) este o permutare a multimii 0, . . . , k − 1 astfel ıncat d(s(π(0))) ≤ · · · ≤d(s(π(k − 1))), atunci s(π) = (s(π(0)), . . . , s(π(k − 1))) este o secventa acceptabila.

Demonstratie. Presupunem ca exista i < j astfel ıncıt d(s(i)) > d(s(j)). Consideram s′ = (. . . , s′(i) =s(j), . . . , s′(j) = s(i), . . .) (ın rest coincide cu s). Din d(s(j)) ≥ j > i rezulta d(s′(i)) > i si din d(s(i)) >d(s(j)) ≥ j rezulta d(s′(j)) > j. Repetand rationamentul de mai sus, la un moment dat vom obtinesecventa care satisface concluzia teoremei. sfdem

Observatie: Teorema de mai sus este adevarata si ın cazul cand timpii de executie ai activitatilor potfi diferiti. sfobs

Teorema 9.4 ne permite sa facem urmatoarea modificare asupra definitiilor pentru solutie acceptabilasi solutie optima. Fie B ⊆ 0, . . . , n− 1. Spunem ca B este o solutie acceptabila daca exista o secventaacceptabila (s(0), . . . , s(k − 1)) astfel ıncat B = s(0), . . . , s(k − 1). B este solutie optima daca existao secventa optima s∗ = (s∗(0), . . . , s∗(k − 1)) astfel ıncat B = s∗(0), . . . , s∗(k − 1). Cu aceste definitiiputem descrie algoritmul greedy care rezolva secventializarea optima a activitatilor. Pasul de alegeregreedy va selecta de fiecare data o activitate care aduce un profit maxim si formeaza o solutie acceptabilacu celelalte activitati alese pana ın acel moment. Schema procedurala a algoritmului este:

procedure secvact(p, d, n, B)begin

X ← 0, . . . , n− 1B ← ∅while (X = ∅) do

alege i din X cu profit maximX ← X \ iif B ∪ i este solutie acceptabilathen B ← B ∪ i

end

Exercitiul 9.7.1. Sa se arate ca familia solutiilor accesibile formeaza un sistem accesibil. Care suntbazele acestui sistem accesibil?

Corectitudinea algoritmului secvact este data de urmatoarea teorema.

Teorema 9.5. Fie B multimea determinata de algoritmul descris de procedura secvact. Orice secventializareacceptabila a lui B este optima.

Demonstratie. Presupunem B = i0, . . . , ik−1 si fie B′ = j0, . . . , jk′−1 o solutie optima. Ideeademonstratiei este urmatoarea: Daca B′ = B si cele doua multimi au r elemente comune, atunci seconstruieste o solutie optima B′′ care are r + 1 elemente comune cu B. Procedeul se repeta pana candse obtine o solutie optima care coincide cu B. Putem presupune, fara sa restrangem generalitatea, cap(i0) ≥ · · · ≥ p(ik−1) si ca p(j0) ≥ · · · ≥ p(jk′−1). In plus, daca p(ja) = p(ja+1) atunci ja < ja+1. Deasemenea, presupunem ca algoritmul determina activitatile tot ın aceasta ordine (dintre toate activitatilecu acelasi profit o va alege pe cea cu numarul de ordine (indicele) mai mic). Exista urmatoarele posibilitati:

Page 152: algoritmi_tehnici_dorel lucanu - carte

162 CAPITOLUL 9. ALGORITMI “GREEDY”

1. B ⊂ B′. Din modul cum lucreaza algoritmul secvact, rezulta ca B′ nu este acceptabila (la B nuse mai poate adauga nimic astfel ıncat sa se poata obtine o secventializare acceptabila).

2. B′ ⊂ B. Rezulta ca B′ nu este solutie optima.

3. B si B′ incomparabile. Vom arata ca putem alege ia ∈ B\B′ si jb ∈ B′\B cu d(jb) ≤ d(ia). Alegemia cu a ≤ mink, k′, ia = ja si a este cel mai mic cu aceasta proprietate. Fie T = 0, . . . , t−1 = = ia | d() ≤ d(ia). Presupunem d(0) ≤ · · · ≤ d(t−1). Distingem urmatoarele doua subcazuri:

(a) T ⊆ B. Rezulta ca pentru orice jb ∈ B′ \ B avem d(jb) > d(ia) > t. Fie s o secventializareacceptabila a lui B′ (ordonata crescator dupa termenele de executie). Urmeaza ca secventa(s(0) = 0, . . . , s(t − 1) = t−1, ia, s(t), . . .) este acceptabila si de aici rezulta B′ ∪ ia ac-ceptabila (ın orice secventa acceptabila a lui B′ poate fi inserat si ia). Dar aceasta contrazicefaptul ca B′ este optima.

(b) ∃jb ∈ T astfel ıncat jb ∈ B. Din definitia multimii T rezulta d(ia) ≥ d(jb). Deci B′′ =B′ \ jb ∪ ia este acceptabila. Din modul de alegere a lui ia rezulta p(ia) ≥ p(jb) careimplica B′′ optima.

Deci, ın singurul caz posibil, am obtinut o solutie optima care are a elemente comune cu B (B′ aveanumai a−1 elemente comune cu B). Repetand procedeul, vom obtine la un moment dat o solutie optimaB∗ = B. Acum teorema este demonstrata complet. sfdem

9.7.3 Implementare

Datorita teoremei 9.4 putem determina direct secventa optima s∗ cu d(s∗(0)) ≤ · · · ≤ d(s∗(k − 1)).Vom utiliza o variabila s:TSecventa si o variabila k:Integer astfel ıncat S = s[0], . . . , s[k − 1] sid(s[0]) ≤ · · · ≤ d(s[k − 1]). Testarea proprietatii daca S ∪ i este admisibila se face prin inserarea luii ın tabloul s astfel ıncat ordonarea nedescrescatoare a termenilor de executie sa fie posibila. Pentru caalgoritmul de inserare sa poata fi descris uniform este util de considerat o activitate 0 cu d(0) = p(0) = 0.Strategia de cautare este urmatoarea:

– Se cauta secvential indicele i0 cu

d(s[i0]) ≤ d(i) ≤ d(s[i0 + 1])

– Se verifica proprietatea:(∀j)i0 + 1 ≤ j < k ⇒ d(s[j]) ≥ j + 1

– Daca rezultatul evaluarii este true atunci insereaza i la pozitia i0 + 1.

Conditiile de mai sus pot fi combinate ıntr–una singura:

– Se determina secvential de la dreapta la stanga primul i0 cu proprietatea:

d[s[i0]] ≤ d[i] ∨ d[s[i0]] = i0

– Daca procesul de cautare se termina cu d[s[i0]] ≤ d[i] atunci din d[s[j]] ≥ j ∧ d[s[j]] = j rezultad[s[j]] ≥ j + 1, pentru orice j > i0. In acest caz se insereaza i pe pozitia i0 + 1.

Alegerea activitatilor de profit maxim este mai usoara daca acestea se considera sortate dupa profit:p[0] ≥ · · · ≥ p[n− 1]. Descrierea strategiei de mai sus este urmatoarea:

procedure secvact(p, d, n, s, k)begin

p[0] ← 0d[0] ← 0s[0] ← 0for i ← 1 to n-1 do

j ← k

Page 153: algoritmi_tehnici_dorel lucanu - carte

9.8. PROBLEMA INSTRUCTORULUI DE SCHI 163

while ((d[s[j]] > d[i]) and (d[s[j]] > j)) doj ← j-1

if (d[s[j]] ≤ d[i])then i0 ← j

for j ← k downto i0+1 dos[j+1] ← s[j]

s[i0+1] ← ik ← k+1

end

O bucla for executa O(k) operatii si deci complexitatea algoritmului este O(1)+ · · ·+O(n) = O(n2).Complexitatea poate fi redusa aproape de O(n) reprezentand multimile prin arbori si utilizand algoritmii“union” si “find” pentru operatiile asupra multimilor [HS84].

9.8 Studiu de caz: Problema instructorului de schi

9.8.1 Descrierea problemei

Un instructor de schi are la dispozitie n perechi de schiuri pe care trebuie sa le distribuie la n eleviıncepatori. Problema instructorului consta ın faptul ca distribuirea trebuie facuta ın asa fel ıncat sumadiferentelor absolute dintre ınaltimea elevului si lungimea schiurilor atribuite sa fie minima.

9.8.2 Modelul matematic

Notam cu x0, . . . , xn−1 ınaltimile elevilor si cu y0, . . . , yn−1 ınaltimile schiurilor. Problema revine larezolvarea urmatoarei probleme de optim:

minπ∈Sn

n−1∑i=0

|xi − yπ(i)|

unde prin Sn am notat multimea permutarilor elementelor 0, . . . , n− 1. Strategia greedy propusa esteurmatoarea: la cel mai mic elev fara schiuri se atribuie cea mai scurta pereche de schiuri disponibila.Descrierea acestei strategii este:

procedure ski(x, y, n, B)begin

X ← x0, . . . , xn−1Y ← y0, . . . , yn−1B ← ∅while ((X = ∅) and (Y = ∅)) do

x ← min XX ← X \ xy ← min YY ← Y \ yB ← B ∪ (x, y)

end

Fara sa restrıngem generalitatea presupunem x0 ≤ x1 ≤ · · · ≤ xn−1. Cu aceasta presupunere, criteriulde alegere locala se reduce la a considera elevii ın ordine crescatoare. Corectitudinea strategiei de maisus este data de urmatoarea teorema:

Teorema 9.6. Notam cu S(π) suman−1∑i=0

|xi − yπ(i)|. Daca yπ(0) ≤ · · · ≤ yπ(n−1) atunci:

S(π) = minS(π′) | π′ permutare a multimii 0, 1, . . . , n− 1

Page 154: algoritmi_tehnici_dorel lucanu - carte

164 CAPITOLUL 9. ALGORITMI “GREEDY”

Demonstratie. Fie π o permutare oarecare cu i < j, yπ(i) > yπ(j). Vom arata ca S(π′) ≤ S(π), unde π′

este produsul lui π cu transpozitia (i, j). Distingem urmatoarele cazuri:

1. xi ≤ xj ≤ yπ(i).

(a) yπ(j) < xi ≤ xj ≤ yπ(i). Avem:

|yπ(i) − xi|+ |xj − yπ(j)| = |yπ(i) − xj |+ |xi − yπ(j)|+ 2(xj − xi)≥ |yπ(i) − xj |+ |xi − yπ(j)|

(b) xi ≤ yπ(j) ≤ xj ≤ yπ(i). Avem:

|yπ(i) − xi|+ |xj − yπ(j)| = |yπ(i) − xj |+ |yπ(j) − xi|+ 2(xj − yπ(j))≥ |yπ(i) − xj |+ |yπ(j) − xi|

(c) xi ≤ xj ≤ yπ(j) ≤ yπ(i). Avem:

|yπ(i) − xi|+ |yπ(j) − xj | = |yπ(j) − xi|+ |yπ(i) − xj |

2. yπ(j) < yπ(i) < xj .

(a) xi ≤ yπ(j) < yπ(i) < xj . Avem:

|yπ(i) − xi|+ |xj − yπ(j)| = |yπ(j) − xi|+ |xj − yπ(i)|+ 2(yπ(i) − yπ(j))≥ |yπ(j) − xi|+ |xj − yπ(i)|

(b) yπ(j) < xi ≤ yπ(i) < xj . Avem:

|yπ(i) − xi|+ |xj − yπ(j)| = |xj − yπ(i)|+ |xi − yπ(j)|+ 2(yπ(i) − xi)≥ |xj − yπ(i)|+ |xi − yπ(j)|

(c) yπ(j) < yπ(i) < xi ≤ xj . Avem:

|xi − yπ(i)|+ |xj − yπ(j)| = |xj − yπ(i)|+ |xi − yπ(j)|

Deci, ın toate cazurile rezulta:

|xi − yπ(i)|+ |xj − yπ(j)| ≥ |xi − yπ(j)|+ |xj − yπ(i)|

Acum are loc:S(π′) =

∑k =i,j

|xk − yπ(k)|+ |xi − yπ(j)|+ |xj − yπ(i)|

≤∑

k =i,j

|xk − yπ(k)|+ |xi − yπ(i)|+ |xj − yπ(j)|

= S(π)

Am obtinut urmatoarea proprietate:

(∀i, j)i < j, yπ(i) > yπ(j), π′ = π · (i, j)⇒ S(π′) ≤ S(π)

Rezulta ca permutarea π cu proprietatea yπ(0) ≤ · · · ≤ yπ(n−1) realizeaza minimul functiei S. sfdem

Corolar 9.1. Daca(∀i, j)xi ≤ yj sau (∀i, j)yj ≤ xi

atunci S(π) = const.

Exercitiul 9.8.1. [MS91] Sa se arate ca algoritmul ski minimizeaza de asemenea si functia S(π) =max|xi − yπ(i)| | 0 ≤ i ≤ n− 1 (diferenta pentru cazul cel mai nefavorabil).

Page 155: algoritmi_tehnici_dorel lucanu - carte

9.9. PREZENTARE FORMALA A PARADIGMEI 165

9.9 Prezentare formala a paradigmei

9.9.1 Modelul matematic

Fie S o multime finita de intrari si C o colectie de submultimi ale lui S. Spunem ca C este accesibila dacasatisface axioma de accesibilitate:

(∀X ∈ C)X = ∅ ⇒ (∃x ∈ X)X \ x ∈ C (9.3)

Daca C este accesibila atunci perechea (S, C) se numeste sistem accesibil.

Exercitiul 9.9.1. Fie S multimea definita la memorarea programelor 9.1.1 si C = B ⊂ S | B este bijectie.Sa se arate ca (S, C) este sistem accesibil.

Exercitiul 9.9.2. Fie G = (V, E) un graf. Definim S(G) = E si C(G) = X ⊆ E | (V, X) este arbore.Sa se arate ca (S(G), C(G)) este sistem accesibil.

Exercitiul 9.9.3. Sa se defineasca un sistem accesibil pentru arborii ponderati pe frontiera.

O submultime X ∈ C se numeste baza daca este maximala, i.e. nu exista x ∈ S \ X astfel ıncatX ∪ x ∈ C. O submultime X ∈ C care nu este baza se numeste extensibila. Cu alte cuvinte, daca Xeste extensibila atunci exista y ∈ S \X astfel ıncat X ∪ y ∈ C. Clasa de probleme pentru care se potdefini algoritmi “greedy” este definita de urmatoarea schema:

Se considera date un sistem accesibil (S, C) si o functie obiectiv f : C → R. Problema constaın determinarea unei baze B ∈ C care satisface:

f(B) = optimf(X) | X baza ın C

In general, prin optim vom ıntelege minim sau maxim. Strategia “greedy” consta ın gasirea unui criteriude selectie a elementelor din S care candideaza la formarea bazei optime (care da optimul pentru functiaobiectiv). Acest criteriu este numit alegere “greedy” sau alegere a optimului local. Formal, optimul localare o urmatoarea definitie [MS91]:

f(X ∪ x) = optimf(X ∪ y) | y ∈ S \X, X ∪ x ∈ C (9.4)

Aceasta strategie este descrisa schematic de urmatorul algoritm:

procedure greedy(S, B)begin

S1 ← SB ← ∅while (B este extensibila) do

alege un optim local x din S1 conform cu 9.4S1 ← S1 \ xB ← B ∪ x

end

Din pacate, numai conditia de accesibilitate nu asigura existenta totdeauna a unui criteriu de alegerelocala care sa conduca la determinarea unei baze optime. Aceasta ınseamna ca, pentru anumite probleme,putem proiecta algoritmi “greedy” care nu furnizeaza solutia optima ci o baza pentru care functia obiectivpoate avea valori apropiate de cea optima. Acesta este cazul, de exemplu, pentru anumite probleme NP-complete.

9.9.1.1 Matroizi

In aceasta subsectiune vom prezenta o clasa particulara de algoritmi “greedy” pentru care alegerile optimelocale conduc la determinarea unei baze optime.

Perechea M = (S, C) se numeste matroid daca satisface urmatoarele conditii:

Page 156: algoritmi_tehnici_dorel lucanu - carte

166 CAPITOLUL 9. ALGORITMI “GREEDY”

– proprietatea de ereditate:

X ∈ C ∧ X = ∅ ⇒ (∀x ∈ X)X \ x ∈ C,

– proprietatea de interschimbare:

X, Y ∈ C ∧ #X < #Y ⇒ (∃y ∈ Y \X)X ∪ y ∈ C.

Exercitiul 9.9.4. Sa se studieze daca (S, C) deinit ın exercitiul 9.9.1 poate fi extins la un matroid prinadaugarea ponderilor Li.

Exercitiul 9.9.5. Fie G = (V, E) un graf. Definim S(G) = E si C(G) = X ⊆ E | (V, X) este aciclic.Sa se arate ca (S(G), C(G)) este sistem accesibil. Ramane afirmatia adevarata daca ın loc de “aciclic”consideram arbore?

Fie G = (V, E) Un matroid ponderat este un matroid M = (S, C) ın care fiecare element x ∈ S areasociata o pondere w(x). Problemele pe care le consideram aici sunt definite dupa urmatorul sablon:

Se considera dat un matroid ponderat M = (S, C, w). Dacua X ⊆ S atunci definim w(X) =∑x∈X

w(x). Problema consta ın determinarea unei baze B ∈ C care satisface:

w(B) = maxw(X) | X baza ın C

Determinarea optimului local consta ın selectarea unui x ∈ S \X astfel ıncat

w(x) = maxw(y) | y ∈ S \X, X ∪ y ∈ C.

Deoarece optimul local este determinat numai pe baza ponderilor elementelor ramase, algoritmul “greedy”consta ın testarea tuturor elementelor din S ın ordinea descrescatoare a ponderilor w(x):

procedure greedyMatr(S, w, B)begin

sorteaza descrescator dupa w(x) SB ← ∅for l (fiecare x ∈ S considerat ın ordine descrescatoare dupa w(x)) do

if (B ∪ x ∈ C) then B ← B ∪ xend

Teorema 9.7. Daca M = (S, C, w) este un matroid ponderat, atunci algoritmul greedyMatr determinao baza optima.

Demonstratie. Fie x primul element din S ales de algoritmul greedyMatr. Mai ıntai arata urmatorulfapt: exista o baza optima A care contine x. Fie A′ o baza optima. Daca x ∈ A′, atunci luam A = A′.Presupunem ca x ∈ A′. Luam pentru ınceput A = x. Din definitia algoritmului greedyMatr, A ∈ C.Utlizand proprietatea de interschimbare ın mod repetat, adaugam elemente din A′ la pana cand #A =#A′. Exista y ∈ A′ astefl ıncat A = A′ \ x∪y. Din modul de alegere a lui x, avem w(x) ≥ w(y) careimplica:

w(A) = w(A′)− w(x) + w(y) ≥ w(A′).

Deoarece A′ este optima, rezulta w(A) = w(A′ si de aici avem ca A este optima. Acum demonstratiafaptului este terminata.Faptul de mai sus ne spune ca algoritmul greedy procedeaza corect cand ıl alege pe x pentru ca acestaapartine la o baza optima. Fie acum M ′ = (S′, w′, C′), unde S′ = y ∈ S | x, y ∈ C, w′ = |S′

(restrictia lui w la S′) si C′ = X ∈ C | X ∪ x ∈ C. Aplicand proprietatea de ereditate rezulta ca M ′

este matroid si daca A este o baza optima a lui M , atunci A\x este o baza optima pentru M ′ (matroiziiau proprietatea de substructura optima). Aplicand un rationament inductiv, obtinem ca B \ x estebaza optima pentru M ′. sfdem

Page 157: algoritmi_tehnici_dorel lucanu - carte

9.10. REFERINTE BIBLIOGRAFICE 167

9.9.2 Implementare

Presupunem ca pasul de alegere “greedy” selecteaza elemente x ın timpul O(kp) unde k = #S1 si catestarea conditiei B ∪ x ∈ C se face ın timpul O(q), unde = #B. Avem k + ≤ n. Presupunemcostul operatiilor B ∪ x si S1 − x egal cu O(1). Deoarece pasul de alegere este executat de n orirezulta ca strategia are complexitatea timp

T (n) = O(np + 1q) + · · ·+ O(1p + nq)= O(1p + · · ·+ np + 1q + · · ·+ nq)= O(np+1 + nq+1) = O(nmax(p+1,q+1))

Operatiile peste multimile S1 si B vor trebui descrise ın functie de reprezentarile concrete ale acestora.In cazul matrizilor ponderati, complexitatea timp pentru cazul cel mai nefavorabil poate fi redusa la

O(n log n) daca testarea conditiei B ∪ x ∈ C se face ın timpul O(1).

9.10 Referinte bibliografice

Prezentarea de aici se bazeaza pe [HS84, MS91, CLR93, Sed88, LG86]. Pentru aspectele teoretice privindmetoda greedy recomandam [MS91, Cro92, CLR93].

9.11 Exercitii

Exercitiul 9.1. Fie t un arbore binar cu n varfuri pe frontiera si cu proprietatea ca oricare varf internare exact doi fii si x = (x1, . . . , xn) o secventa de numere. Notam cu T (t, x) multimea arborilor ponderatipe frontiera care au forma t si varfurile de pe frontiera etichetate cu componentele secventei x. Doi arboridin T (t, x) difera numai prin ordinea de etichetare a celor n varfuri de pe frontiera. Sa se proiecteze unalgoritm greedy pentru determinarea arborelui cu LEP minima peste T (t, x).

Exercitiul 9.2. [MS91] (Alocarea optima a fisierelor pentru retele de calculatoare) Se considera o reteacu n noduri si o multime de fisiere la care au acces toate nodurile. Se presupune ca se cunoaste ın devanso secventa de cereri de regasire/modificare a informatiei din fisiere. Pentru fiecare cerere se cunoastenodul care a initiat cererea, fisierul invocat si numarul de biti ce urmeaza a fi transferati. O schema dealocare consta ıntr-o atribuire a fiecarui fisier la unul sau mai multe noduri. Avand mai multe copii aleaceluiasi fisier avem un avantaj ın regasirea informatiei: costul unei regasiri este zero daca fisierul estelocal si este egal cu numarul de biti transferati daca fisierul este accesat de la distanta. Dar multiplicareafisierelor creste costul operatiei de modificare ıntrucat fiecare copie trebuie modificata si astfel numarulde biti accesati pentru modificare este ınmultit cu numarul de copii aflate la distanta. De asemenea,existenta a mai multor copii duce la cresterea sigurantei ın exploatare; dar aceasta se ıntımpla pına la unpunct deoarece este o probabilitate foarte mica sa cada toate nodurile statiei. Functia care da castigulın siguranta depinde de numarul de copii si se supune urmatorului principiu: fiecare copie nou adaugataaduce un castig mai mic decat copia anterioara. Costul unei scheme de alocare se obtine prin ınsumareacosturilor cererilor de regasire/modificare din secventa data din care se scade castigul ın siguranta.

Sa se proiecteze un algoritm greedy care sa determine o schema de alocare optima si sa se demonstrezecorectitudinea sa.

Exercitiul 9.3. [HS84] (Schimbarea banilor) Fie An = a1, . . . , an o multime finita de tipuri de monezi.De exemplu: a1 = 100 lei, a2 = 50 lei, etc. Presupunem ca ai este ıntreg pentru orice i : 1 ≤ i ≤ n.Pentru fiecare tip exista o infinitate de monezi. Se pune problema ca pentru un numar ıntreg C dat, sase determine numarul minim de monezi care dau suma exact C (C poate fi schimbata numai cu monezide tipuri din An).

1. Sa se arate ca daca a1 > ... > an si an = 1 atunci exista C > 0 si o multime finita de monezi pentrucare problema nu are solutie.

2. Sa se arate ca daca an = 1 atunci problema are totdeauna solutie.

3. Sa se proiecteze un algoritm greedy pentru cazul particular An = kn−1, . . . , k0, k > 1.

Page 158: algoritmi_tehnici_dorel lucanu - carte

168 CAPITOLUL 9. ALGORITMI “GREEDY”

4. Sa se arate ca algoritmul gasit la 3 nu determina ıntotdeauna solutia optima pentru cazul general.

Exercitiul 9.4. [HS84] (Memorarea programelor II) Se considera n programe de lungimi 1, . . . , n ceurmeaza a fi memorate pe o banda. Un program i este regasit cu frecventa fi. Daca programele suntmemorate ın ordinea π(1), π(2), . . . , π(n) atunci timpul mediu de regasire este:

T =

∑nj=1 fπ(j) ·

∑jk=1 π(k)∑n

j=1 fj

Sa se scrie un algoritm greedy care determina ordinea de memorare ce minimizeaza timpul mediu deregasire. Sa se demonstreze corectitudinea algoritmului.

Exercitiul 9.5. [CLR93] Se considera o multime S = 1, 2, . . . , n de activitati care utilizeaza o aceeasiresursa. Fiecare activitate i are un timp de start si si un timp de terminare ti. Daca o activitate esteselectata atunci ea se va desfasura ın perioada de timp data de intervalul semideschis [si, ti). Douaactivitati i si j sunt compatibile daca intervalele [si, ti) si [sj, tj) nu se acopera, i.e. sau si ≥ tj sausj ≥ ti. Sa se proiecteze un algoritm greedy care sa determine o multime cu numar maxim de activitaticompatibile. Sa se dovedeasca corectitudinea algoritmului.

Exercitiul 9.6. Urmatoarea problema este cunoscuta ca arborele partial de cost minim: Dat un grafponderat G = 〈V, E〉 cu functia de cost c : E → R, sa se determine un arbore partial de cost minim.Urmatorul algoritm generic, bazat pe strategia greedy, determina arborele partial descris ca o multimede arce:

A ← ∅while A nu formeaza arbore partial do

determina o muchie i, j cu A ∪ i, j fara circuitesi de cost minim

A ← A ∪ i, j

Se cunosc doi algoritmi eficienti bazati pe schema de mai sus:

• Algoritmul lui Kruskal: multimea A este o colectie de arbori (padure). Pasul de alegere locala vaselecta muchia de cost minim care nu formeaza circuite cu muchiile alese pana ın acel moment.

• Algoritmul lui Prim: multimea A este arbore. Pasul de alegere locala selecteaza muchia de costminim care, ımpreuna cu celelalte alese pana ın acel moment, pastreaza proprietatea de arbore.

Sa se realizeze:

1. O implementare eficienta a algoritmului lui Kruskal, reprezentand A printr-o structura “union-find”.

2. O implementare eficienta a algoritmului lui Prim prin ıntretinerea unei structuri “heap”, pe care onotam cu Q. Fiecarui varf i i se asociaza o valoare cheie(i) ce reprezinta minimul dintre costurilemuchiilor care unesc acel varf cu un varf din arborele construit pana ın acel moment. Pe timpulexecutiei algoritmului, Q va memora, pe baza valorilor cheie(i) definite mai sus, varfurile care nusunt ın arbore. Iar multimea A va fi A = i, parinte(i) | i ∈ V \rad\Q, unde rad este radacinaarborelui (aleasa arbitrar) si parinte(i) este adresa varfului care realizeaza valoarea cheie(i).

Exercitiul 9.7. Urmatorul algoritm, cunoscut sub numele de algoritmul Dijkstra, determina drumurileminime ıntr-un digraf ponderat D = (〈V, A〉, ) care pleaca dintr-un varf i0 dat, ın cazul cand ponderile[i, j] sunt ≥ 0. Pentru fiecare varf i, d[i] va fi lungimea drumului minim de la i0 la i si p[i] va fipredecesorul lui i pe drumul minim de la i0 la i. Q este coada cu prioritati cu cheile date de valorile d[i].

procedure Dijkstra(D, i0, d, p)begin

for i ← 1 to n dop[i] ← 0

Page 159: algoritmi_tehnici_dorel lucanu - carte

9.11. EXERCITII 169

d[i] ← ∞d[i0] ← 0Q ← Vwhile Q = ∅ do

i ← citeste(Q)elimina(Q)for fiecare j ∈ listaDeAdiacenta(i) do

if (d[j] > d[i]+[i,j])then d[j] ← d[i] + [i,j]

p[j] ← iend

Se cere:

1. Sa se exemplifice executia algoritmului Dijkstra pentru digraful din fig. 9.6.

2. Notam cu δ(i0, i) lungimea drumului minim de la i0 la i (cand exista) si cu S(t) multimea varfurilori eliminate din Q pana la momentul t. Sa se arate ca daca i ∈ S(t) atunci d[i] = δ[i0, i].

3. Sa se arate ca algoritmul Dijkstra determina corect drumurile minime care pleaca din i0 (adicad[i] = δ[i0, i] pentru orice i, dupa terminare).

4. Sa se determine complexitatea algoritmului Dijkstra.

5. Sa se arate ca algoritmul Dijkstra este un algoritm greedy.

1 2

34

5

2

4 2

8

6

67

4

2

3

Figura 9.6: Exercitiul 9.7

Page 160: algoritmi_tehnici_dorel lucanu - carte

Capitolul 10

“Divide-et-impera”

10.1 Prezentare generala

10.1.1 Modelul matematic

Paradigma divide-et-impera (ın engleza divide-and-conquer) consta ın divizarea problemei initiale ındoua sau mai multe subprobleme de dimensiuni mai mici, apoi rezolvarea ın aceeasi maniera (recursiva)a subproblemelor si combinarea solutiilor acestora pentru a obtine solutia problemei initiale. Divizareaunei probleme se face pana cand se obtin subprobleme de dimensiuni mici ce pot fi rezolvate prin tehnicielementare. Paradigma poate fi descrisa schematic astfel:

procedure divideEtImpera(P, n, S)begin

if (n ≤ n0)then rezolva subproblema P prin tehnici elementareelse ımparte P in P1, . . . , Pa de dimensiuni n1, . . . , na

divideEtImpera(P1, n1, S1)...divideEtImpera(Pa, na, Sa)combina S1, . . . , Sa pentru a obtine S

end

Exemple tipice de aplicare a paradigmei divide-et-impera sunt algoritmii de parcurgere a arborilorbinari si algoritmul de cautare binara ın multimi total ordonate. Deoarece descrierea strategiei are uncaracter recursiv, aplicarea ei trebuie precedata de o generalizare de tipul problema → subproblema princare dimensiunea problemei devine o variabila libera.

Vom presupune ca dimensiunea ni a subproblemei Pi satisface ni ≤ nb, unde b > 1. In acest fel

pasul de divizare reduce o subproblema la altele de dimensiuni mai mici, ceea ce asigura proprietatea determinare a subprogramului recursiv. De asemenea, descrierea recursiva ne va permite utilizarea inductieirecursive pentru demonstrarea corectitudinii.

In continuare ne vom ocupa de evaluarea eficientei strategiei. Presupunem ca divizarea problemeiın subprobleme si asamblarea solutiilor necesita timpul O(nk). Complexitatea timp T (n) a algoritmuluiDivide_et_impera este data de urmatoarea relatie de recurenta:

T (n) =

O(1) , daca n ≤ n0

a · T (nb) + O(nk) , daca n > n0

(10.1)

Teorema 10.1. Daca n > n0 atunci:

T (n) =

O(nlogb a) , daca a > bk

O(nk logb n) , daca a = bk

O(nk) , daca a < bk

(10.2)

171

Page 161: algoritmi_tehnici_dorel lucanu - carte

172 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

Demonstratie. Fara sa restrangem generalitatea presupunem n = bm ·n0. De asemenea mai presupunemca T (n) = cnk

0 daca n ≤ n0 si T (n) = aT (nb) + cnk daca n > n0. Pentru n > n0 avem:

T (n) = aT (nb) + cnk

= aT (bm−1n0) + cnk

= a(aT (bm−2n0) + c(

nb

)k

) + cnk

= a2T (bm−2n0) + c[a(n

b)k + nk

]= · · ·

= amT (n0) + c

[am−1

(n

bm−1

)k

+ · · ·+ a(

nb

)k

+ nk

]= amcnk

0 + c[am−1bknk

0 + · · ·+ a(bm−1

)knk

0 + (bm)knk

0

]= cnk

0am

[1 + bk

a + · · ·+(

bk

a

)m]

= camm∑

i=0

(bk

a

)j

unde am renotat cnk0 prin c. Distingem cazurile:

1. a > bk. Seriam∑

i=0

(bk

a

)j

este convergenta si deci sirul sumelor partiale este convergent. De aici

rezulta T (n) = O(am) = O(alogb n) = O(nlogb a).

2. a = bk. Rezulta am = bkm = cnk si de aici T (n) = O(nkm) = O(nk logb n).

3. a < bk. Avem T (n) = O(am(bk

a )m) = O(bkm) = O(nk).

Acum teorema este demonstrata complet. sfdem

10.1.2 Implementare

??????????

10.2 Studiu de caz: Sortare prin interclasare (Merge Sort)

10.2.1 Modelul matematic

Consideram cazul cand lista liniara ce urmeaza a fi sortata este reprezentata printr-un tablou. Stimca prin interclasarea a doua liste sortate obtinem o lista sortata ce contine toate elementele listelorde intrare. Ideea este de a utiliza interclasarea ın etapa de asamblare a solutiilor: ın urma rezolvariirecursive a subproblemelor rezulta liste ordonate si prin interclasarea lor obtinem lista initiala sortata.Primul pas consta ın generalizarea problemei. Presupunem ca se cere sortarea unui tablou a[p..q] cu psi q variabile libere, ın loc de sortarea tabloului a[0..n-1] cu n variabila legata (deoarece este data deintrare). Divizarea problemei consta ın ımpartirea listei de sortat ın doua subliste a[p..m] si a[m+1..q], depreferat de lungimi aproximativ egale. Noi vom lua m =

[p + q

2

]. Asa cum am spus, faza de combinare

a solutiilor consta ın interclasarea celor doua subliste, dupa ce ele au fost sortate recursiv prin acelasiprocedeu. Pasul de baza este dat de faptul ca sublistele de lungime 1 sunt ordonate prin definitie:

procedure mergeSort(a, p, q)begin

if (p < q)

then m ←[p + q

2

]mergeSort(a, p, m)mergeSort(a, m+1, q)

Page 162: algoritmi_tehnici_dorel lucanu - carte

10.2. SORTARE PRIN INTERCLASARE 173

interclaseaza subtablourile (a[p], . . . , a[m]), (a[m + 1], . . . , a[q])utilizand un tablou temporar

end

Pasul de divizare a problemei ın subprobleme se face ın timpul O(1). Pentru faza de asamblare asolutiilor, reamintim ca interclasarea a doua secvente ordonate crescator se face ın timpul O(m1 + m2),unde m1 si m2 sunt lungimile celor doua secvente. Aplicand teorema 10.1 pentru a = 2, b = 2, k = 1rezulta ca algoritmul MergeSort va efectua sortarea unui tablou de lungime n ın timpul O(n log2 n).

10.2.2 Implementare

Implementarea metodei presupune rescrierea subprogramului de interclasare deoarece parametrii de in-trare sunt acum doua subsecvente adiacente ale unui tablou. Listele partiale obtinute ın timpul in-terclasarii vor fi memorate temporar ıntr-o variabila tablou auxiliara. Dupa terminarea procesului deinterclasare, lista rezultat va fi copiata ın locul subsecventelor de intrare. Astfel programul va utilizaO(n + log2 n) memorie suplimentara (tabloul auxiliar si stiva cu apelurile recursive).

procedure intercl2(a, p, q, m, temp)begin

i ← pj ← m+1k ← 0while ((i ≤ m) and (j ≤ q)) do

k ← k+1if (a[i] ≤ a[j])then temp[k]← a[i]

i ← i+1else temp[k]← a[j]

j ← j+1while (i ≤ m) do

k ← k+1temp[k]← a[i]i ← i+1

while (j ≤ n) dok ← k+1temp[k]← a[j]j ← j+1

end

procedure mergeSort(a, p, q)begin

if (p < q)

then m ←[p + q2

]mergeSort(a, p, m)mergeSort(a, m+1, q)intercl2(a, p, q, m, temp)for i ← p to q do

a[i] ← temp[i-p+1]end

Exercitiul 10.2.1. Sa se rescrie MergeSort pentru cazul cand lista de sortat este reprezentata printr-olista liniara simplu ınlantuita. Sa se compare eficienta noului algoritm cu cel corespunzator reprezentariicu tablouri.

10.2.2.1 Varianta nerecursiva

In continuare vom cauta sa gasim o varianta nerecursiva pentru MergeSort. Pentru aceasta sa observamca arborele subproblemelor generat de metoda (echivalent, arborele apelurilor recursive) este un arbore

Page 163: algoritmi_tehnici_dorel lucanu - carte

174 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

binar ın care varfurile de pe frontiera corespund subsecventelor de lungime 1. Varianta nerecursivava proceda la parcugerea acestui arbore ın maniera “bottom-up”, i.e. parcurge nivel cu nivel de lafrontiera spre radacina: ıntai sunt vizitate toate varfurile de pe nivelul cel mai mare (cel imediat superiorfrontierei), apoi dupa vizitarea varfurilor de pe nivelul h se trece la vizitarea varfurilor de pe nivelul h−1.Vizitarea unui varf al arborelui consta de fapt ın interclasarea a doua subtablouri. Deoarece adresa unuivarf poate fi calculata printr-o relatie simpla, nu este nevoie de gestionarea unei cozi care sa memorezeadresele varfurilor ce urmeaza a fi vizitate. De remarcat ca nivelul vizitat curent ın arbore da si lungimeasubsecventelor sortate deja. Frontiera corespunde subsecventelor de lungime 1, nivelul imediat superiorsubsecventelor de lungime 2, urmatorul subsecventelor de lungime 4, si asa mai departe (fig. 10.1).

Pentru a lucra corect, utilizam un tablou temporar temp cu urmatorul scop: daca se interclaseazasubsecvente din secventa a atunci rezultatul interclasarii va fi memorat ın temp, iar daca se interclaseazasubsecvente din temp atunci rezultatul va fi memorat ın a. In acest fel, listele intermediare (sortatepartial) vor fi memorate alternativ ın cele doua tablouri: a si temp.

Faza de interclasare a subsecventelor de pe un nivel este realizata ın modul urmator: se interclaseazaprimele doua subsecvente, apoi se interclaseaza cu a treia subsecventa cu a patra s.a.m.d. S-a preferat odescriere mai condensata a metodei de interclasare.

a

temp

a

temp

Figura 10.1: MergeSort nerecursiv

procedure intercl(secvin, secvout, n, ls)begin

i ← 0j ← lsk ← 0repeat

t ← ju ← j+lsif (u > n) then u ← nwhile ((i < t) and (j < u)) do

if (secvin[i] ≤ secvin[j])then secvout[k]← secvin[i]

i ← i+1k ← k+1

else secvout[k]← secvin[j]j ← j+1k ← k+1

while (i < t) dosecvout[k]← secvin[i]i ← i+1

Page 164: algoritmi_tehnici_dorel lucanu - carte

10.3. SORTAREA RAPIDA 175

k ← k+1while (j < u) do

secvout[k]← secvin[j]j ← j+1k ← k+1

i ← uj ← i+ls

until (j > n-1)for j ← i to n-1 do

secvout[j]← secvin[j]end

procedure mergeSortNerec(a, p, q)begin

ina ← truels ← 1while (ls < n) do

if (ina)then intercl(a,temp,n,ls)else intercl(temp,a,n,ls)ina ← not inals ← ls*2

if (not ina)for i ← 0 to n-1 do

a[i] ← temp[i]end

Exercitiul 10.2.2. Memorarea alternativa a listelor intermediare ın cele doua tablouri a si b reduceconsiderabil numarul transferurilor. Se poate aplica aceeasi tehnica si ın cazul subprogramului recursivMergeSort? Daca raspunsul este da sa se arate cum, iar daca este nu sa se dea o justificare a acestuia.

Exercitiul 10.2.3. Sa se rescrie mergeSortNerec pentru cazul cand lista de sortat este reprezentataprintr-o lista liniara simplu ınlantuita. Sa se evidentieze cateva dintre avantajele/dezavantajele utilizariiacestei reprezentari.

10.3 Studiu de caz: Sortarea rapida (Quick Sort)

10.3.1 Modelul matematic

Ca si ın cazul algoritmului MergeSort, vom presupune ca trebuie sortat tabloul a[p..q]. Divizareaproblemei consta ın alegerea unei valori x din a[p..q] si determinarea prin interschimbari a unui indice kcu proprietatile:

• p ≤ k ≤ q si a[k] = x;

• ∀i : p ≤ i ≤ k ⇒ a[i] ≤ a[k];

• ∀j : k < j ≤ q ⇒ a[k] ≤ a[j];

Elementul x este numit pivot. In general se alege pivotul x = a[p], dar nu este obligatoriu. Partitionareatabloului se face prin interschimbari care mentin invariante proprietati asemanatoare cu cele de mai sus.Se considera doua variabile index: i cu care se parcurge tabloul de la stanga la dreapta si j cu carese parcurge tabloul de la dreapta la stanga. Initial se ia i = p + 1 si j := q. Proprietatile mentinuteinvariante ın timpul procesului de partitionare sunt:

∀i′ : p ≤ i′ < i⇒ a[i′] ≤ x (10.3)

si∀j′ : j < j′ ≤ q ⇒ a[j′] ≥ x (10.4)

Page 165: algoritmi_tehnici_dorel lucanu - carte

176 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

Presupunem ca la momentul curent sunt interogate elementele a[i] si a[j] cu i < j. Distingem urmatoarelecazuri:

1. a[i] ≤ x. Transformarea i := i+1 pastreaza 10.3.

2. a[j] ≥ x. Transformarea j := j-1 pastreaza 10.4.

3. a[i] > x > a[j]. Daca se realizeaza interschimbarea a[i] ↔ a[j] si se face i := i+1 si j := j-1atunci ambele predicate 10.3 si 10.4 sunt pastrate.

Operatiile de mai sus sunt repetate pana cand i devine mai mare decat j. Considerand k = i − 1 siinterschimband a[p] cu a[k] obtinem partitionarea dorita a tabloului.

Dupa sortarea recursiva a subtablourilor a[p..k−1] si a[k+1..q] se observa ca tabloul este sortat deja.Astfel partea de asamblare a solutiilor este vida.

Algoritmul rezultat este:

procedure quickSort(a, p, q)begin

if (p < q)then determina prin interschimbari indicele k cu:

p ≤ k ≤ q∀i : p ≤ i ≤ k ⇒ a[i] ≤ a[k]∀j : k < j ≤ q ⇒ a[k] ≥ a[j]

quickSort(a, p, m)quickSort(a, m+1, q)

end

Cazul cel mai nefavorabil se obtine atunci cand la fiecare partitionare se obtine una din subproblemecu dimensiunea 1. Deoarece operatia de partitionare necesita O(q − p) comparatii, rezulta ca pentruacest caz numarul de comparatii este O(n2). Acest rezultat este oarecum surprinzator, avand ın vedereca numele metodei este “sortare rapida”. Asa cum vom vedea, ıntr-o distributie normala cazurile pentrucare QuickSort executa n2 comparatii sunt rare, fapt care conduce la o complexitate medie foarte bunaa algoritmului. In continuare determinam numarul mediu de comparatii. Presupunem ca q + 1 − p = n

(lungimea secventei) si ca probabilitatea ca pivotul x sa fie al k-lea element este 1n (fiecare element al

tabloului poate fi pivot cu aceeasi probabilitate 1n ). Rezulta ca probabilitatea obtinerii subproblemelor

de dimensiuni k − p = i− 1 si q − k = n− i este 1n . In procesul de partitionare, un element al tabloului

(pivotul) este comparat cu toate celelalte, astfel ca sunt necesare n−1 comparatii. Acum numarul mediude comparatii se calculeaza prin formula:

T med(n) =

(n− 1) + 1

n

n∑i=1

(T med(i− 1) + T med(n− i)) , daca n ≥ 1

1 , daca n = 0

Rezolvam aceasta recurenta. Avem:

T med(n) = (n− 1) + 2n (T med(0) + · · ·+ T med(n− 1))

nT med(n) = n(n− 1) + 2(T med(0) + · · ·+ T med(n− 1))

Trecem pe n ın n− 1:

(n− 1)T med(n− 1) = (n− 1)(n− 2) + 2(T med(0) + · · ·+ T med(n− 2))

Scadem:

nT med(n) = 2(n− 1) + (n + 1)T med(n− 1)

Page 166: algoritmi_tehnici_dorel lucanu - carte

10.3. SORTAREA RAPIDA 177

Impartim prin n(n + 1) si rezolvam recurenta obtinuta:

T med(n)n + 1 = T med(n− 1)

n + 2n + 1 −

2n(n + 1)

= T med(n− 2)n− 1 + 2

n + 2n + 1 −

(2

(n− 1)n + 2n(n + 1)

)= · · ·

= T med(0)1 + 2

1 + · · ·+ 2n + 1 −

(2

1 · 2 + · · ·+ 2n(n + 1)

)

= 1 + 2(

11 + 1

2 + · · ·+ 1n + 1

)− 2

(1

1 · 2 + · · ·+ 1n(n + 1)

)

Deoarece 1 + 12 + · · ·+ 1

n = O(log2 n) si seria∑ 1

k(k + 1) este convergenta (si deci sirul sumelor partiale

este marginit), rezulta ca T (n) = O(n log2 n).Am demonstrat urmatorul rezultat:

Teorema 10.2. Complexitatea medie a algoritmului QuickSort este O(n log2 n).

10.3.2 Implementare

Subprogramul Partitioneaza descrie algoritmul de divizare de mai sus:

procedure partitioneaza(a, p, q, k)begin

x ← a[p]i ← p + 1j ← qwhile (i ≤ j) do

if (a[i] ≤ x then i ← i + 1if (a[j] ≥ x then j ← j - 1if (i < j)then if ((a[i] > x) and (x > a[j]))

thenswap(a[i], a[j])i ← i + 1j ← j - 1

k ← i-1a[p] ← a[k]a[k] ← x

end

Daca se presupune ca are loc a[p− 1] ≤ a[i] ≤ a[q + 1], pentru orice i cu p ≤ i ≤ q, (aceasta implicaexistenta initiala a doua elemente artificiale a[−1] si a[n] cu a[−1] ≤ a[i] ≤ a[n], 0 ≤ i ≤ n − 1) atunciprocedura de partitionare poate fi descrisa mai simplu astfel:

procedure partitioneaza(a, p, q, k)begin

x ← a[p]i ← p - 1j ← q + 1while (i < j) do

repeat i ← i + 1 until (a[i] ≥ x)repeat j ← j - 1 until (a[j] ≤ x)if (i < j)thenswap(a[i], a[j])

k ← ja[p] ← a[k]a[k] ← x

end

Page 167: algoritmi_tehnici_dorel lucanu - carte

178 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

Exercitiul 10.3.1. Daca tabloul a contine multe elemente egale, atunci algoritmul Partitioneaza re-alizeaza multe interschimbari inutile (de elemente egale). Sa se modifice algoritmul astfel ıncat nouaversiune sa elimine acest inconvenient.

Exercitiul 10.3.2. Sa se modifice subprogramul de partitionare de mai sus prin ınlocuirea instructiuniiwhile cu repeat si a celor doua instructiuni repeat cu while. Atentie: partea de initilizare si parteade interschimbare vor fi modificate corespunzator pentru ca noul subprogram sa rezolve corect problemapartitionarii.

Exercitiul 10.3.3. Urmatorul program poate fi de asemenea utilizat cu succes pentru partitionareatabloului a[p..q]:

procedure partitioneaza(a, p, q, k)begin

i ← pj ← qiinc ← 0jinc ← -1while (i < j) do

if (a[i] > a[j])thenswap(a[i], a[j])

incaux ← iinciinc ← -jincjinc ← -incaux

i ← i+iincj ← j+jinc

k ← iend

Sa se demonstreze ca programul face o partitionare corecta. Ce proprietati invariante pastreaza instructiuneawhile?

Acum, programul care descrie algoritmul QuickSort este urmatorul:

procedure quickSort(a, p, q)begin

if (p < q)then partitioneaza(a,p,q,k)

quickSort(a, p, m)quickSort(a, m+1, q)

end

Exercitiul 10.3.4. Sa se rescrie QuickSort pentru cazul cand lista de sortat este reprezentata printr-olista liniara simplu ınlantuita.

10.4 Studiu de caz: Selectionare

Urmatoarea problema este o varianta a celei din exercitiul 4.1.7:

Sa se scrie un algoritm care avand la intrare un tablou (a[i] | 0 ≤ i < n) si un numark ∈ 0, 1, . . . , n − 1, schimba ordinea elementelor din a astfel ıncat la iesire pe pozitia k seafla cel de-al k + 1-lea numar cel mai mic (echivalent, cel de-al n− 1− k-lea cel mai mare).

Evident, orice algoritm de sortare rezolva problema de mai sus. Deoarece cerintele pentru selectie suntmai slabe decat cele de la ordonare, se pune firesc ıntrebarea daca exista algoritmi mai performanti decatcei utilizati la sortare. Conditia pe care trebuie sa o satisfaca la iesire tabloul a este formulata de:

(∀i)(i < k ⇒ a[i] ≤ a[k]) ∧ (i > k ⇒ a[i] ≥ a[k])

Page 168: algoritmi_tehnici_dorel lucanu - carte

10.5. LINIA ORIZONTULUI 179

Fie j o pozitie ın a astfel ıncat:

(∀i)(i < j ⇒ a[i] ≤ a[j]) ∧ (i > j ⇒ a[i] ≥ a[j])

Un asemenea j poate fi obtinut cu algoritmul de partitionare de la quickSort. Daca j = k atunciproblema este rezolvata. Daca j < k atunci cel de-al k-lea cel mai mic element trebuie cautat ın subtabloula[j+1..n], iar daca j > k atunci cel de-al k-lea cel mai mic element trebuie cautat ın subtabloula[1..j-1]. Aceasta conduce la urmatoarea formulare recursiva a algoritmului de selectare:

function selecteaza(a, p, q, k)begin

partitioneaza(a, p, q, k1)if (k1 = k)then return a[k]else if (k1 < k)

then selecteaza(a, k1+1, q, k)else selecteaza(a, p, k1-1, k)

end

Descrierea recursiva nu este avantajoasa deoarece produce un consum de memorie suplimentara (stivaapelurilor recursive) ce poate fi eliminat prin derecursivare:

function selecteaza(a, n, k)begin

p ← 0q ← n-1repeat

partitioneaza(a, p, q, k1)if (k1 = k)then if (k1 < k)

then p ← k1+1else q ← k1-1

until (k1 = k)return a[k]

end

Analiza algoritmului selecteaza este asemanatoare cu cea a algoritmului quickSort. In cazul celmai nefavorabil necesita O(n2) timp, iar pentru complexitatea medie se cunoaste urmatorul rezultat:

Teorema 10.3 ([Sed88]) Complexitatea timp medie a algoritmului Selecteaza este O(n). Mai precis,numarul de comparatii este aproximativ:

n + k log(n

k

)+ (n− k) log

(n

n− k

).

10.5 Studiu de caz: Linia orizontului

10.5.1 Descrierea problemei

Pe o suprafata orizontala se considera n paralelipipede (se poate presupune ca sunt cladiri) asezate astfelıncat toate paralelipipedele au o suprafata laterala paralela cu o aceeasi dreapta. In acest fel putemconsidera ca toate paralelipipedele au fata spre est. O sursa de lumina, aflata la o distanta destul demare astfel ıncat razele de lumina sunt paralele si cad perpendicular pe fetele paralelipipedelor (soareleputin timp dupa ce a rasarit), proiecteaza paralelipipedele pe un ecran (orizontul), presupus a fi suficientde mare. Se cere sa se determine conturul superior al umbrei (linia orizontului).

Page 169: algoritmi_tehnici_dorel lucanu - carte

180 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

10.5.2 Modelul matematic

In primul rand sa observam ca problema poate fi redusa de la o problema ın spatiul tridimensional la oproblema ın plan. Proiectia unui paralelipiped pe ecran este un dreptunghi cu baza pe axa Ox. Un astfelde dreptunghi poate fi specificat prin trei elemente: cele doua proiectii xstg < xdrp ale varfurilor pe axaOx si ınaltimea y. Deoarece un dreptunghi se poate afla partial sau total ın spatele altui dreptunghi,rezulta ca proiectiile se pot intersecta. In acest fel, linia orizontului va fi ınfasuratoarea superioara aunei colectii de dreptunghiuri ce au bazele pe axa Ox. Pentru ca domeniul problemei sa fie completspecificat, mai trebuie sa vedem ce ınseamna linia orizontului. Pentru aceasta, vom raspunde mai ıntaila ıntrebarea: din ce se compune linia orizontului? Consideram colectia de dreptunghiuri din fig. 10.2a.Linia orizontului corespunzatoare acestei colectii este reprezentata ın fig. 10.2b. Observam ca ea secompune din:

• doua semidrepte incluse ın axa Ox, care sunt extremitatile;

• segmente orizontale si verticale care sunt laturi, portiuni de laturi sau portiuni din axa Ox;

• ın plus linia orizontului are proprietatea ca orice dreptunghi se afla ıntre Ox si linia orizontului.

a)

b)

Figura 10.2: Linia orizontului

Proiectiile capetelor segmentelor orizontale pe axa Ox determina o secventa de puncte, pe care lenotam de la stanga la dreapta prin x1, x2, . . . , xk, xk+1 (s-a presupus ca linia este formata de k segmenteorizontale). Fiecare segment orizontal i are o ınaltime yi, 1 ≤ i ≤ k. Daca vom considera ın plusx0 = −∞, xk+2 = +∞, y0 = yk+1 = 0, rezulta ca secventa x0, y0, x1, y1, . . . , xk, yk, xk+1, yk+1, xk+2

reprezinta ın mod unic linia orizontului. Pentru exemplul nostru, linia este reprezentata de secventa(−∞, x1, y1, x2, 0, x3, y3, . . . , x8, 0, +∞) (fig. 10.3).

y1y2 = 0

y3y4 y5

y6

y7y0 = 0

x1 x2 x3 x4 x5 x6 x7 x8

y8 = 0

x9 = +∞x0 = −∞

Figura 10.3: Reprezentarea liniei orizontului

Page 170: algoritmi_tehnici_dorel lucanu - carte

10.5. LINIA ORIZONTULUI 181

In general, linia orizontului poate fi reprezentata printr-o lista liniara de 2k+1 numere reale: (x1, y1, . . . , xk, yk, xk+1)cu k ≤ n. Un dreptunghi poate fi considerat un caz particular de linie a orizontului (k = 1) si deci poatefi reprezentat de lista liniara (xstg , y, xdrp).

O colectie de dreptunghiuri va fi reprezentata de o variabila tablou d, unde d[i] este o structura cucampurile d[i].xstg, d[i].xdrp, d[i].y, precum si de o variabila de tip ıntreg n.

Vom rezolva problema determinarii liniei orizontului prin strategia divide-et-impera. Generalizampresupunand date dreptunghiurile (d[p], . . . , d[q]) ın loc de (d[1], . . . , d[n]). Exista doua moduri de adiviza problema:

1. Divizarea verticala. Se considera un z cu d[p].xstg ≤ z ≤ d[p].xdrp. O subproblema va fi formata dincolectia de dreptunghiuri aflate la stanga lui z si cealalta subproblema din colectia de dreptunghiuriaflate la dreapta lui z. Dreptunghiurile d[i] cu d[i].stg < z < d[i].drp (o latura verticala la stangalui z si cealalta la dreapta lui z) vor fi divizate ın doua dreptunghiuri prin considerarea unei laturiverticale duse prin z. Aceasta strategie are avantajul ca partea de asamblare este simpla (constadin concatenarea celor doua linii ale orizontului obtinute prin rezolvarea subproblemelor), dar aresi marele dezavantaj ca sunt cazuri cand pasul de divizare nu conduce la micsorarea numarului dedreptunghiuri pentru subprobleme. Ca exemplu, consideram urmatoarea colectia de doua drep-tunghiuri din fig. 10.4a. Indiferent cum ar fi ales z ıntre x1 si x4 (fig. 10.4b), cel putin una dinsubprobleme are doua sau mai multe dreptunghiuri (atentie, procesul de divizare poate conducechiar la marirea numarului de dreptunghiuri ıntr-o subproblema).

De remarcat totusi ca o ordonare lexicografica conduce la o simplificare a pasului de divizare.

x1 x3 x4x2

a)

x1 x3 x4x2 x1 x3 x4x2 x1 x3 x4x2z z z

b)

Figura 10.4: Un exemplu cand divizarea verticala nu reduce numarul de dreptunghiuri

2. Divizarea orizontala. Pasul de divizare este foarte simplu: prima subproblema este formata dinprimele

[n2

]dreptunghiuri, iar a doua subproblema din celelalte n −

[n2

]dreptunghiuri. Nu mai

este necesara ordonarea dreptunghiurilor. Acum este suficient sa se determine m =[p + q

2

]si

prima subproblema va contine colectia (sublista) d[p], . . . , d[m] iar a doua subproblema va continecolectia (sublista) d[m+1], . . . , d[q]. Partea de asamblare este un pic mai dificila pentru ca necesitainterclasarea celor doua linii obtinute prin rezolvarea subproblemelor.

Divizarea orizontala pare mai potrivita, motiv pentru care o alegem pentru determinarea liniei ori-zontului. Mai ıntai consideram un exemplu. Consideram colectia din fig. 10.5. Prin divizare se obtin

Page 171: algoritmi_tehnici_dorel lucanu - carte

182 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

14

3

2

Figura 10.5: Problema initiala

1

2

4

3

Figura 10.6: Divizarea ın subprobleme

subproblemele reprezentate ın fig. 10.6. Rezolvarea subproblemelor conduce la solutiile din fig. 10.7 careinterclasate dau linia reprezentata ın fig. 10.8.

In continuare vom descrie modul ın care se realizeaza interclasarea. Presupunem ca prin rezolvareasubproblemelor s-au obtinut liniile L1:TLinieOrizont cu valoarea (x1, y1, . . . , xm1, ym1, xm1+1) respectivL2:TLinieOrizont cu valoarea (x′

1, y′1, . . . , x

′m2, y

′m2, x

′m2+1). Procesul de interclasare are loc comparand

doua cate doua componentele orizontale ale celor doua linii si alegand de fiecare data pe cea cu ınaltimeamai mare. Notam ca termenul de interclasare este utilizat corect: cele doua linii L1 si L2 sunt listeordonate de segmente orizontale iar rezultatul este tot o lista ordonata de segmente orizontale. Lungimeacurenta a liniei rezultat este memorata de variabila m. Presupunem ca la momentul curent se comparaL1[i] = x[ i

2 ]+1 si L2[j] = x′[ j2 ]+1

. Pentru a simplifica scrierea, notam[

i2

]+ 1 cu i1 si

[j2

]+ 1 cu j1. De

asemenea, notam cu h1 ınaltimea curenta din L1, cu h2 ınaltimea curenta din L2, cu h ınaltimea curentadin linia rezultat L si cu h1, h2, respectiv h variabilele care memoreaza aceste ınaltimi. O variabila kva indica acea linie care contribuie ın pasul curent la linia rezultat: k = 1 indica faptul ca linia L1contribuie la formarea liniei L, si k = 2 indica faptul ca linia L2 contribuie la formarea liniei L. Distingemurmatoarele situatii:

1. xi1 < x′j1 . In continuare h1 va deveni egala cu L1[i + 1]. Daca i ≥ 2 ∗m1 + 1 atunci h1 va deveni

zero. Valoarea variabilei j ramane neschimbata. Se disting subcazurile:

(a) h1 < h2. Daca k = 1 (fig. 10.9) atunci h > h2 si ın continuare vom avea:

k ← 2L[m+1] ← L1 [i]L[m+2] ← h2h ← h2

Figura 10.7: Rezolvarea subproblemelor

Page 172: algoritmi_tehnici_dorel lucanu - carte

10.5. LINIA ORIZONTULUI 183

Figura 10.8: Asamblarea solutiilor

m ← m+2i ← i+2

h

h2

h1

xi1 x′j1

Figura 10.9: xi1 < x′j1

si h1 < h2

Daca k = 2 (fig. 10.10) atunci h = h2 si ın continuare k, m si h raman neschimbate. Singuramodificare care este i\primeste i+2.

h = h2

h1

xi1 x′j1

Figura 10.10: xi1 < x′j1 si h = h2

(b) h1 = h2 . Daca k = 1 (fig. 10.11) atunci h > h2 si ın continuare vom avea:

L[m+1] ← L1[i]L[m+2] ← h1h ← h1m ← m+2i ← i+2

iar k ramane neschimbata.Daca k = 2 (fig. 10.12) atunci h = h2 si ın continuare k, m, h raman neschimbate. Singuramodificare este i\primeste i+2.

(c) h1 > h2. Daca k = 1 (fig. 10.13) atunci h > h2 si ın continuare vom avea:

L[m+1] ← L1[i]L[m+2] ← h1h ← h1m ← m+2i ← i+2

iar k ramane neschimbata.Daca k = 2 atunci h = h2 si vom avea:

Page 173: algoritmi_tehnici_dorel lucanu - carte

184 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

h

h1 = h2

xi1 x′j1

Figura 10.11: xi1 < x′j1 si h1 = h2

h = h1 = h2

xi1 x′j1

Figura 10.12: xi1 < x′j1

si h = h1 = h2

k ← 1L[m+1] ← L1[i]L[m+2] ← h1h ← h1m ← m+2i ← i+2

2. xi1 = x′j1 . In continuare vom avea h1 va deveni egal cu L1[i + 1] (daca i ≥ 2 ∗m1 + 1 atunci h1

devine zero), h2 devine egal cu L2[j + 1] (daca j ≥ 2 ∗m2 + 1 atunci h2 devine zero). Distingemsubcazurile:

(a) h1 ≥ h2 (fig. 10.15). In continuare k, m si h ısi schimba valoarea numai daca h = h1, caz ıncare vom avea:

k ← 1L[m+1] ← L1[i]L[m+2] ← h1h ← h1m ← m+2i ← i+2j ← j+2

(b) h1 < h2 (fig. 10.16). Variabilele k, m si h ısi schimba valoarea numai daca h = h2 si ın acestcaz vom avea:

k ← 2L[m+1] ← L2[j]L[m+2] ← h2h ← h2m ← m+2

h

h1

h2

xi1 x′j1

Figura 10.13: xi1 < x′j1 si h, h1 > h2

Page 174: algoritmi_tehnici_dorel lucanu - carte

10.5. LINIA ORIZONTULUI 185

h1

h = h2

xi1 x′j1

Figura 10.14: xi1 < x′j1 si h1 > h = h2

xi1 = x′j1

h1

h2

Figura 10.15: xi1 = x′j1

si h1 ≥ h2

i ← i+2j ← j+2

xi1 = x′j1

h2

h1

Figura 10.16: xi1 = x′j1

si h1 < h2

3. xi1 > x′j1

. Se trateaza similar cazului 1.

Valorile initiale ale variabilelor sunt:

h1 ← 0h2 ← 0h ← 0k ← 1 /* 1 este ales arbitrar*/i ← 1j ← 1m ← 0

Revenim la aplicarea startegiei divide-et-impera. Vom considera drept cazuri de baza urmatoareledoua:

• Colectia nu are dreptunghiuri (n = 0). In acest caz linia orizontala coincide cu axa Ox.

• Colectia are un singur dreptunghi (n = 1). Linia orzontului coincide cu reprezentarea dreptunghi-ului.

Aplicand teorema 10.1 pentru cazul a = b = 2 si k = 1 obtinem ca algoritmul de determinare a linieiorizontului are complexitatea timp O(n log n).

10.5.3 Implementare

Programul Pascal descris aici este lung, dar usor de scris si de citit. Mai pot fi facute schimbari caresa reduca lungimea textului. De asemenea, anumite variabile pot fi eliminate. De exemplu, se poate

Page 175: algoritmi_tehnici_dorel lucanu - carte

186 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

tine cont de faptul ca h1 = L1[i − 1], h2 = L2[j − 1], h = L[m]. Considerand elementele suplimentareL1[0] = L2[0] = L[0] = 0, se poate renunta la utilizarea variabilelor h1, h2 si h.

Exercitiul 10.5.1. Descrierea algoritmului cu ajutorul unui subprogram recursiv are dezavantajul cautilizeaza doua tablouri locale pentru memorarea liniilor rezultate din rezolvarea subproblemelor. Sal-varea acestor tablouri ın stiva sistemului reduce semnificativ performantele programului. Sa se elimineacest inconvenient printr-un procedeu asemanator cu cel de la sortare prin interclasare.

10.6 Studiu de caz: Transformata Fourier discreta

10.6.1 Modelul matematic

Un semnal poate fi vazut din doua puncte de vedere diferite:

1. domeniul timp;

2. domeniul frecventa.

Notam cu f(t) functia care descrie semnalul ın domeniul timp si cu F (ν) functia care descrie semnalulın domeniul frecventei. Se poate trece dintr-o descriere ın alta prin transformata Fourier. Trecerea dindomeniul timp ın domeniul frecventa se face prin transformata Fourier directa:

F (ν) = F [f(t)] =∫ +∞

−∞f(t)e−2πiνtdt, (10.5)

iar trecerea de la domeniul frecventa la domeniul timp se face prin transformata Fourier inversa:

f(t) = F−1[F (ν)] =∫ +∞

−∞F (ν)e2πiνtdν. (10.6)

Trnsformata Fourier discreta se obtine cand se considera f(t) masurata ıntr-un numar finit de puncte:t0, . . . , tn−1 cu tj = jT , unde T este perioada de timp la care sa fac masuratorile. Notand xk = f(tk)pentru k = 0, . . . , n− 1, transformata Fourier discreta directa este data de relatia:

F [f(t)] =n−1∑k=0

xke−2πij

nT kT T = Tn−1∑k=0

xke−2πijk

n . (10.7)

Notam:

Wj =n−1∑k=0

xke−2πijk

n . (10.8)

Trnsformata Fourier discreta inversa este data de relatia:

xk =n−1∑j=0

WjT e2πijk

n1

nT=

1n

n−1∑j=0

Wje2πijk

n (10.9)

Daca se considera polinomul de variabila Y :

f(Y ) = x0 + x1Y + · · ·xn−1Yn−1 (10.10)

si radacinile de ordinul n ale unitatii:

wj = e2πij

n , j = 0, 1, . . . , n− 1

obtinemWn−j = f(wj), j = 0, 1, . . . , n− 1 (10.11)

unde am considerat Wn = W0.Radacinile de ordinul n ale unitatii satisfac urmatoarele proprietati:

Page 176: algoritmi_tehnici_dorel lucanu - carte

10.6. TRANSFORMATA FOURIER DISCRETA 187

Lema 10.1. Daca n este par, n = 2m, si j < m atunci −wj = wj+m.

Demonstratie. Avem w2j+m = (e

2πi(j+m)2m )2 = (e

2πij2m )2(e

2πim2m )2 = (e

2πij2m )2e

2πi2m2m = w2

j . Deoarece wj si

wj+m sunt distincte, rezulta wj = −wj+m. sfdem

Lema 10.2. Daca n este par, n = 2m, si 1 ≤ j < m atunci w2j este de asemenea o radacina = 1.

Demonstratie. Deoarece wnj = 1 rezulta (w2

j )n = 1. Pe de alta parte, w2j = (e

2πijn )2 = e

2πi(j+j)n =

wj+j = 1 pentru ca 2 ≤ j + j ≤ n− 2. sfdem

In continuare ne ocupam de un mijloc de calcul eficient al valorilor f(wj). Reamintim ca determinareavalorii unui polinom ıntr-un punct se poate realiza prin n ınmultiri si n adunari, utilizand schema luiHorner (a se vedea exercitiul 10.2), si aceste valori sunt optime [HS84, Kro79]. De aici, calculul directal celor n componente ale transformatei Fourier necesita timpul O(n2). Utilizand strategia divide-et-impera, vom proiecta un algoritm care necesita O(n log n) timp. Numim calculul dat de acest algoritmtransformata Fourier rapida si-l notam FFT (Fast Fourier Transform). Consideram mai ıntai cazuln = 2r. Utilizam proprietatile de mai sus ale radacinilor unitatii pentru a desparti suma din definitialui f(wj) ın doua subsume: suma coeficientilor pari si suma coeficientilor impari. Avem:

f(wj) =n2 −1∑m=0

x2mw2mj +

n2 −1∑m=0

x2m+1w2m+1j

=n2 −1∑m=0

x2mw2mj + wj

n2 −1∑m=0

x2m+1w2mj

De fapt, expresia de mai sus corespunde scrierii polinomului f(t) sub forma:

f(Y ) = (x0 + x2Y2 + · · ·+ xn−2Y

n−2) + Y (x1 + x3Y2 + · · ·+ xn−1Y n−2) = g(Y ) + Y h(Y )

unde g(Y ) si h(Y ) sunt polinoame de grad n−2, i.e. de grad mai mic cu 1 decat cel al lui f(Y ). Evaluareaacestor polinoame se va face numai ın punctele wm, m = 0, 1, . . . , n

2 −1 = 2r−1−1. Consideram listele denumere x0, x2, x4, . . . , x2r−2, respectiv x1, x3, x5, . . . , x2r−1. Seriile Fourier ale acestor liste constau dinvalorile polinoamelor:

g′(Y ) = x0 + x2Y + x4Y2 + · · ·+ xn−2Y

n2 −1

sih′(Y ) = x1 + x3Y + x5Y

2 + · · ·+ xn−1Yn2 −1

pentru radacinile de ordinul n2 ale unitatii. Notam cu w′

j , j = 0, 1, . . . , n2 − 1 aceste radacini. Se pune

problema daca putem calcula f(wj) utilizand g′(w′j) si h′(w′

j). Pentru j < n2 avem:

w2mj = e

2πij2m2r = e

2πijm2r−1 = w′

jm

iar pentru j ≥ n2 are loc:

w2mj = −w2m

j−n2

= −e2πi(j−n

2 )2m

2r = e2πi(j−n

2 )m

2r−1 = w′mj−n

2

Aceste relatii arata ca valorile f(wj) pot fi calculate daca se cunosc g′(w′j) si h′(w′

j): f(wj) = g′(w′j) +

wjh′(w′

j) daca j < n2 si f(wj) = g′(−w′

j) + wjh′(w′

j−n) daca j ≥ n2 . Deci strategia divide-et-impera

poate fi aplicata cu succes. Algoritmul rezultat este:

procedure FFT(f, n, w)begin

if (n = 1)then f(w0) ← x0

Page 177: algoritmi_tehnici_dorel lucanu - carte

188 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

else n ←[n2

]g′ ← x0 + x2Y + · · ·+ x2n−2Yn−1

h′ ← x1 + x3Y + · · ·+ x2n−1Yn−1

FFT(g’, n, w)FFT(h’, n, w)for j ← 0 to n-1 do

f(wj) ← g′(w′j) + wj ∗ h′(w′

j)for j ← n to 2*n-1 do

f(wj) ← g′(w′j−n) + wj ∗ h′(w′

j−n)end

In algoritmul de mai sus exista dezavantajul ca trebuiesc calculate atat radacinile unitatii de ordinuln cat si cele de ordinul n

2 . Acest dezavantaj poate fi eliminat daca se schimba instanta problemei.Plecand de la observatia ca daca se cunoaste o radacina primitiva de ordinul n a lui 1, sa zicem w =1, atunci celelalte radacini sunt puteri ale lui w. Deci putem lua wj = wj . Instanta problemei semodifica ın felul urmator: ın loc sa consideram dat numai polinomul f , presupunem date polinomul fde grad n − 1 si o radacina primitiva de ordinul n a unitatii. Iesirea consta ın determinarea valorilorf(w0), f(w1), f(w2), . . . , f(wn−1). De asemenea, se tine cont de faptul ca daca w este o radacina primitivade ordinul n a unitatii, atunci w2 este o radacina primitiva de ordinul n

2 a unitatii. Noul algoritm este:

procedure FFT(f, n, w)begin

if (n = 1)then f(w0) ← x0

else n ←[n2

]g′ ← x0 + x2Y + · · ·+ x2n−2Yn−1

h′ ← x1 + x3Y + · · ·+ x2n−1Yn−1

FFT(g’, n, w2)FFT(h’, n, w2)for j ← 0 to n-1 do

f(wj) ← g′(w2j) + w ∗ h′(w2j)for j ← n to 2*n-1 do

f(wj) ← g′(w2j) + w ∗ h′(w2j)end

Teorema 10.4. Daca n este o putere a lui 2, atunci transformata Fourier discreta pentru n masuratoripoate fi calculata ın timpul O(n log n).

Demonstratie. Se aplica teorema 10.1 pentru a = 2 = b si k = 1. sfdem

10.6.2 Implementare

function ad(x,y)begin

z.re ← x.re + y.rez.im ← x.im + y.imreturn z

end

function sc(x,y)begin

z.re ← x.re - y.rez.im ← x.im - y.imreturn z

end

Page 178: algoritmi_tehnici_dorel lucanu - carte

10.7. REFERINTE BIBLIOGRAFICE 189

function inm(x,y)begin

z.re ← x.re*y.re - x.im*y.imz.im ← x.re*y.im + x.im*y.rereturn z

end

Procedura recursiva care implementeaza schema FFT este urmatoarea:

procedure FFT(f, n, w, fw)begin

if (n = 1)then fw[0] ← f[0]else n ← n / 2

for i ← 0 to n-1 dog[i] ← f[2*i]h[i] ← f[2*i+1]

inm(w,w,w1)FFT(g,n,w1,gw)FFT(h,n,w1,hw)w1 ← complex(1)for j ← 0 to n-1 do

w2 ← inm(w1,hw[j])fw[j] ← ad(gw[j],w2)fw[j+n] ← sc(gw[j],w2)w1 ← inm(w1,w)

end

10.7 Referinte bibliografice

Prezentarea de aici se bazeaza pe [HS84, MS91, LG86]. In [Sed88] metoda este prezentata ca o aplicatiea recursiei.

10.8 Exercitii

Exercitiul 10.1. Se stie ca maximul (minimul) dintr-o lista cu n elemente se poate determina facandn−1 comparatii. Astfel, se poate scrie un program care calculeaza simultan si maximul si minimul facand2(n − 1) comparatii. Sa se proiecteze un algoritm divide-et-impera care determina simultan minimul simaximul. Algoritmul va trebui sa execute 3n

2 − 2 comparatii, daca n este o putere a lui 2.

Exercitiul 10.2. (Evaluarea polinoamelor) Sa se scrie un algoritm divide-et-impera care sa calculezevaloarea unui polinom ıntr-un punct. Care este eficienta algoritmului? Sa se compare aceasta cu cea aalgoritmului bazat pe schema lui Horner:

f(x) = a0 + (a1 + · · · (anx + an−1)x + · · · )x

Exercitiul 10.3. [MS91] (Numere Fibonacci) Sa se scrie un program care calculeaza al n-lea numarFibonacci F (n) executand Θ(log n) operatii aritmetice.

Exercitiul 10.4. [MS91] (Inmultire rapida)

1. Aratati ca doua polinoame de gradul 1 pot fi ınmultite executand exact trei ınmultiri.

2. Utilizand 1. sa se scrie un algoritm divide-et-impera care sa ınmulteasca doua polinoame de gradn ın timpul Θ(nlog2 3).

Page 179: algoritmi_tehnici_dorel lucanu - carte

190 CAPITOLUL 10. “DIVIDE-ET-IMPERA”

3. Utilizınd 2. sa se arate ca doi ıntregi reprezentati binar pe n biti pot fi ınmultiti ın timpul Θ(nlog2 3),unde orice operatie binara invoca un numar constant de biti.

Exercitiul 10.5. [MS91] (Dominanta maximala) In spatiul k-dimensional, un punct (x1, . . . , xk) dominaalt punct (y1, . . . , yk) daca xi ≥ yi pentru i = 1, 2, . . . , k, si cel putin o inegalitate fiind stricta. Data omultime finita de puncte S, un punct P ∈ S este maximal daca nu este dominat de un oricare alt punctdin S. Scrieti un algoritm divide-et-impera eficient pentru determinarea punctelor maximale dintr-omultime cu n puncte data. Un algoritm cu complexitatea O(n · (log n)k−2 + n · log n) este posibil.

Exercitiul 10.6. Diametrul unui arbore (graf conex fara cicluri) este lungimea celui mai lung drum ıntredoua varfuri. Sa se gaseasca un algoritm divide-et-impera pentru determinarea diametrului unui arbore.

Exercitiul 10.7. (Algoritmul lui Strassen de ınmultire a matricilor) Inmultirea a doua matrici A si Bse poate realiza cu numai 7 ınmultiri:

• se calculeaza expresiile:q1 = (a11 + a22)(b11 + b22)q2 = (a21 + a22)b11

q3 = a11(b12 − b22)q4 = a22(−b11 + b21)q5 = (a11 + a12)b22

q6 = (−a11 + a21)(b11 + b12)q7 = (a12 +−a22)(b21 + b22)

• apoi se calculeaza elementele matricei C = AB:

c11 = q1 + q4 − q5 + q7

c12 = q3 + q5

c21 = q2 + q4

c22 = q1 + q3 − q2 + q6

Sa se arate ca ınmultirea a doua matrici n×n se poate face cu O(nlog2 7) ınmultiri.

Exercitiul 10.8. Se considera un ecran alb/negru cu rezolutia 1024×1024. Notiunea de fereastra estedefinita recursiv astfel:

• ecranul este o fereastra;• un pixel este o fereastra;• o fereastra de dimensiune n×n defineste 4 ferestre (stanga-sus, dreapta-sus,stanga-jos si dreapta-jos)

de dimensiuni n2×

n2 .

Colorarea ferestrelor se poate realiza cu urmatorul set de instructiuni:

@ - sterge ecranul,a - subfereastra stanga-sus devine fereastra curenta,b - subfereastra dreapta-sus devine fereastra curenta,c - subfereastra dreapta-jos devine fereastra curenta,d - subfereastra stanga-jos devine fereastra curenta,↑ - ultima fereastra vizitata ınaintea celei curente devine fereastra curenta.

Se cere:

1. Sa se arate ca pentru orice dreptunghi de pe ecran, cu laturile paralele cu marginile ecranului, existao secventa de instructiuni care realizeaza colorarea dreptunghiului.

2. Sa se proiecteze un algoritm care, pentru un astfel de dreptunghi dat, determina o secventa deinstructiuni de lungime minima care realizeaza colorarea dreptunghiului.

Page 180: algoritmi_tehnici_dorel lucanu - carte

Capitolul 11

Programare dinamica

11.1 Prezentarea intuitiva a paradigmei

Principalele ingrediente ale paradigmei programare dinamica sunt urmatoarele:

1. Clasa de probleme la care se aplica include probleme de optim.

2. Definirea notiunii de stare, care este de fapt o subproblema, si asocierea functtii obiectiv pentrustare (subproblema).

3. Definirea unei relatii de tranzitie ıntre stari. O relatie s → s′, unde s si s′ sunt stari, va fi numitadecizie. O politica este o secventa de decizii consecutive, adica o secventa de forma s0 → s1 →· · · sn.

4. Aplicarea Principiului de Optim pentru obtine o relatie de recurenta. Principiul de optim (PO)afirma ca o subpolitica a unei politici optimale este la randul ei optimala. Deoarece este posibil caPO sa nu aiba loc, rezulta ca trebuie verificata validitatea relatiei de recurenta.

5. Calculul recurentei rezolvand subproblemele de la mic la mare si memorand valorile obtinuteıntr-un tablou. Nu se recomanda scrierea unui program recursiv care sa calculeze valorile optime.Daca ın procesul de descompunere problema → subproblema, o anumita subproblema apare de maimulte ori, ea va fi calculata de cate ori apare.

6. Extragerea solutiei optime din tablou utilizand proprietatea de substructura optima a solutiei,care afirma ca solutia optima a problemei include solutiile optime ale subproblemelor sale. .

Ca si ın cazul celorlalte paradigme, aplicarea programarii dinamice se poate face ın doua moduri:

• direct: se defineste notiunea de stare (de cele mai multe ori ca fiind o subproblema), se aplicaprincipiul de optim pentru a deduce relatiile de recurenta de tip 11.8 si apoi se stabilesc strategiilede calcul a valorilor si solutiilor optime.

• prin comparare: se observa ca problema este asemanatoare cu una dintre problemele cunoscute sise ıncearca aplicarea strategiei ın aceeasi maniera ca ın cazul problemei corespunzatoare.

11.1.1 Exemplu: drum optim ıntr-o retea triunghiulara de numere

Consideram urmatoarea problema foarte simpla. Fie a = (a0, . . . , an−1) o secventa de numere ıntregiastfel ıncat n + 1 = k(k+1)

2 si R(a) reteaua triunghiulara ce are nodurile etichetate cu numerele ai asacum este sugerat ın fig. 11.1. Se pune problema determinarii unui drum din varful triunghiului la bazatriunghiului pentru care suma numerelor aflate pe drum este maxima. Daca notam cu D multimeadrumurilor de la varf la baza si cu (d) suma numerelor aflate pe drumul d atunci functia obiectiv este

maxd∈D

(d)

191

Page 181: algoritmi_tehnici_dorel lucanu - carte

192 CAPITOLUL 11. PROGRAMARE DINAMICA

Prin stare a problemei vom ıntelege subproblema DMR(i) corespunzatoare subretelei cu varful ın ai.Functia obiectiv a subproblemei DMR(i) este

maxd∈D(i)

(d)

unde D(i) este multimea drumurilor care pleaca din varful ai spre baza triunghiului. Notam cu f(i)valoarea functiei obiectiv pentru DMR(i). Fie st(i) indicele “fiului stanga” al lui ai si dr(i) indicele“fiului dreapta” al lui ai. Exista relatia evidenta dr(i) = st(i) + 1. Drumul optim ce pleaca din ai vatrece prin unul din cei doi fii ai lui ai. Presupunem ca trece prin ast(i). Aplicand principiul de optim,subdrumul ce pleaca din st(i) este la randul sau optim. Se rationeaza asemanator ın cazul cand drumuloptim trece prin adr(i) si rezulta urmatoarea relatie de recurenta:

f(i) = max(f(st(i)), f(dr(i))) + ai (11.1)

a9

a8

a7

a

a a

a

a0

a

a

6

543

21

Figura 11.1: R(a) pentru n = 10

Relatia 11.1 poate fi dovedita utilizand inductia si reducerea la absurd. Daca se rezolva recursivaceasta relatie, atunci f(5) va fi calculata de doua ori, f(8) de trei ori s.a.m.d. De aceea valorile core-spunzatoare drumurilor optime vor fi memorate ıntr-un tablou unidimensional si ordinea de calcul va fide la baza triunghiului spre varf, adica ın ordinea descrescatoare a indicilor.

Drumul optim b1, b2, . . . pentru o retea de numere este determinat, pe baza tabloului cu valori optime,prin urmatorul algoritm:

b[0] ← a[0];for j ← 1 to k do

if (f[i]=f[st(i)]+b[j-1])then b[j] ← st(i)else b[j] ← dr(i)

11.2 Studiu de caz: Alocarea resurselor

11.2.1 Descrierea problemei

Pentru realizarea a p proiecte sunt disponibile r resurse. Alocarea a j resurse la proiectul iproduce un profit c[i, j]. Problema consta ın alocarea celor r resurse astfel ıncat profitul totalsa fie maxim.

Problema poate fi reformulata ca o problema de optim peste digrafuri. Consideram mai ıntai un exemplu.

Exemplu: Presupunem p = 3 si r = 2. Digraful asociat problemei este reprezentat ın fig. 11.2.Exista un varf initial s, care corespunde numarului initial de resurse, si un varf final t, care corespundenumarului de resurse ramase nealocate (care este zero). Un varf intermediar corespunde numarului deresurse ce pot fi alocate ın continuare. Arcele sunt etichetate cu profiturile aduse de resursele ce pot fialocate la un anumit proiect. Nu pot fi alocate mai multe resurse decat sunt disponibile. Solutia optimadescrie un drum de la s la t. sfex

Page 182: algoritmi_tehnici_dorel lucanu - carte

11.2. STUDIU DE CAZ: ALOCAREA RESURSELOR 193

c[1, 0]

c[1, 1]

c[1, 2]

c[2, 0]

c[2, 1]

c[2, 2]

c[2, 0]

c[2, 1]

c[2, 0]

c[3, 2]

c[3, 1]

c[3, 0]

s t

Figura 11.2: Alocarea resurselor: reprezentarea cu digrafuri

11.2.2 Modelul matematic

Constructia digrafului asociat problemei pentru cazul general poate fi data ın modul urmator: Multimeade varfuri ale digrafului este partajata ın p + 1 submultimi disjuncte: V1, . . . , Vp+1. V1 contine un singurvarf s, Vp+1 contine tot un singur varf t si Vi contine r + 1 varfuri, (i, j), 0 ≤ j ≤ r,1 < i ≤ p. Pentruuniformitate, vom presupune s = (1, r), t = (p + 1, 0). Un arc uneste un varf (i, j) ∈ Vi cu un varf(i + 1, k) ∈ Vi+1 numai daca j ≥ k si ın acest caz este etichetat cu c[i, j − k]. Semnificatia unui arc〈(i, j), (i + 1, k)〉 cu eticheta c[i, j − k] este urmatoarea: daca la pasul i sunt disponibile j resurse si laproiectul i se aloca j − k resurse, atunci se obtine un profit c[i, j − k] si raman k resurse disponibile. Unastfel de graf este un caz particular de digraf etajat (multi-stage graph) definit dupa cum urmeaza:

Definitia 11.1. Un digraf etajat este un digraf G = (V, E) ın care V = V1 ∪ · · · ∪ Vp+1 cu proprietatile:

• Vi ∩ Vj = ∅ daca i = j.

• #V1 = #Vp+1 = 1. Presupunem V1 = s, Vp+1 = t.

• Daca un arc are sursa ın Vi atunci are destinatia ın Vi+1.

Problema alocarii resurselor poate fi generalizata acum la o problema de optim peste digrafuri etajate.

Fie date un digraf etajat G = (V, E) si o functie de profit (cost) c : E →R. Profitul (costul)unui drum este suma profiturilor (costurilor) arcelor care descriu drumul. Problema constaın determinarea unui drum de la s la t cu profit maxim (cost minim).

Presupunem V = 0, 1, . . . , n − 1, s = 0, t = n − 1 si ca varfurile de pe acelasi etaj sunt numereconsecutive.

Vom ıncerca sa explicam parcurgerea fiecarei etape a programarii dinamice. Definim drept stareproblema determinarii drumurilor optime de la orice varf j ∈ X ⊆ V la t. Notam aceasta problema prinDODE(X) (Drumurile Optime ın Digrafuri Etajate). Pentru i (1 ≤ i ≤ p + 1) si j ∈ Vi notam cu D[i, j]drumul optim de la varful j la t si cu ValOpt[i, j] profitul (costul) acestui drum. ValOpt[i, j] reprezintavaloarea asociata starii DODE(j). Valoarea asociata starii DODE(X) va fi multimea ValOpt[i, j] |j ∈ X.

Ne punem problema gasirii relatiei analitice pentru valoarea optima ValOpt[i, j]. Daca i = p + 1atunci singura valoare posibila pentru j este n si avem ValOpt[p + 1, n] = 0. Consideram i < p.Orice drum de la j la n ıncepe cu un arc cu destinatia ın Vi+1. Notam cu k destinatia primului arcde pe drumul optim D[i, j]. Selectarea acestui arc poate fi gandita ca fiind decizia prin care stareaDODE(j) este transformata ın starea DODE(k). Aplicand principiul de optim, politica optima apli-cata starii DODE(k) este o subpolitica a politicii optime corespunzatoare starii DODE(j). RezultaValOpt[i, j] = c[j, k] + ValOpt[i + 1, k]. De aici rezulta urmatoarea ecuatie pentru ValOpt:

ValOpt[p + 1, n] = 0ValOpt[i, j] = optimc[j, k] + ValOpt[i + 1, k] | k ∈ Vi+1, 〈j, k〉 ∈ E (11.2)

unde optim = max daca c[j, k] reprezinta profitul si optim = min daca c[j, k] reprezinta costul arcului〈j, k〉.

Page 183: algoritmi_tehnici_dorel lucanu - carte

194 CAPITOLUL 11. PROGRAMARE DINAMICA

Pe baza relatiilor 11.2, calculul valorilor ValOpt[i, j] rezulta din rezolvarea urmatoarelor subprobleme:DODE(Vp+1), DODE(Vp ∪ Vp+1), . . . , DODE(V1 ∪ · · · ∪ Vp+1) = DODE(V ). Deoarece varfurile aflate peun acelasi etaj sunt numere consecutive iar etajele sunt considerate de la stanga la dreapta (de la s spre t),rezulta ca drumurile optime se vor determina ın ordinea descrescatoare a varfurilor. Asa cum vom vedeala implementare, valorile ValOpt[i, j] pot fi memorate ıntr-un tablou unidimensional prin renuntarea laınregistrarea etajului la care apartine un varf.

Utilizand 11.2, proprietatea de substructura optima se caracterizeaza astfel: un drum optim carepleaca din varful j contine drumurile optime care pleaca din orice varf intermediar al sau. Astfel, daca secunosc drumurile optime din DODE(X) atunci se pot determina drumurile optime din DODE(X ∪ j).De aici, determinarea unui drum optim de la s la t, dupa ce se cunosc valorile optime ValOpt[i, j], serealizeaza prin determinarea tuturor drumurilor optime D[i, j]:

D[p + 1, t] = () (drumul vid)D[i, j] = (〈j, k〉, D[i + 1, k]) daca ValOpt[i, j] = c[j, k] + ValOpt[i + 1, k]

unde un drum este reprezentat printr-o lista de arce. Notam ca drumurile pot fi determinate simultancu valorile optime.

Aplicarea programarii dinamice pentru determinarea drumurilor optime ıntr-un digraf etajat esteprezentata schematic de urmatorul algoritm:

procedure alocRes(V, E, c, ValOpt, D)begin

ValOpt[p+1,n]← 0D[p+1,n]← listaVida()for i ← p downto 1 do

for orice j ∈ Vi dodetermina k0 a.ı.

c[j, k0] + ValOpt[i + 1, k0] = optimc[j, k] + ValOpt[i + 1, k] | 〈j, k〉 ∈ EValOpt[i,j]← c[j,k0]+ValOpt[i+1,k0]insereaza(D[i,j], 1, 〈j, k〉)

end

Exercitiul 11.2.1. Sa se descrie un algoritm pentru determinarea drumului optim ıntr-un digraf etajat,bazat pe paradigma programarii dinamice, considerand ca stare DODE′(X) = problema determinariidrumurilor optime de la s la orice j ∈ X .

11.2.3 Implementare

Pentru implementare, consideram digraful G reprezentat prin listele de adiacenta spre interior. Pentrureprezentarea functiei ValOpt este suficient sa utilizam un tablou unidimensional prin renuntarea laınregistrarea etajului la care apartine varful j, i.e. ValOpt[j] = ValOpt[i, j]. Datorita proprietatii desubstructura optima, nu este eficient sa ınregistram tot drumul optim care pleaca din varful j. Daca stimprimul arc 〈j, k〉 de pe drumul optim, atunci parcurgem acest arc si apoi continuam (recursiv) pe drumuloptim care pleaca din k. In acest mod se parcurge tot drumul optim care pleaca din j. Vom utiliza untablou S[j] care va ınregistra numai primul varf (Secundul) de pe drumul optim care pleaca din j, iarıntregul drum va fi (j, S[j], S[S[j]], . . . , n) (reprezentat ca lista de varfuri). Determinarea functiei ValOptpresupune parcurgerea digrafului pe etaje, ıncepand cu ultimul etaj Vp+1 = n. Consideram numai cazuloptim = max. Pentru o descriere uniforma a algoritmului, se presupune ca initial are loc:

ValOpt[j] = −∞ , j = 0, . . . , n− 2

unde −∞ va fi reprezentat de o constanta MinusInf, mai mica decat orice c[i, j]. Plecand de la ipotezaca pentru varful k de pe nivelul i valoarea optima ValOpt[k] a fost determinata, se actualizeaza ValOpt[j]pentru toate varfurile j de pe nivelul i − 1 cu proprietatea ca exista arcul 〈j, k〉. Actualizarea constaın verificarea conditiei ValOpt[j] < c[j, k] + ValOpt[k] si ın cazul cand este adevarata, noua valoare alui ValOpt[j] va fi c[j, k] + ValOpt[k] iar valoarea variabilei D[j] este k. Valoarea c[j, k] este memoratade variabila q->c, unde q->varf = j iar q este o variabila referinta (pointer) cu care se parcurge listavarfurilor incidente spre interior ın k. Dupa completarea tablourilor ValOpt si S, se determina drumuloptim. Valoarea drumului optim este ValOpt[0].

Page 184: algoritmi_tehnici_dorel lucanu - carte

11.3. DRUMURILE CELE MAI SCURTE INTRE DOUA VARFURI 195

function alocRes(G, ValOpt, D)begin

for j ← 0 to G.n-2 doValOpt[j]← −∞

ValOpt[G.n-1]← 0for k ← G.n-1 downto 1 do

q ← G.a[k]while (q = NULL) do

j ← q->varfif (ValOpt[j] < ValOpt[k] + q->c)then ValOpt[j]← ValOpt[k] + q->c

S[j] ← kq ← q->succ

D[0] ← 0D[p] ← n-1for i ← 1 to p-1 do

D[i] ← S[D[i-1]]return ValOpt[0]

end

Evaluarea algoritmului Fiecare arc este cercetat o singura data, astfel ca determinarea celor douatablouri ValOpt si S necesita O(m) timp, unde m este numarul de arce. Deoarece determinarea drumuluise face ın timpul Θ(p), rezulta ca algoritmul alocRes necesita O(m) timp.

11.3 Studiu de caz: Drumurile cele mai scurte ıntre oricare douavarfuri ale unui digraf

11.3.1 Descrierea problemei

Aceasta problema este o generalizare a problemei determinarii drumului optim ıntr-un digraf etajat:

Se considera G = (V, E) un digraf cu V = 0, . . . , n − 1 si o functie : E → R o functiede etichetare a arcelor. Perechea 〈G, 〉 se mai numeste digraf ponderat. Notam ij ın loc de(〈i, j〉) si numim ij lungimea (= costul) arcului 〈i, j〉. Lungimea (= costul) unui drum estesuma lungimilor arcelor ce compun drumul. Problema consta ın a determina, pentru oricedoua varfuri i, j, un drum de lungime minima de la varful i la varful j (cand exista).

11.3.2 Modelul matematic

Pentru o prezentare uniforma a metodei, extindem functia la : V × V → R punand ij = ∞ pentruacele perechi de varfuri distincte cu 〈i, j〉 ∈ E si ii = 0 pentru orice i = 0, . . . , n− 1.

Drept stare definim DM2VD(X) (Drum Minim ıntre oricare 2 Varfuri ale unui Digraf) ca fiindsubproblema corespunzatoare determinarii drumurilor de lungime minima cu varfuri intermediare dinmultimea X ⊆ V . Evident, DM2VD(V ) este chiar problema initiala. Notam cu X

ij lungimea drumuluiminim de la i la j construit cu varfuri intermediare din X . Daca X = ∅ atunci ∅ij = ij . Consideramdecizia optima care transforma starea DM2VD(X ∪ k) ın DM2VD(X). Presupunem ca 〈G, 〉 este undigraf ponderat fara circuite negative. Fie ρ un drum optim de la i la j ce contine varfuri inter-mediare din multimea X ∪ k. Avem lung(ρ) =

X∪kij , unde lung(ρ) este lungimea drumului ρ. Daca

varful k nu apartine lui ρ atunci politica obtinerii lui ρ corespunde de asemenea si starii DM2VD(X) si,aplicand principiul de optim, obtinem:

Xij = lung(ρ) =

X∪kij

In cazul ın care k apartine drumului ρ, notam cu ρ1 subdrumul lui ρ de la i la k si cu ρ2 subdrumul dela k la j. Aceste doua subdrumuri au varfuri intermediare numai din X . Conform principiului de optim,

Page 185: algoritmi_tehnici_dorel lucanu - carte

196 CAPITOLUL 11. PROGRAMARE DINAMICA

politica optima corespunzatoare starii DM2VD(X) este subpolitica a politicii optime corespunzatoarestarii DM2VD(X ∪ k). Rezulta ca ρ1 si ρ2 sunt optime ın DM2VD(X). De aici rezulta:

X∪kij = lung(ρ) = lung(ρ1) + lung(ρ2) = X

ik + Xkj

Acum, ecuatia functionala analitica pentru valorile optime Xij are urmatoarea forma:

X∪kij = minX

ij , Xik + X

kj (11.3)

Corolar 11.1. Daca 〈G, 〉 nu are circuite de lungime negativa, atunci au loc urmatoarele relatii:

• X∪kkk = 0

• X∪kik = X

ik

• X∪kkj = X

kj

pentru orice i, j, k ∈ V .

Calculul valorilor optime rezulta din rezolvarea subproblemelor

DM2VD(∅), DM2VD(0), DM2VD(0, 1), . . . , DM2VD(0, 1, . . . , n− 1) = DM2VD(V )

Convenim sa notam kij ın loc de

0,...,k−1ij . Pe baza corolarului 11.1 rezulta ca valorile optime pot fi

memorate ıntr-un acelasi tablou. Maniera de determinare a acestora este asemanatoare cu cea utilizatala determinarea matricei existentei drumurilor de catre algoritmul lui Warshall.

Pe baza ecuatiilor 11.3, proprietatea de substructura optima se caracterizeaza prin: un drum optimde la i la j include drumurile optime de la i la k si de la k la j, pentru orice varf intermediar k al sau.Astfel ca drumurile optime din DM2VD(X ∪ k) pot fi determinate utilizand drumurile minime dinDM2VD(X). In continuare consideram numai cazurile X = 0, 1, . . . , k − 1. Ca si ın cazul digrafuriloretajate, determinarea drumurilor optime poate fi facuta cu ajutorul unor tablouri P k = (P k

ij), dar carede aceasta data au o semnificatie diferita: P k

ij este varful P enultimului varf de pe drumul optim de la i

la j. Pentru k = 0 avem P 0ij = i daca 〈i, j〉 ∈ E si P 0

ij = 0, ın celelalte cazuri. Decizia k determina P k

odata cu determinarea matricei k = (kij). Daca k−1

ik + k−1kj < k−1

ij atunci drumul optim de la i la jeste format din concatenarea drumului optim de la i la k cu drumul optim de la k la j si deci penultimulvarf de pe drumul de la i la j coincide cu penultimul varf de pe drumul de la k la j: P k

ij = P k−1kj . In caz

contrar, avem P kij = P k−1

ij . Cu ajutorul matricei Pnij pot fi determinate drumurile optime: ultimul varf

pe drumul de la i la j este jt = j, penultimul varf este jt−1 = Pnij , antipenultimul este jt−2 = Pn

ijt−1s. a.

m. d.. In acest mod, toate drumurile pot fi memorate utilizand numai O(n2) spatiu.Aplicarea programarii dinamice pentru problema determinarii drumurilor minime este descrisa de

schema procedurala drmin:

procedure drmin(G, , P)begin

for i ← 0 to n-1 dofor j ← 0 to n-1 do

0ij =

0 , i = j

ij , 〈i, j〉 ∈ E

∞ , altfel

P0ij =

i , i = j, 〈i, j〉 ∈ E

0 , altfelfor k ← 0 to n-1 do

for i ← 0 to n-1 dofor j ← 0 to n-1 do

kij = mink−1ij , k−1

ik + k−1kj

Pkij =

P k−1

ij , kij = k−1

ij

P k−1kj , k

ij = k−1ik + k−1

kj

end

Page 186: algoritmi_tehnici_dorel lucanu - carte

11.4. STUDIU DE CAZ: PROBLEMA RUCSACULUI II (VARIANTA DISCRETA) 197

11.3.3 Implementare

Presupunem ca graful G = 〈V, E〉 este reprezentat prim matricea de adicaenta. pe care o convenim sa onotam aici cu G.L (este usor de vazut ca matricea ponderilor include si reprezentarea lui E). Datoritacorolarului 11.1, matricele k si k−1 pot fi memorate de acelasi tablou bidimensional G.L. Este usorde vazut ca matricea G.L include si reprezentarea lui E. Simbolul ∞ este reprezentat de o constantaplusInf cu valoare foarte mare. Daca digraful are circuite negative, atunci acest lucru poate fi depistat:daca la un moment dat se obtine G.L[i, i] < 0, pentru un i oarecare, atunci exista un circuit de lungimenegativa care trece prin i. Functia drmin ıntoarce valoarea true daca digraful ponderat reprezentat dematricea G.L nu are circuite negative si ın acest caz G.L va contine la iesire lungimile drumurilor minimeıntre oricare doua varfuri iar G.P reprezentarea acestor drumuri.

procedure drmin(G, P)begin

for i ← 0 to n-1 dofor j ← 0 to n-1 do

if ((i = j) and (L[i,j] = plusInf))then P[i,j] ← ielse P[i,j] ← 0

for k ← 0 to n-1 dofor i ← 0 to n-1 do

for j ← 1 to n doif ((L[i,k] = PlusInf) or (L[k,j] = PlusInf))then temp ← plusInfelse temp ← L[i,k]+L[k,j]if (temp < L[i,j])then L[i,j] ← temp

P[i,j] ← P[k,j]if ((i = j) and (L[i,j] < 0))then throw ’(di)graful are circuite negative’

end

Evaluare Se verifica usor ca executia algoritmului drmin necesita O(n3) timp si utilizeaza O(n2) spatiu.

Observatie: Algoritmul descris de drmin este cunoscut ın literatura sub numele de algoritmul Floyd-Warshall. O forma restrictiva a problemei drumurilor minime se obtine prin precizarea varfului destart. Algoritmii cei mai cunoscuti care rezolva aceasta forma restrictiva sunt Dijkstra (exercitiul 9.7) siBellman-Ford (exercitiul 11.2). sfobs

11.4 Studiu de caz: Problema rucsacului II (varianta discreta)

11.4.1 Descrierea problemei

Consideram urmatoarea versiune modificata a problemei rucsacului:

Se considera n obiecte 1, . . . , n de dimensiuni (greutati) w1, . . . , wn ∈ Z+, respectiv, si unrucsac de capacitate M ∈ Z+. Un obiect i sau este introdus ın totalitate ın rucsac, xi = 1,sau nu este introdus de loc, xi = 0, astfel ca o umplere a rucsacului consta dintr-o secventax1, . . . , xn cu xi ∈ 0, 1 si

∑i xi · wi ≤ M . Ca si ın cazul continuu, introducerea obiectului

i ın rucsac aduce profitul pi ∈ Z iar profitul total este∑n

i=1 xipi. Problema consta ın adetermina o alegere (x1, . . . , xn) care sa aduca un profit maxim.

Deci, singura deosebire fata de varianta continua studiata la metoda greedy consta ın conditia xi ∈ 0, 1ın loc de xi ∈ [0, 1]. Formulata ca problema de optim, problema rucsacului, varianta discreta, este:

– functia obiectiv:

maxn∑

i=1

xi · pi

Page 187: algoritmi_tehnici_dorel lucanu - carte

198 CAPITOLUL 11. PROGRAMARE DINAMICA

– restrictii:n∑

i=1

xi · wi ≤M

xi ∈ 0, 1, i = 1, . . . , nwi ∈ Z+, pi ∈ Z, i = 1, . . . , nM ∈ Z

Exercitiul 11.4.1. Consideram o varianta mai “vesela” a problemei: un hot intra ıntr-un magazin undesunt n obiecte de dimensiuni si valori diferite. In sacul hotului ıncap numai o parte dintre aceste obiecte.Hotul trebuie sa decida ıntr-un timp foarte scurt ce obiecte pune ın sac astfel ca sa aiba un “profit” catmai mare. Fiind un bun algoritmist, acesta aplica un algoritm greedy.

1. Aratati ca indiferent de criteriul de alegere locala, nu totdeauna solutia aleasa este si cea optima.

2. Am spus ca hotul era un bun algoritmist. De ce a ales el strategia greedy si nu oricare alta metodacare da solutia optima? (Desi un raspuns riguros argumentat poate fi dat dupa citirea acesteisectiuni, ıncercati sa-l anticipati.)

11.4.2 Modelul matematic

O stare este notata cu RUCSAC(j, X) si reprezinta urmatoarea problema, care este o generalizare a celeiinitiale:

– functia obiectiv:

maxj∑

i=1

xi · pi

– restrictii:j∑

i=1

xi · wi ≤ X

xi ∈ 0, 1, i = 1, . . . , jwi ∈ Z+, pi ∈ Z, i = 1, . . . , jX ∈ Z

Cu fj(X) notam valoarea optima pentru instanta RUCSAC(j, X). Daca j = 0 si X ≥ 0 atunci,evident fj(X) = 0. Presupunem j > 0. Consideram decizia optima prin care starea RUCSAC(j, X)este transformata ın RUCSAC(j − 1, ?). Notam cu (x1, . . . , xj) alegerea care da valoarea optima fj(X).Daca xj = 0 (obiectul j nu este pus ın rucsac) atunci, conform principiului de optim, fj(X) este valoareaoptima pentru starea RUCSAC(X, j − 1) si de aici fj(X) = fj−1(X). Daca xj = 1 (obiectul j estepus ın rucsac) atunci, din nou conform principiului de optim, fj(X) este valoarea optima pentru stareaRUCSAC(j − 1, X −wj) si de aici fj(X) = fj−1(X −wj) + pj . Combinand relatiile de mai sus obtinem:

fj(X) =

−∞ , daca X < 00 , daca j = 0 si X ≥ 0maxfj−1(X), fj−1(X − wj) + pj , daca j > 0 si X ≥ 0

(11.4)

Am considerat fj(X) = −∞ daca X < 0 pentru a include si cazurile cand obiectul j nu ıncape ıntotalitate ın rucsac.

Utilizand 11.4, proprietatea de substructura optima se caracterizeaza astfel: solutia optima (x1, . . . , xj)a problemei RUCSAC(j, X) include solutia optima (x1, . . . , xj−1) a subproblemei RUCSAC(j − 1, X −xjwj . Astfel, solutia optima pentru RUCSAC(j, X) se poate obtine utilizand solutiile optime pentrusubproblemele RUCSAC(i, Y ) cu 1 ≤ i < j, 0 ≤ Y ≤ X . Notam ca 11.4 implica o recursie ın cascada sideci numarul de subprobleme de rezolvat este O(2n). De aceea, ın continuare ne ocupam de calculul simemorarea eficienta a valorilor optime pentru subprobleme. Mai ıntai consideram urmatorul

Exemplu: Fie M = 10, n = 3 si greutatile si profiturile date de urmatorul tabel:

Page 188: algoritmi_tehnici_dorel lucanu - carte

11.4. STUDIU DE CAZ: PROBLEMA RUCSACULUI II (VARIANTA DISCRETA) 199

i 1 2 3wi 3 5 6pi 10 30 20

Valorile optime pentru subprobleme sunt calculate cu ajutorul relatiilor 11.4 si pot fi memorate ıntr-untablou bidimensional astfel:

X 0 1 2 3 4 5 6 7 8 9 10f0 0 0 0 0 0 0 0 0 0 0 0f1 0 0 0 10 10 10 10 10 10 10 10f2 0 0 0 10 10 30 30 30 40 40 40f3 0 0 0 10 10 30 30 30 40 40 40

Tabloul de mai sus este calculat linie cu linie: pentru a calcula valorile de pe o linie sunt consultatenumai valorile de pe linia precedenta. Algoritmul de calcul este foarte simplu. De exemplu, f2(8) =maxf1(8), f1(8 − 5) + 30 = max10, 40 = 40. Valoarea optima a functiei obiectiv este f3(10) = 40.Solutia care da aceasta valoare se determina ın modul urmator: Se testeaza daca f2(10) = f3(10)?.Raspunsul este afirmativ si de aici rezulta x3 = 0, i.e. obiectul 3 nu este pus ın rucsac. In continuare setesteaza daca f1(10) = f2(10)?. De data aceasta raspunsul este negativ. Rezulta ca f2(10) = f1(10 −5) + 30 = f1(5) + 30 si de aici x2 = 1, i.e. obiectul 2 este pus ın rucsac. In continuare se testeaza dacaf0(5) = f1(5)?. Si de data aceasta raspunsul este negativ si deci x1 = 1. Dinamica valorilor comparateeste sugerata ın tablou prin scrierea acestora ın dreptunghiuri.

Tabloul de mai sus are dimensiunea n · m (au fost ignorate prima linie si prima coloana). Dacam = O(2n) rezulta ca atat complexitatea spatiu cat si cea timp sunt exponentiale. Privind tabloul demai sus observam ca exista multe valori care se repeta. In continuare ne punem problema memorariimai compacte a acestui tablou. Construim graficele functiilor f0, f1, f2 si f3 pentru exemplul de mai sus.Avem:

f0(X) =

−∞ , X < 00 , X ≥ 0

Notam cu g0 functia data de:

g0(X) = f0(X − w1) + p1 =

−∞ , X < 310 , 3 ≤ X

Graficele functiilor f0 si g0 sunt reprezentate ın fig. 11.3. Functia f1 se calculeaza prin:

3

10

Figura 11.3: Functiile f0 si g0

f1(X) = maxf0(X), g0(X) =

−∞ , X < 00 , 0 ≤ X < 310 , 3 ≤ X

Page 189: algoritmi_tehnici_dorel lucanu - carte

200 CAPITOLUL 11. PROGRAMARE DINAMICA

Notam cu g1 functia data prin:

g1(X) = f1(X − w2) + p2 =

−∞ , X < 530 , 5 ≤ X < 840 , 8 ≤ X

Graficele functiilor f1 si g1 sunt reprezentate ın fig. 11.4. Functia f2 se calculeaza prin:

3

10

3

10

5

3040

8

Figura 11.4: Functiile f1 si g1

f2(X) = maxf1(X), g1(X) =

−∞ , X < 00 , 0 ≤ X < 310 , 3 ≤ X < 530 , 5 ≤ X < 840 , 8 ≤ X

In continuare, notam cu g2 functia data prin:

g2(X) = f2(X − w3) + p3 =

−∞ , X < 620 , 6 ≤ X < 930 , 9 ≤ X < 1150 , 11 ≤ X < 1460 , 14 ≤ X

Graficele functiilor f2 si g2 sunt reprezentate ın fig. 11.5. Functia f3 se calculeaza prin:

3

10

3

10

5

30405060

85

3040

8 6 9 11 14

20

Figura 11.5: Functiile f2 si g2

Page 190: algoritmi_tehnici_dorel lucanu - carte

11.4. STUDIU DE CAZ: PROBLEMA RUCSACULUI II (VARIANTA DISCRETA) 201

f3(X) = maxf2(X), g2(X) =

−∞ , X < 00 , 0 ≤ X < 310 , 3 ≤ X < 530 , 5 ≤ X < 840 , 8 < X ≤ 1150 , 11 ≤ X < 1460 , 14 ≤ X

Graficul functiei f3 este reprezentat ın fig. 11.6. Se remarca faptul ca functiile fi si gi sunt functii ın scara.

3

10

5

30

40

8

50

60

11 14

Figura 11.6: Functia f3

Graficele acestor functii pot fi reprezentate prin multimi finite din puncte din plan. De exemplu, graficulfunctiei f2 este reprezentat prin multimea (0, 0), (3, 10), (5, 30), (8, 40). O multime care reprezinta ofunctie ın scara contine acele puncte ın care functia face salturi. Graficul functiei gi se obtine din graficulfunctiei fi printr-o translatie iar graficul functiei fi+1 se obtine prin interclasarea graficelor functiilor fi

si gi. sfex

In general, fiecare fi este complet specificat de o multime Si = (Xj , Yj) | j = 0, . . . , r undeYj = fi(Xj). Presupunem X1 < · · · < Xr. Analog, functiile gi sunt reprezentate prin multimile Ti =(X + wi, Y + pi) | (X, Y ) ∈ Si. Notam Ti = τ(Si) si Si+1 = µ(Si, Ti). Multimea Si+1 se obtinedin Si si Ti prin interclasare. Operatia de interclasare se realizeaza ıntr-un mod semanator cu cel de lainterclasarea a doua linii ale orizontului. Se considera o variabila L care ia valoarea 1 daca graficul lui fi+1

coincide cu cel al lui fi si cu 2 daca el coincide cu cel al lui gi. Deoarece (0, 0) apartine graficului rezultat,consideram L = 1, j = 1 si k = 1. Presupunand ca la un pas al interclasarii se compara (Xj , Yj) ∈ Si cu(Xk, Yk) ∈ Ti atunci:

• daca L = 1:

– daca Xj < Xk atunci adauga (Xj , Yj) ın Si+1 si se incrementeaza j;

– daca Xj = Xk:

∗ daca Yj > Yk atunci adauga (Xj , Yj) ın Si+1 si se incrementeaza j si k;∗ daca Yj < Yk atunci adauga (Xk, Yk) ın Si+1, L = 2 si se incrementeaza j si k;

– daca Xj > Xk atunci, daca Yk > Yj adauga (Xk, Yk) ın Si+1, L = 2 si se incrementeaza k;

• daca L = 2:

– daca Xj < Xk atunci, daca Yj > Yk adauga (Xj , Yj) ın Si+1, L = 1 si se incrementeaza j;

– daca Xj = Xk:

∗ daca Yj < Yk atunci adauga (Xk, Yk) ın Si+1 si se incrementeaza j si k;

Page 191: algoritmi_tehnici_dorel lucanu - carte

202 CAPITOLUL 11. PROGRAMARE DINAMICA

∗ daca Yj > Yk atunci adauga (Xj , Yj) ın Si+1, L = 1 si se incrementeaza j si k;

– daca Xj > Xk atunci adauga (Xk, Yk) ın Si+1 si se incrementeaza k;

Notam cu interclGrafice(Si, Ti) procedurafunctia care determina Si+1 conform algoritmului de maisus. Ramane de extras solutia optima din Sn. Consideram mai ıntai cazul din exemplul de mai sus.

Exemplu: (continuare)

• Se cauta ın Sn = S3 perechea (Xj , Yj) cu cel mai mare Xj pentru care Xj ≤M . Obtinem (Xj , Yj) =(8, 40). Deoarece (8, 40) ∈ S3 si (8, 40) ∈ S2 rezulta foptim(M) = foptim(8) = f3(8) = f2(8) si decix3 = 0. Perechea (Xj , Yj) ramane neschimbata.

• Pentru ca (Xj , Yj) = (8, 40) este ın S2 si nu este ın S1, rezulta ca foptim(8) = f1(8 − w2) + p2 sideci x2 = 1. In continuare se ia (Xj , Yj) = (Xj − w2, Yj − p2) = (8− 5, 40− 30) = (3, 10).

• Pentru ca (Xj , Yj) = (3, 10) este ın S1 si nu este ın S0, rezulta ca foptim(3) = f1(3 − w1) + p1 sideci x1 = 1.

sfex

Metoda poate fi descrisa pentru cazul general:

• Initial se determina perechea (Xj , Yj) ∈ Sn cu cel mai mare Xj pentru care Xj ≤M . Valoarea Yj

constituie ıncarcarea optima a rucsacului, i.e. valoarea functiei obiectiv din problema initiala.

• Pentru i = n− 1, . . . , 0:

– daca (Xj , Yj) este ın Si, atunci fi+1(Xj) = fi(Xj) = Yj si se face xi+1 = 0 (obiectul i + 1 nueste ales);

– daca (Xj , Yj) nu este ın Si, atunci fi+1(Xj) = fi(Xj − wi+1) + pi+1 = Yj si se face xi+1 = 1(obiectul i + 1 este ales), Xj = Xj − wi+1 si Yj = Yj − pi+1.

Descrierea algoritmica completa a metodei este:

procedure rucsac II(n, w, p, valOpt, x)begin

S0 ← (0, 0)T0 ← (w1, p1)for i ← 1 to n

Si(X) ← interclGrafice(Si−1, Ti−1)Ti ← (X + wi, Y+ pi) | (X, Y) ∈ Si

determina (Xj, Yj) cu Xj = maxXi | (Xi, Yi) ∈ Sn, Xi ≤ Mfor i ← n-1 downto 1 do

if (Xj, Yj) ∈ Sithen xi+1 ← 0else xi+1 ← 1

Xj ← Xj − wi+1

Yj ← Yj − pi+1

end

Evaluare Ne propunem sa determinam complexitatile timp si spatiu ale algoritmului descris de schema??. Notam m =

∑ni=0 #Si. Deoarece #Ti = #Si rezulta ca #Si+1 ≤ 2 ·#Si si de aici

∑i #Si ≤

∑i 2i =

2n − 1. Calculul lui Si din Si−1 necesita timpul Θ(#Si−1) si de aici calculul lui Sn necesita timpul∑i Θ(#Si) = O(2n). Deoarece profiturile pi sunt numere ıntregi, pentru orice (X, Y ) ∈ Si , Y este ıntreg

si Y ≤∑

j≤i pj . Analog, pentru ca dimensiunile wi sunt numere ıntregi, pentru (X, Y ) ∈ Si, X esteıntreg si X ≤

∑j≤i wj . Deoarece perechile (X, Y ) cu X > M nu intereseaza, ele pot sa nu fie incluse ın

multimile Si. De aici rezulta ca numarul maxim de perechi (X, Y ) distincte din Si satisface relatiile:

#Si ≤ 1 +∑i

j=1 wj

#Si ≤M

Page 192: algoritmi_tehnici_dorel lucanu - carte

11.5. STUDIU DE CAZ: SUBSECVENTA CRESCATOARE MAXIMALA 203

care implica

#Si ≤ 1 + mini∑

j=1

wj , M

Relatia de mai sus permite o estimare mai precisa a spatiului necesar pentru memorarea multimilor Si

ın cazul unor probleme concrete. In ceea ce priveste timpul, facand calculele rezulta ca algoritmul arecomplexitatea timp O(min(2n, n

∑ni=1 pi, nM)).

11.5 Studiu de caz: Subsecventa crescatoare maximala

11.5.1 Descrierea problemei

Fie a = (a1, . . . , an) o secventa de numere ıntregi. Stergand cateva elemente din a se obtine o nouasecventa, pe care o numim subsecventa. O subsecventa se numeste crescatoare daca elementele sale suntın ordine crescatoare. De exemplu, daca a = (7, 3, 8, 5, 13) atunci subsecventa (7, 3, 5) nu este crescatoareiar subsecventa (7, 8, 13) este crescatoare. Problema consta ın determinarea unei subsecvente crescatoarede lungime maxima. Daca exista mai multe, atunci se determina una arbitrara dintre ele.

11.5.2 Modelul matematic

Se ataseaza problemei un digraf G = (V, E) unde

V = 0, 1, . . . , nE = 〈i, j〉 | a[i] ≤ a[j], 1 ≤ i < j ≤ n ∪ 〈0, i〉 | i = 1, . . . , n

Determinarea unei subsecvente crescatoare maximale este echivalenta cu determinarea unui drum delungime maxima ın G.

Exemplu: Digraful asociat secventei a = (3, 1, 4, 6, 3) este cel reprezentat ın fig. 11.7.

0

1 2 3 4 5

Figura 11.7: Digraful asociat secventei a = (3, 1, 4, 6, 3)

sfex

Se considera urmatoarea matrice de costuri pe arce (ponderi):

c[i, j] =

1 , (i < j si ai ≤ aj) sau (i = 0)−∞ , altfel

Notam cu SCM′(i) subproblema determinarii lungimii celui mai lung drum care se termina ın varful i,echivalent, subproblema determinarii subsecventei crescatoare maximale ce are pe ultimul loc pe a[i].Fie L[i] valoarea optima pentru SCM′(i). Daca i = 0 atunci L[0] = 0. Presupunem i > 0. Fie j sursaultimului arc de pe drumul care da valoarea optima L[i]. Evident, j < i. Aplicand principiul de optim,

Page 193: algoritmi_tehnici_dorel lucanu - carte

204 CAPITOLUL 11. PROGRAMARE DINAMICA

politica optima corespunzatoare starii SCM′(j) este subpolitica a politicii optime corespunzatoare stariiSCM′(i). Rezulta L[i] = L[j] + c[j, i]. Deci L[i] satisface urmatoarea ecuatie functionala:

L[i] =

0 , i = 0maxj<i L[j] + c[j, i] , i > 0

(11.5)

Pentru a determina o secventa maximala din tabelul valorilor optime, se procedeaza ıntr-un modasemanator cu determinarea drumului optim din matricea ce memoreaza penultimul varf de pe fiecaredrum optim. Aici nu este nevoie de memorarea penultimului varf, pentru ca el poate fi determinat dintabelul valorilor optime. Se procedeaza ın modul urmator:

• se determina j cu L[j] = maxi L[i];

• k := L[j]; s[k] := a[j];

• urmatorul proces se repeta pana cand k devine 1:

– se determina j1 cu j1 < j, a[j1] ≤ a[j] si L[j1] = L[j]− 1;– k := k − 1; j := j1; s[k] := a[j].

11.5.3 Implementare

Pentru implementare nu este necesara construirea efectiva a digrafului. Acesta a fost utilizat numaipentru gasirea si verificarea corectitudinii algoritmului.

procedure scm(a, n, sm, lg)begin

L[1] ← 1for i ← 2 to n do

k ← 0for j ← 1 to i-1 do

if ((a[j] ≤ a[i]) and (L[j] > k))then k ← L[j]

L[i] ← k+1lg ← L[1]j ← 1for i ← 2 to n do

if (L[i] > lg)then lg ← L[i]

j ← ism[lg] ← a[j]for i ← lg-1 downto 1 do

k ← j-1while ((L[k]+1 = L[j]) or (a[k] > a[j])) do

k ← k-1sm[i] ← a[k]j ← k

end

Evaluare Prima parte, care determina lungimile subsecventelor crescatoare maximale care se terminaın i, pentru i = 1, . . . , n, se realizeaza ın timpul O(n2). A doua etapa, care determina secventa optimautilizand tabelul lungimilor optime, necesita timpul O(n). Rezulta ca ıntreg algoritmul are complexitateatimp O(n2). Memorarea secventei initiale, subsecventei crescatoare maximale si a lungimilor utilizeazaO(n) spatiu.

Observatie: Performanta timp al programului DetSCM2 poate fi ımbunatatita prin utlizarea suplimen-tara a unui tablou p si completand acest tablou ın prima parte punand p[j] = k, unde k da maximul.Acest tablou poate fi utilizat la determinarea subsecventei crescatoare maximale ın timpul O(n). Uti-lizarea tabloului p este similara cu cea a tabloului bidimensional p de la drumurile minime. sfobs

Page 194: algoritmi_tehnici_dorel lucanu - carte

11.6. STUDIU DE CAZ: DISTANTA INTRE SIRURI 205

11.5.4 Determinarea numai a lungimii subsecventei optime

11.6 Studiu de caz: Distanta ıntre siruri

11.6.1 Descrierea problemei

Se considera doua siruri α = a1 · · · an si β = b1 · · · bn formate cu litere dintr-un alfabet A.Asupra sirului α se pot face urmatoarele operatii:

• Stergere: S(i) – sterge litera de pe pozitia i;

• Inserare: I(i, c) – insereaza litera c pe pozitia i;

• Modificare: M(i, c) – ınlocuieste litera de pe pozitia i cu c.

Problema consta ın determinarea unei secvente de operatii de lungime minima care transformape α ın β.

Exemplu: Fie α = carnet, β = paleta. O secventa de transformari este carnet → parnet → palnet →palet → paleta. Transformarile efectuate sunt M(1, p), M(3, l), S(4) si I(6, a). Exista o alta secventa maiscurta? sfex

11.6.2 Modelul matematic

Mai ıntai dovedim cateva proprietati ale secventelor optime de transformari care duc pe α ın β.

Lema 11.1. Fie s = (. . . T (i, •), T ′(j, •) . . .) o secventa optima (de lungime minima) care transformape α ın β. Atunci exista k, astfel ıncat secventa s′ = (. . . T ′(k, •), T (, •) . . .), obtinuta din s prininterschimbarea celor doua operatii T si T ′ si ın rest ramanand neschimbata, este de asemenea o secventaoptima care transforma pe α ın β.

Demonstratie. Distingem urmatoarele cazuri.1. T (i, •) = S(i), T ′(j, •) = S(j). Nu conteaza ordinea ın care sunt sterse doua litere. k si sunt pozitiilede stergere actualizate.2. T (i, •) = S(i), T ′(j, •) = I(j, c). Daca i > j atunci T ′(k, •) = I(j, c) si T (, •) = S(i + 1). Daca i ≤ jatunci T ′(k, •) = I(j + 1, c) si T (, •) = S(i).3. T (i, •) = S(i), T ′(j, •) = M(j, c). Analog cazului 2.4. T (i, •) = I(i, c), T ′(j, •) = S(j). Daca i = j atunci se procedeaza ca la 2. Daca i = j atunci,datorita faptului ca executia succesiva a operatiilor I(i, c), S(i) lasa neschimbat sirul, rezulta ca secventade operatii nu ar fi optima.5. T (i, •) = I(i, c), T ′(j, •) = M(j, c). Analog cu 2.6. T (i, •) = I(i, c), T ′(j, •) = I(j, c). Nu are importanta ordinea ın care sunt inserate doua litere. k si sunt pozitiile de inserare actualizate.Celelalte cazuri, cand T (i, •) = M(i, c) se trateaza ın mod asemanator. sfdem

Corolar 11.2. Exista o secventa optima care daca efectueaza transformarile:

α = α0 → α1 → · · · → αt = β

atunci pentru orice i, |αi| ≤ |β|, unde prin | | am notat lungimea sirului .

Demonstratie. Primele transformari care se fac sunt stergerile. sfdem

Notam cu d(α, β) lungimea unei secvente optime.

Lema 11.2. Are loc:

(i) d(α, α) = 0;

Page 195: algoritmi_tehnici_dorel lucanu - carte

206 CAPITOLUL 11. PROGRAMARE DINAMICA

(ii) d(α, β) = d(β, α);

(iii) d(α, γ) ≤ d(α, β) + d(β, γ).

Demonstratie. (i) este evidenta. Proprietatea (ii) rezulta din faptul ca orice operatie T : α → β areinversa T−1 : β → α:

S−1(i) = I(i, ai)I−1(i, c) = S(i)M−1(i, c) = M(i, ai)

(iii) rezulta din conditia de minim. sfdem

Observatie: Lema de mai sus arata ca d(α, β) este o metrica. De aici si numele problemei. sfobs

In continuare aplicam metoda programarii dinamice pentru determinarea secventei optime. Definimdrept stare subproblema DS(αi, βj) corespunzatoare transformarii subsirului αi = a1 . . . ai ın βj =b1 . . . bj si prin d[i, j] valoarea optima d(αi, βj). Daca i = 0 atunci βj se obtine prin j inserari: deci d[0, j] =j. Daca j = 0 atunci βj se obtine prin i stergeri si avem d[i, 0] = i. Presupunem i, j > 0. Consideramdecizia optima prin care starea DS(a1 . . . ai, b1 . . . bj) este transformata ıntr-o stare DS(a1 . . . ai′ , b1 . . . bj′)cu (i′ < i si j′ ≤ j) sau (i′ ≤ i si j′ < j). Deoarece ordinea efectuarii operatiilor nu conteaza, putempresupune ca exista o secventa optima pentru care prima decizie realizeaza a1 · · ·ai → a1 · · · bj (primalitera potrivita este cea de pe ultimul loc). Distingem urmatoarele situatii:

1. Daca ai = bj atunci i′ = i − 1, j′ = j − 1 si, aplicand principiul de optim, obtinem d[i, j] =d[i− 1, j − 1].

2. bj se obtine prin stergere. Exista un k < i cu ak = bj si secventa de stergeri este S(i), . . . , S(k + 1).Fara sa restrangem generalitatea putem presupune k = i− 1. Rezulta i′ = i− 1, j′ = j si, aplicandprincipiul de optim, obtinem d[i, j] = d[i− 1, j] + 1.

3. bj se obtine prin inserarea I(i + 1, bj). Avem i′ = i, j′ = j − 1 si, aplicand principiul de optim,obtinemd[i, j] = d[i, j − 1] + 1. Din corolarul lemei precedente rezulta ca aceasta operatie poate firealizata numai daca i < j.

4. bj se obtine prin modificarea M(i, bj). Avem i′ = i− 1, j′ = j − 1 si, aplicand principiul de optim,obtinem d[i, j] = d[i− 1, j − 1] + 1.

Deoarece d[i, j] trebuie sa fie minima, rezulta:

d[i, j] = mind[i− 1, j] + 1, d[i− 1, j − 1] + δ, d[i, j − 1] + 1

unde

δ =

0 , daca ai = bj

1 , daca ai = bj

In continuare vom utiliza valorile d[i, j] la determinarea secventei optime. Procedeul este asemanatorcu cel de la subsecventa maximala, varianta a doua, numai ca acum se cauta ıntr-un tablou bidimensional.Notam cu L lista care ınregistreaza transformarile solutiei optime. Se procedeaza ın modul urmator:

• initial se considera i := n; j := n; si L := ( ) (lista vida);

• urmatorul proces se repeta pana cand i si j devin 0:

– daca d[i, j] = d[i− 1, j − 1] atunci L ramane neschimbata si se face i := i-1; j := j-1;

– altfel, daca d[i, j] = d[i− 1, j − 1] + 1 atunci se face L := M(i, bj)@L si i:=i-1; j:=j-1;

– altfel, daca d[i, j] = d[i− 1, j] + 1 atunci se face L := S(i)@L si i:=i-1;

– altfel, daca d[i, j] = d[i, j − 1] + 1 atunci se face L := I(i, bj)@L si j:=j-1.

Schema procedurala care determina distantele este:

Page 196: algoritmi_tehnici_dorel lucanu - carte

11.7. PREZENTAREA FORMALA A PARADIGMEI 207

procedure distSir(a, b, n)begin

for j ← 1 to n dod[0,j] ← j

for i ← 1 to n dod[i,0] ← i

for i ← 1 to n dofor j ← 1 to n do

δ ← if (a[i]=b[j]) then 0 else 1d[i, j] ← mind[i− 1, j] + 1, d[i− 1, j− 1] + δ, d[i, j− 1] + 1

L ← listaVida()i ← nj ← nrepeat

if (d[i,j] = d[i-1,j-1])then i ← i-1

j ← j-1else if (d[i,j] = d[i-1,j-1]+1)

then push(L, (‘M’, i, b[j]))i ← i-1j ← j-1

else if (d[i,j]=d[i-1,j]+1)then push(L, (’S’, i))

i ← i-1else push(L, (’I’, i, b[j]))

j ← j-1until ((i = 0) and (j = 0))

end

11.6.3 Implementare

Valorile d[i, j] sunt memorate ıntr-un tablou bidimensional si ordinea de calcul este linie cu linie, ıncepandcu linia 1. Secventa de transformari va fi memorata ıntr-o lista liniara abstracta.

Notam ca utilizarea programului de mai sus necesita o implementare a tipului abstract Lista.

Evaluarea algoritmului este simpla si conduce la urmatorul rezultat:

Teorema 11.1. Determinarea distantei optime si a secventei optime care transforma un sir α ıntr-unsir β, |α| = |β| = n, se poate face ın timpul O(n2).

11.7 Prezentarea formala a paradigmei

11.7.1 Modelul matematic

Problemele ale caror solutii se pot obtine prin programarea dinamica sunt probleme de optim. Un prototipde astfel de problema este urmatorul:

Sa se determine:optim R(x0, . . . , xm−1) (11.6)

dupa x0, . . . , xm−1, ın conditiile ın care acestea satisfac restrictii de forma:

g(x0, . . . , xm−1) ? 0 (11.7)

unde ? ∈ <, ≤, =, ≥, >.

Page 197: algoritmi_tehnici_dorel lucanu - carte

208 CAPITOLUL 11. PROGRAMARE DINAMICA

Prin optim ıntelegem min sau max iar ecuatia 11.6 se mai numeste si functie obiectiv. Un alt prototip estefurnizat de digrafurile ponderate, unde R(x0, . . . , xm−1) exprima suma ponderilor arcelor x0, . . . , xm−1,iar restrictiile impun ca x0, . . . , xm−1 sa fie drum sau circuit cu anumite proprietati.

Paradigma programarii dinamice propune gasirea valorii optime prin luarea unui sir de decizii 〈d1, . . . , dn〉,numit si politica, unde decizia di transforma starea (problemei) si−1 ın starea si, aplicand principiul deoptim[BD62]:

Secventa de decizii optime (politica optima) care corespunde starii s0 are proprietatea cadupa luarea primei decizii, care transforma starea s0 ın starea s1, secventa de decizii (politica)ramasa este optima pentru starea s1.

De cele mai multe ori prin stare a problemei ıntelegem de fapt o subproblema. Toate studiile de caz dinacest capitol utilizeaza aceasta definitie pentru stare. Unei stari s ıi asociem o valoare z si definim f(z)astfel ıncat, daca starea s corespunde problemei initiale, atunci

f(z) = optim R(x0, . . . , xm−1)

Principiul de optim conduce la obtinerea unei ecuatii functionale de forma [BD62]:

f(z) = optimy

[H(z, y, f(T (z, y)))] (11.8)

unde:

• s and s′ sunt doua stari astfel ıncat una se obtine din cealalta aplicand decizia d,• z este valoarea asociata starii s,• T (z, y) calculeaza valoarea starii s′, iar• H exprima algoritmul de calcul al valorii f(z) dat de decizia d.

Relatia de mai sus poate fi interpretata astfel: dintre toate deciziile care se pot lua ın starea s (saucare conduc la starea s), se alege una care da valoarea optima ın conditiile ın care politica aplicata ıncontinuare (sau pana atunci) este este si ea optima.

Relatia 11.8 poate fi dovedita utilizand inductia si reducerea la absurd. Deoarece este posibil caprincipiul de optim sa nu aiba loc pentru anumite formulari, este necesara verificarea sa pentru problemasupusa rezolvarii. Rezolvarea ecuatiilor recurente 11.8 conduce la determinarea unui sir de decizii ce ınfinal constituie politica optima prin care se determina valoarea functiei obiectiv.

11.7.2 Implementare

Principul de optim implica proprietatea de substructura optima a solutiei, care afirma ca solutia optimaa problemei include solutiile optime ale subproblemelor sale. Aceasta proprietate este utlizata la gasireasolutiilor corespunzatoare starilor optime. In general, programele care implementeaza modelul dat deprogramarea dinamica au doua parti:

1. In prima parte determina valorile optime date de sirul de decizii optime, prin rezolvarea ecuatiilor11.8. Presupunem ca pentru exemplul retelei de numere valorile sunt memorate ıntr-un tablouunidimensional f.

2. In partea a doua se construiesc solutiile (valorile xi care dau optimul) corespunzatoare stariloroptime pe baza valorilor calculate ın prima parte, utlizand proprietatea de substructura optima.

Nu se recomanda scrierea unui program recursiv care sa calculeze valorile optime. Daca ın procesulde descompunere problema → subproblema, o anumita subproblema apare de mai multe ori, eava fi calculata de cate ori apare. Este mult mai convenabil ca valorile optime corespunzatoaresubproblemelor sa fie memorate ıntr-un tablou si apoi combinate pe baza ecuatiilor 11.8 pentrua obtine valoarea optima a unei supraprobleme. In acest fel, orice subproblema este rezolvata osingura data (aici este una dintre diferentele dintre programarea dinamica si strategia divide-et-impera unde o aceeasi subproblema poate fi calculata de mai multe ori), iar determinarea valoriloroptime se face de la subproblemele mai mici la cele mai mari (“bottom-up”). Prin memorarea

Page 198: algoritmi_tehnici_dorel lucanu - carte

11.8. REFERINTE BIBLIOGRAFICE 209

valorilor optime ıntr-un tablou, regasirea oricareia dintre ele se face ın timpul O(1) ceea ce conducela un timp scurt de calcul pentru optimul unei supraprobleme. Toate aceste observatii sunt stranslegate cu metoda de derecursivare din subsectiunea ??. Pentru exemplul cu numerele asezate ınretea valorile corespunzatoare drumurilor optime vor fi memorate ıntr-un tablou unidimensional siordinea de calcul va fi de la baza triunghiului spre varf, adica ın ordinea descrescatoare a indicilor.

Complexitatea algoritmului care calculeaza valorile optime depinde direct de tipul de recursivitateimplicat de recurentele rezultate prin aplicarea principiului de optim. Daca rezulta o recursivitateliniara atunci stim de la tehnicile de derecursivare (subsectiunea ??) ca valorile optime ale subprob-lemelor pot fi calculate ın timp liniar si memorate ıntr-un tablou unidimensional. In cazul recursieiın cascada lucrurile sunt mai complicate. Daca adancimea arborelui corespunzator apelurilor recur-sive este n atunci rezulta un numar de 2n de subprobleme de rezolvat. In unele cazuri, o redefinirea notiunii de stare poate conduce la obtinerea unei recursii liniare obtinandu-se astfel o reduceredrastica a complexitatii – de la exponential la polinomial. De asemenea, o reducere la complexi-tate polinomiala (de cele mai multe ori patratica) se obtine atunci cand se poate aplica metoda dederecursivare cu memorarea rezultatelor pentru subprobleme ın tabele (subsectiunea ??). Pentruproblemele dificile (cele NP-complete) o astfel de posibilitati nu exista. Pentru aceste cazuri secauta un mod de memorare cat mai compacta a valorilor optime pentru subprobleme si metodecat mai eficiente pentru calculul acestora astfel ıncat, pentru instantele de dimensiuni rezonabile,determinarea solutiei sa se faca ıntr-un timp acceptabil.

11.8 Referinte bibliografice

In scrierea acestui capitol am fost cel mai mult influentat de [CLR93, HS84]. Mai pot fi consultate[LG86, Sed88].

Page 199: algoritmi_tehnici_dorel lucanu - carte

210 CAPITOLUL 11. PROGRAMARE DINAMICA

11.9 Exercitii

Exercitiul 11.1. Se considera urmatoarea varianta a determinarii LEP minime:

Se considera date o lista de numere ıntregi x0 = (x01, . . . , x

0n) si un alt numar ıntreg

M0. Acestea constituie starea initiala a problemei. O decizie corespunzatoare starii〈(x1, . . . , xk), M〉 consta ın extragerea a doua numere xi si xj din lista x = (x1, . . . , xk),introducerea ın locul lor ın lista a sumei xi +xj si de asemenea adaugarea acestei sume laM . Se obtine o noua stare 〈x′, M ′〉 unde x′ = x\ (xi, xj)∪ (xi +xj) si M ′ = M +xi +xj .Problema consta ın determinarea unei secvente de decizii care conduce la starea finala〈(x0

1 + · · ·+ x0n), M〉 cu M minim.

Notam cu LEPOPT(〈x, M〉) valoarea sumei din starea finala data de solutia optima.

(a) Sa se arate ca:1

LEPOPT(〈x, M〉) = minLEPOPT(〈x \ (u, v) ∪ (u + v), M + (u + v)〉) |u, v apar ca elemente distincte ın x (11.9)

(b) Utilizand 11.9 sa se calculeze LEPOPT(〈(5, 8, 3, 11), 0〉). Valorile starilor intermediare vor fimemorate ıntr-un tabel. Apoi sa se deduca din acest tabel secventa de decizii optime.

(c) Sa se proiecteze un algoritm bazat pe paradigma programarii dinamice care determina solutiaoptima.

(d) Sa se arate ca starile date de algoritmul greedy satisfac:

LEPOPT(〈x, M〉) = LEPOPT(〈x \ (u, v) ∪ (u + v), M + (u + v)〉) (11.10)

unde u = min x si v = min(x \ (u)).

(e) Explicati diferentele si asemanarile dintre algoritmul greedy si cel dat de programarea di-namica.

Exercitiul 11.2. Urmatorul algoritm, cunoscut sub numele de algoritmul Bellman-Ford, deter-mina drumurile minime ıntr-un digraf ponderat D = (〈V, A〉, ) care pleaca dintr-un varf i0 dat.Pentru fiecare varf i, d[i] va fi lungimea drumului minim de la i0 la i si p[i] va fi predecesorul lui ipe drumul minim de la i0 la i.

procedure BellmanFord(D, i0, d, p)beginfor i ← 1 to n do

p[i] ← 0d[i] ← ∞

d[i0] ← 0for k ← 1 to n-1 do

for fiecare 〈i, j〉 ∈ A doif ([j] > d[j]+[i,j])then d[j] ← d[i] + [i,j]

p[j] ← i;for fiecare 〈i, j〉 ∈ A do

if (d[j] > d[i]+[i,j])then throw ’exista drum de lungime negativa’

end

1Aici privim listele ca reprezentari ale multi-multimilor. Intr-o multi-multime U un element u poate apare de mai multeori. Astfel, o multi-multime U peste S poate fi definita ca fiind o functie U : S → N, unde U(a) reprezinta de cate oriapare elementul a ∈ S ın U . Operatiile peste multi-multimi se definesc ın mod natural. De exemplu a ∈ U ⇐⇒ U(a) > 0,(U ∪ V ) : S → N este data prin (U ∪ V )(a) = U(a) + V (a), etc.

Page 200: algoritmi_tehnici_dorel lucanu - carte

11.9. EXERCITII 211

Se cere:

(a) Sa se defineasca notiunea de stare (subproblema) pentru problema drumurilor minime cu sursaprecizata.

(b) Sa se aplice principiul de optim pentru a obtine relatia de recurenta.(c) Sa se precizeze ordinea ın care sunt rezolvate subproblemele.(d) Sa se arate ca daca digraful D nu are circuite negative atunci algoritmul Bellman-Ford deter-

mina corect drumurile minime care pleaca din i0.(e) Sa se determine complexitatea algoritmului Bellman-Ford.

Exercitiul 11.3. (Inmultirea optima a unui sir de matrici.) Se considera un sir (A1, . . . , An)de matrici, unde Ai este de dimensiune pi × pi+1. Se doreste calcularea produsului A1A2 · · ·An,utilizand un subprogram de ınmultire a doua matrici. Datorita asociativitatii, exista mai multeposibilitati de ınmultire a matricelor doua cate doua. Numarul posibilitatilor este egal cu numarulexpresiilor complet parantetizate. De exemplu, pentru n = 4 exista cinci posibilitati. Inmultireaa doua matrici de dimensiuni p × q si respectiv q × r necesita pqr ınmultiri. Problema constaın determinarea unei ordini de ınmultire a matricelor doua cate doua (echivalent, a unei expresiicomplet parantetizate) care da numarul minim de ınmultiri.

(a) Pentru 1 ≤ i ≤ j ≤ n, se noteaza cu m[i, j] numarul minim de ınmultiri necesare pentru acalcula Ai · · ·Aj . Sa se arate ca:

m[i, j] =

0 , daca i = j

mini≤k<jm[i, k] + m[k + 1, j] + pipk+1pj+1 , daca i < j

(b) Sa se scrie un program care determina valorile m[i, j]. Care este complexitatea algoritmuluidescris de program?

(c) Sa se proiecteze o structura de date pentru reprezentarea unei ordini de ınmultire (unei expresiicomplet parantetizate).

(d) Sa se scrie un program care, avand la intrare valorile calculate la punctul 2, determina o ordinede ınmultire optima.

(e) Sa se modifice algoritmul de la 2 astfel ıncat sa determine simultan valorile m[i, j] cat si ordineade ınmultire optima.

Exercitiul 11.4. Sa se scrie un program care, pentru doua secvente x = (x1, . . . , xm) si y =(y1, . . . , yn) date, determina o cea mai lunga subsecventa comuna (subsecventa trebuie ınteleasa ınsensul definitiei din 11.5.1).Indicatie. Se procedeaza ıntr-o maniera asemanatoare cu cea de la distanta dintre siruri.

Exercitiul 11.5. [CLR93] Fie P un poligon convex ın plan. O triangularizare a poligonului P esteo multime T de diagonale ale lui P care ımparte interiorul poligonului ın triunghiuri cu interioareledisjuncte (de aici rezulta ca diagonalele nu se intersecteaza). Laturile unui triunghi sunt laturi saudiagonale complete ale poligonului. Peste multimea tuturor triunghiurilor ce participa la cel putino triangularizare se considera data o functie de ponderi w. Ca exemplu, se poate considera dreptpondere a unui triunghi suma lungimilor laturilor sale. Sa se scrie un program care sa determine otriangularizare pentru care suma ponderilor este minima.Indicatie. Presupunem P = v1 . . . vn (vi sunt varfurile poligonului). Unei triangularizari ıi putemasocia un arbore binar definit recursiv astfel: radacina arborelui este latura v1vn. Fie v1vnvi tri-unghiul din triangularizare care are pe v1vn ca latura. Daca v1vi este diagonala atunci subarboreleaflat la stanga va fi cel corespunzator subpoligonului marginit de v1vi, aflat ın partea opusa triunghi-ului si cu radacina v1vi. Daca v1vi este latura a poligonului (i.e. i = 2) atunci subarborele aflat lastanga va fi format numai din nodul v1vi. Analog, daca vnvi este diagonala atunci subarborele aflatla dreapta va fi cel corespunzator subpoligonului marginit de vnvi, aflat ın partea opusa triunghiuluisi cu radacina vnvi. Daca vnvi este latura a poligonului (i.e. i = n− 1) atunci subarborele aflat ladreapta va fi format numai din nodul vnvi. Un exemplu de construire a arborelui este aratat ın fig.11.8. In continuare se rationeaza la fel ca la ınmultirea optima a matricelor (exercitiul 11.3).

Page 201: algoritmi_tehnici_dorel lucanu - carte

212 CAPITOLUL 11. PROGRAMARE DINAMICA

v1

v2

v3

v4 v5

v6

v7

Figura 11.8: Triangularizare si arborele binar atasat

Exercitiul 11.6. Fie p1, . . . , pn n puncte ın plan. Presupunem pi = (xi, yi) cu xi = xj daca i = j.Un traseu monoton este un drum care uneste cel mai din stanga punct cu cel mai din dreapta sieste format din segmente ce unesc puncte din p1, . . . , pn si pot fi parcurse toate ın acelasi sens(de exemplu, de la stanga la dreapta). Un tur bitonic este format din reuniunea a doua traseemonotone care conecteaza toate cele n puncte. Un exemplu de tur bitonic este dat ın fig. 11.9. Sase scrie un program care determina un tur bitonic de lungime minima.Indicatie. Se vor explora punctele de la stanga la dreapta, mentinandu-se cele doua trasee optime.

Figura 11.9: Tur bitonic

Exercitiul 11.7. [CLR93] Se considera problema scrierii la imprimanta ıntr-un mod estetic a unuiparagraf. Textul de intrare este o secventa de n cuvinte w1, . . . , wn de lungimi 1, . . . , n, respectiv.Lungimile cuvintelor sunt masurate ın caractere. Se doreste scrierea acestui paragraf ıntr-un modcat mai estetic astfel ıncat fiecare linie contine cel mult M caractere. Criteriul prin care se masoara“estetica” textului este urmatorul. Daca o linie contine cuvintele de la wi la wj , atunci numarul despatii de la sfarsitul liniei este M − j + i−

∑jk=i k. Un text scris estetic minimizeaza suma, dupa

toate liniile exceptand ultima, a cuburilor numerelor de spatii extra de la fiecare sfarsit de linie. Sase scrie un program care scrie la imprimanta paragraful dat respectand acest criteriu de esteticitatedescris mai sus. Se presupune ca M ≤ 80 si ca un paragraf are cel mult 20 linii.

Exercitiul 11.8. [CLR93] Cand un terminal “inteligent” modifica o linie a unui text, ınlocuindsirul “sursa” x[1..m] cu sirul “destinatie” y[1..n], exista cateva operatii de baza prin care realizeazaaceasta modificare:

(a) un caracter al textului sursa poate fi sters (delete c), ınlocuit (replace c by c′), sau copiat(copy c) ın textul destinatie;

(b) un caracter este inserat ın textul destinatie (insert c);

(c) doua caractere vecine din textul sursa sunt interschimbate ın timpul copierii ın textul destinatie(twidle cc′ into c′c;

(d) dupa efectuarea tuturor operatiilor de tipul celor de mai sus astfel ıncat textul destinatie estecomplet, sufixul textului sursa este sters (kill . . .).

Consideram ca exemplu modificarea cuvantului algorithm ın altruistic:

Page 202: algoritmi_tehnici_dorel lucanu - carte

11.9. EXERCITII 213

Operatie text sursa Text destinatiecopy a lgorithm acopy l gorithm alreplace g by t orithm altdelete o rithm altcopy r ithm altrinsert u ithm altruinsert i ithm altruiinsert s ithm altruistwidle it into ti hm altruistiinsert c hm altruistickill hm altruistic

Fiecare operatie = kill are asociat un cost. Se presupune, de exemplu, ca operatia de ınlocuireare costul mai mic decat suma costurilor operatiilor de stergere si de inserare. Costul unei operatiide modificare este suma costurilor operatiilor individuale. Sa se scrie un program care, avand laintrare textele sursa si destinatie, determina secventa de opratii care modifica sursa ın destinatiecu un cost minim.

Exercitiul 11.9. [CLR93] Profesorul McKenzie este consultat de presedintele companiei A&BCompany pentru a planifica o petrecere cu angajatii companiei. Relatia sef-subaltern din companiepoate fi reprezentata printr-un arbore ın care radacina este presedintele companiei. La angajare, ınurma uui interviu, fiecarui angajat i s-a atribuit un coeficient de “jovialitate”, care este un numarreal. Pentru a face petrecerea mai nostima, s-a decis sa nu participe nici o pereche formata dintr-unangajat si seful lui direct.

(a) Sa se scrie un program care-l ajuta pe profesor saplanifice petrecerea astfel ıncat coeficientultotal de jovialitate (= suma coeficientilor individuali a persoanelor care participa la petrecere)sa fie maxim.

(b) Sa se modifice programul de la 1. astfel ıncat presedintele companiei sa participe la petrecereacompaniei sale.

Page 203: algoritmi_tehnici_dorel lucanu - carte

214 CAPITOLUL 11. PROGRAMARE DINAMICA

Page 204: algoritmi_tehnici_dorel lucanu - carte

Capitolul 12

“Backtracking” si “branch andbound”

“Backtracking” si “branch and bound” sunt doua strategii care ımbunatatesc cautarea exhaustiva. Unalgoritm de cautare exhaustiva este definit dupa urmatoarea schema: se defineste spatiul solutiilor candi-dat U si cu un algoritm de enumerare se selecteaza acele solutii candidat care sunt solutii ale problemei.In general, o solutie candidat este solutie a problemei daca satisface o anumita conditie, notata cu ST(eSTe), ce poate fi testata ın timp polinomial. Putem privi ST ca fiind o functie ST : U→ Boolean.

“Backtracking” si “branch and bound” propun o cautare sitematica ın spatiul solutiilor. Ambelestrategii au la baza urmatoarele ingrediente:

1. Spatiul solutiilor este organizat ca un arbore cu radacina astfelıncat exista o corespondenta bijectivaıntre varfurile de pe frontiera arborelui si solutiile candidat. De cele mai multe ori solutia candidateste descrisa de drumul de la radacina la varful de pe frontiera corespunzator.

2. Cautarea sistematica se realizeaza cu ajutorul unui algoritm de explorare sistematica a acestuiarbore.

3. Varfurile arborelui sunt clasificate astfel:

(a) un varf viabil este un varf pentru care sunt sanse sa se gaseasca o solutie a problemei explorandsubarborele cu radacina ın acel varf;

(b) un varf activ (live) este un varf care a fost vizitat cel putin o data de algoritmul de exploraresi urmeaza sa mai fie vizitat cel putin ınca o data;

(c) un varf activ dupa ce a fost vizitat ultima data de algoritmul de explorare devine inactiv(death).

4. Sunt explorati numai subarborii cu radacini viabile. In felul acesta se evita procesarea inutila asubarborilor pentru care suntrem siguri ca nu contin solutii.

5. Cele doua strategii, ”backtracking” si ”branch and bound”, difera doar prin modul ın care exploreazalista varfurilor viabile din arbore.

12.1 Organizarea spatiului solutiilor candidat

12.1.1 Produs cartezian

Consideram mai ıntai cazul cand toate elementele produsului cartezian au aceeasi lungime. Fara sa re-strangem generalitatea, putem considera problema enumerarii elementelor produsului cartezian 0, . . . , m−1n = 0, . . . , m−1× · · ·×0, . . . , m−1 (de n ori). Dimensiunea spatiului solutiilor candidat este mn.Multimea 0, . . . , m − 1n poate fi reprezentata printr-un arbore cu n nivele ın care fiecare varf internare exact m succesori iar varfurile de pe frontiera corespund elementelor multimii. De exemplu, arborelecorespunzator cazului m = 2 si n = 3 este reprezentat grafic ın fig. 12.1.

215

Page 205: algoritmi_tehnici_dorel lucanu - carte

216 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

•0 1

(0, 0, 0) (0, 0, 1)

•0 1

(0, 1, 0) (0, 1, 1)

0 1

•0 1

(1, 0, 0) (1, 0, 1)

•0 1

(1, 1, 0) (1, 1, 1)

0 1

0 1

Figura 12.1: Arborele produsului cartezian

Fiecare varf ın arbore este identificat de drumul de la radacina la el: notam acest drum cu (x0, . . . , xk).Pentru varfurile de pe frontiera avem k = n− 1 iar drumul (x0, . . . , xn−1) este un element al produsuluicartezian. Algoritmul pe care-l prezentam va simula generarea acestui arbore prin parcurgerea DFS.Deoarece “adresele” varfurilor succesoare pot fi determinate printr-un calcul foarte simplu, stiva estereprezentata de o variabila simpla k, care indica pozitia varfului stivei.

procedure enumProdCart(n, m)begin

k ← 0x[0] ← -1while (k ≥ 0) do

if (x[k] < m-1)then x[k] ← x[k]+1

if (k = n)then scrieElement(x,n)else k ← k+1

x[k] ← -1else k ← k-1

end

Varianta recursiva a programului enumProdCart este urmatoarea:

procedure enumProdCartRec(x, k)begin

for j ← 0 to m-1 dox[k] ← jif (k = n-1)then scrieElement(x, n)else enumProdCartRec(x, k+1)

end

Enumerarea tuturor elementelor produsului cartezian se face executand apelul:

enumProdCartRec(x, 0)

Consideram acum cazul cand elementele produsului cartezian au lungimi diferite. Presupunem dinnou, fara sa restrangem generalitatea, ca se doreste enumerararea elementelor produsului cartezian0, . . . , m1 − 1 × · · · × 0, . . . , mn − 1. Programul de enumerare se obtine prin ınlocuirea ın programulcorespunzator de mai sus a variabilei simple m cu componenta tablou m[k], unde m[k] = mk.

Page 206: algoritmi_tehnici_dorel lucanu - carte

12.1. ORGANIZAREA SPATIULUI SOLUTIILOR CANDIDAT 217

2

2 21 0 1 0

1 0 22 0 1

0 1

Figura 12.2: Permutari - varianta I (n=3)

12.1.2 Submultimi

Fie A = a0, . . . , an−1 o multime finita cu n elemente. O submultime S ⊆ A poate fi reprezentata devectorul sau caracteristic (x[i] | 0 ≤ i < n), unde

x[i] =

1 daca ai ∈ S,

0 daca ai ∈ S.

Acum enumerarea submultimilor multimii A este echivalenta cu enumerarea elementelor produsuluicartezian 0, 1n. Dimensiunea spatiului solutiilor candidat este 2n.

12.1.3 Permutari

Notam cu Sn multimea permutarilor multimii 0, 1, . . . , n−1. Dimensiunea spatiului solutiilor candidateste n! = 1 · 2 · · · · · n.

12.1.3.1 Varianta I

Spatiul solutiilor este reprezentat ca un arbore ın care orice drum de la radacina la frontiera descrie opermutare. Arborele pentru S3 este reprezentat ın fig. 12.2. Deoarece orice permutare din Sn este unelement al produsului cartezian 0, 1, . . . , n−1n ce se satisface anumite restrictii, rezulta ca putem utilizaalgoritmul “backtracking” descris ın sectiunea ??. Un varf x[k] este viabil daca satisface urmatoareaproprietate:

0 ≤ x[k] ≤ n− 1 ∧ (∀i)0 ≤ i < k ⇒ x[i] = x[k]

Verificarea conditiei de mai sus este destul de costisitoare, O(k). Deoarece aceasta conditie este verificatapentru toate valorile candidat pentru x[k], rezulta ca timpul cel mai nefavorabil pentru determinareaunui x[k] viabil este O(k2). Performantele algoritmului pot fi ımbunatatite daca se considera un tablousuplimentar (y[j] | 0 ≤ j < n) cu semnificatia:

y[j] =

1 daca exista i astfel ıncat x[i] = j,

0 altfel.

Cautarea urmatorului x[k] viabil se face incrementand x[k] pana cand are loc conditia y[x[k]] = 0, dupacare y[x[k]] devine 1. Decrementarea lui k este de asemenea precedata de atribuirea valorii 0 lui y[x[k]].

12.1.3.2 Varianta II

Se bazeaza pe alta reprezentare arborescenta a permutarilor. Cazurile practice ın care aceasta enumerareeste utilizata ca baza pentru strategia “backtracking” sunt mai rare dar enumerarea simpla a permutariloreste mai eficienta.

Page 207: algoritmi_tehnici_dorel lucanu - carte

218 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

Enumerarea recursiva. Scrierea unui program recursiv pentru generarea permutarilor trebuie saaiba ca punct de plecare o definitie recursiva pentru Sn. Daca (i0, . . . , in−1) este o permutare din Sn cuik = n − 1 atunci (. . . ik−1, ik+1, . . .) este o permutare din Sn−1. Deci orice permutare din Sn se obtinedintr-o permutare din Sn−1 prin insertia lui n ın una din cele n pozitii posibile. Evident, permutaridistincte din Sn−1 vor produce permutari diferite ın Sn. Aceste observatii conduc la urmatoarea definitierecursiva:

S1 = (0)Sn = (i0, . . . , in−2, n− 1), . . . , (n− 1, i0, . . . , in−2) | (i0, . . . , in−2) ∈ Sn−1

Generalizam prin considerarea multimii Sn(π, k) a permutarilor din Sn ce pot fi obtinute din permutareaπ ∈ Sk. Pentru Sn(π, k) avem urmatoarea definitie recursiva:

Sn(π, k) = Sn((i0, . . . , ik−1, k), k) ∪ · · · ∪ Sn((k, i0, . . . , ik−1), k)

unde π = (i0, . . . , ik−1). Are loc Sn = Sn((0), 0) si Sn(π, n − 1) = π. Vom scrie un subprogramrecursiv pentru calculul multimii Sn(π, k) si apoi vom apela acest subprogram pentru determinarea luiSn. Pentru reprezentarea permutarilor utilizam tablouri unidimensionale. Subprogramul recursiv carecalculeaza multimea Sn(π, k) are urmatoarea descriere:

procedure enumPermRec(p, k)begin

if (k = n-1)then scriePerm(p,n)else p[k] ← k

for i ← k-1 downto 0 doenumPermRec(p,k+1)swap(p[i+1],p[i])

enumPermRec(p,k+1)end

Enumerarea tuturor celor n! permutari se realizeaza prin executia urmatoarelor doua instructiuni:

p[0] ← 0enumPermRec(p, 0)

Enumerarea nerecursiva. Metodei recursive i se poate atasa un arbore ca ın fig. 12.3. Fiecare varfintern din arbore corespunde unui apel recursiv. Varfurile de pe frontiera corespund permutarilor din Sn.Ordinea apelurilor recursive coincide cu ordinea data de parcurgerea DFS a acestui arbore. Daca vomcompara programul recursiv care genereaza permutarile cu varianta recursiva a algoritmului DFS, vomobserva ca ele au structuri asemanatoare. Si este normal sa fie asa, pentru ca programul de generare apermutarilor realizeaza acelasi lucru: parcurgerea mai ıntai ın adancime a arborelui din fig. 12.3. Deci sivarianta nerecursiva a algoritmului de generare a permutarilor poate fi obtinut din varianta nerecursivaa algoritmului DFS. Locul tabloului p din DFS este luat de o functie f(k, i, p) care pentru o permutare(p[0], . . . , p[k − 1]) (aflata pe nivelul k − 1 ın arbore) determina al i-lea succesor, 0 ≤ i ≤ k. Deoarecepentru orice permutare, corespunzatoare unui varf de pe nivelul k ≥ 1 ın arbore, putem determinapermutarea din varful tata, rezulta ca nu este necesara memorarea permutarilor ın stiva. Astfel, stiva vamemora, pentru fiecare nivel din arbore, indicele succesorului ce urmeaza a fi vizitat.

procedure enumPerm(n)begin

k ← 0S[0] ← 0while (k ≥ 0) do

if (S[k] ≥ 0)then f(k, S[k], p)

S[k-1] ← S[k-1]-1if (k = n-1)

Page 208: algoritmi_tehnici_dorel lucanu - carte

12.1. ORGANIZAREA SPATIULUI SOLUTIILOR CANDIDAT 219

then scriePerm(p,n)else k ← k+1

S[k] ← kelse aux ← p[0]

for i ← 0 to k-1 dop[i] ← p[i+1]

p[k] ← auxk ← k-1

end

Functia f(k, i, p) este calculata de urmatorul subprogram:

function f(k, i, p)begin

if (i = k)then p[k] ← kelse aux ← p[i+1]

p[i+1] ← p[i]p[i] ← aux

end

(0, 1, 2) (0, 2, 1) (2, 0, 1) (1, 0, 2) (1, 2, 0) (2, 1, 0)

(0, 1) (1, 0)

(0)

Figura 12.3: Arborele permutarilor generat de metoda recursiva

Exercitiul 12.1.1. Sa se scrie un subprogram care, pentru numerele naturale i si n date, determina ai-a permutare (ın ordinea lexicografica) din Sn.

Observatie: Algoritmul de mai sus poate fi ımbunatatit din punctul de vedere al complexitatii timp.Mai ıntai sa notam faptul ca orice algoritm de enumerare a permutarilor are complexitatea O(n!) = O(nn).Ideea este de a gasi un algoritm care sa efectueze cat mai putine operatii pentru determinarea permutariisuccesoare. Executia a c′ ·n! operatii ın loc de c ·n! cu c′ < c, semnifica, de fapt, o reducere cu (c− c′)·n!a complexitatii timp. Un astfel de algoritm este obtinut dupa cum urmeaza. In arborele din figura 12.3se schimba ordinea succesorilor permutarii (1, 0). Ordinea permutarilor de pe orice nivel din noul arboreare proprietatea ca oricare doua permutari succesive difera printr-o transpozitie de pozitii vecine. Dacase reuseste generararea permutarilor direct ın aceasta ordine, fara a simula parcurgerea arborelui, atuncise obtine un program care genereaza permutarile cu numar minim de operatii. Regula generala prin carese obtine aceasta ordine este urmatoarea (fig. 12.4):

La fiecare nivel din arborele apelurilor recursive, succesorii varfurilor de rang par ısi schimbaordinea astfel ıncat cel mai din stanga devine cel mai din dreapta si cel mai din dreapta devinecel mai din stanga.

Evitarea simularii parcurgerii arborelui se realizeaza prin utilizarea unui vector de “directii”, d = (d[k] |0 ≤ k < n), cu urmatoarea semnificatie:

• d[k] = +1 daca permutarile succesoare permutarii (p[0], . . . , p[k − 1]) sunt generate ın ordinea(p[0], . . . , p[k − 1], k), . . . , (k, p[0], . . . , p[k − 1]);

Page 209: algoritmi_tehnici_dorel lucanu - carte

220 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

• d[k] = −1 daca permutarile succesoare permutarii (p[0], . . . , p[k − 1]) sunt generate ın ordinea(k, p[0], . . . , p[k − 1]), . . . , (p[0], . . . , p[k − 1], k);

In acest mod, vectorul d descrie complet drumul de la radacina la un grup de permutari pentru caretranspozitia se aplica ın aceeasi directie. Determinarea indicelui i la care se aplica transpozitia se poateface utilizand un tablou care memoreaza permutarea inversa. Daca notam acest tablou cu pinv atunci,utilizand relatia p[pinv[k]] = k, obtinem ca locul i unde se afla k este pinv[k]. Noua pozitie a lui k va fii + d[k]. sfobs

0123

0132

0312

3012

3021

0321

0231

0213

(0, 1, 2) (0, 2, 1) (2, 0, 1) (2, 1, 0)(1, 2, 0)(1, 0, 2)

(0, 1) (1, 0)

(1)

Figura 12.4: Arborele permutarilor modificat

12.1.4 Drumuri ıntr-un (di)graf

In multe probleme practice, spatiul solutiilor candidat este dat de drumurile dintr-un (di)graf. Arborelereprezentand drumurile care pleaca dintr-un varf fixat i0 poate fi obtinut printr-o modificare minora aalgoritmului DFS:

• varianta nerecursiva:

procedure drumuriDigraf(D, i0, viziteaza())begin

for ← 0 to D.n-1 dop[i] ← D.a[i].prim

SB ← stivaVida()push(SB, i0)viziteaza(i0)while (not esteVida(SB)) do

i ← top(SB)

if (p[i] = NULL)then pop(SB)

p[i] ← D.a[i].primelse j ← p[i]->elt

p[i] ← p[i]->succif j ∈ SBthen viziteaza(j)

push(SB, j)end

• varianta recursiva:

Page 210: algoritmi_tehnici_dorel lucanu - carte

12.1. ORGANIZAREA SPATIULUI SOLUTIILOR CANDIDAT 221

4

0

1 2

3

Figura 12.5: Graf

1

1

2

3

4

5

3

2 4

4

3

1

2

2

Figura 12.6: Arborele drumurilor din graful 12.5

procedure drumuriDigrafRec(i);begin

viziteaza(i)push(SB, i)for fiecare varf j adiacent cu i do

if (j ∈ SB) then drumuriDigrafRec(j)pop(SB)

end

Daca presupunem ca graful din fig. 12.5 este reprezentat de listele de adiacenta:

0→ (1, 4)1→ (0, 2, 3)2→ (1, 3)3→ (1, 2, 4)4→ (0, 3)

atunci arborele care reprezinta toate drumurile ce plecaa din 0 este cel reprezentat ın fig. 12.6.Un caz particular ıl constituie labirintele. De exemplu, labirintul din fig. 12.7a poate fi reprezentat

prin matricea:

a =

0 0 1 11 0 1 11 0 0 01 0 1 00 0 0 00 1 1 0

Page 211: algoritmi_tehnici_dorel lucanu - carte

222 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

(5,3)

a) b)

(0,0)

Figura 12.7: Labirint

care, la randul ei, este reprezentata de graful din fig. 12.7b.Parcurgerea tuturor drumurilor din labirint care plecaa din (0, 0) nu presupune constructia efectiva

a grafului ci utilizarea directa matricea a. Convenim ca ın timpul parcurgerii sa punem a[i, j] = 2 dacasi numai daca (i, j) este ın stiva (elementele egale cu 2 din matrice vor descrie stiva SB). Presupunemca listele de adiacenta sunt reprezentate ın ordinea parcurgerii vecinilor ın sensul arcelor se ceasornicıncepand cu vecinul din dreapta. Cel maisimplu este sa modificam varianta recursiva ınlocuind bucla forcu apelurile corespunzatoare vecinilor:

procedure drumuriLabirint(i,j);begin

viziteaza(i,j)a[i,j] ← 2if (j < n-1 and a[i,j+1] = 0) then drumuriLabirint(i, j+1)if (i < m-1 and a[i+1,j] = 0) then drumuriLabirint(i+1, j)if (j > 0 and a[i,j-1] = 0) then drumuriLabirint(i, j-1)if (i > 0 and a[i-1,j] = 0) then drumuriLabirint(i-1, j)a[i,j] ← 0

end

12.2 “Backtracking”

Paradigma “backtracking” se bazeaza pe urmatoarele ingrediente:

1. se defineste o functie criteriu prin care se stabileste daca un varf este viabil sau nu;

2. arborele este explorat prin algoritmul DFS;

3. fie x = (x0, ..., xk) secventa care descrie drumul de la radacina la varful curent;

4. daca varful curent este pe frontiera, atunci se verifica daca x este solutie;

5. ın caz contrar se alege urmatorul succesor viabil (daca exista).

Daca spatiul solutiilor candidat este produsul cartezian 0, 1, . . . , m − 1n, atunci algoritmii back-tracking au urmatoarea descriere generala:

1. varianta nerecursiva:

procedure backtrack(n, m)begin

Page 212: algoritmi_tehnici_dorel lucanu - carte

12.3. “BRANCH AND BOUND” 223

k ← 0x[0] ← -1while (k ≥ 0) do

if (x[k] < m-1)then repeat

x[k] ← x[k]+1until(viabil(x, k) or (x[k]=m-1))if (viabil(x, k))then if((k = n-1) and ST(x))

then scrieElement(x,n)else k ← k+1

x[k] ← -1else k ← k-1

end

2. varianta recursiva:

procedure backtrackRec(x, k)begin

for j ← 0 to m-1 dox[k] ← jif ((k = n-1) and (ST(x))then scrieElement(x, n)else if (viabil(x, k))

then backtrackRec(x, k+1)end

Paradigma poate fi aplicata si problemelor de optim. Presupunem ca se doreste optimizarea functieif(x). Atunci se procedeaza astfel:

1. se pleaca cu un optim initial;

2. daca varful curent este pe frontiera, atunci se verifica daca f(x) este mai bun decat optimul calculatpana ın acel moment;

3. daca da, atunci f(x) devine noul optim;

4. daca varful curent nu este pe frontiera si f() calculata pentru solutia partiala este mai ”rea” decatoptimul calculat pana ın acel moment, atunci varful nu este viabil si este abandonat.

12.3 “Branch and bound”

Se bazeaza pe urmatoarele ingrediente:

1. fiecare varf viabil este explorat o singura data;

2. cand un varf viabil este explorat, toti fiii viabili sunt generati si memorati ıntr-o structura de datede asteptare;

3. urmatorul varf explorat este ales din structura de asteptare.

Exista doua moduri de implementare pentru structura de asteptare:

• coada (FIFO). Arborele este explorat BFS.

• (min, max)-heap. Se aplica pentru problemele de optim. Se asociaza o functie predictor (valoarede cost aproximativa) pentru fiecare varf si valoarea acesteia va constitui cheia ın heap.

Page 213: algoritmi_tehnici_dorel lucanu - carte

224 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

12.4 Studiu de caz: Colorarea grafurilor

12.4.1 Descrierea problemei

Se considera un (di)graf G = (V, E) cu V = 1, . . . , n si m culori numerotate de la 1 lam. O colorare a (di)grafului este o functie de la multimea varfurilor V la multimea culorilor1, . . . , m cu proprietatea ca oricare muchie are extremitatile colorate diferit. Problemaconsta ın generarea tuturor colorarilor posibile.

Problema este inspirata de la colorarea hartilor. Fiecare harta poate fi transformata ıntr-un graf planarın modul urmator: fiecare regiune a hartii este reprezentata printr-un varf al grafului iar doua varfurisunt adiacente daca regiunile corespunzatoare au o frontiera comuna. De exemplu, harta din fig. 12.8aeste reprezentata de graful din fig. 12.8b.

1

2

35

4

• • •

1

2

5

4

3

a) b)

Figura 12.8: Relatia de vecinatate dintr-o harta reprezentata printr-un graf

Observatie: Pentru multi ani s-a cunoscut faptul ca cinci culori sunt suficiente pentru colorarea uneiharti, dar nu s-a gasit nici o harta care sa necesite mai mult de patru culori. Dupa mai bine de o sutade ani (problema a fost formulata pentru prima data ın 1852 de catre un student londonez, FrancisGuthrie) s-a putut demonstra (Appel si Haken 1976) ca patru culori sunt suficiente pentru colorarea uneiharti. Demonstratia acestui rezultat include verificarea unei proprietati de reductibilitate a grafurilor cuajutorul calculatorului, fapt care a condus la “discutii aprinse” ın ceea ce priveste corectitudinea. sfobs

12.4.2 Modelul matematic

Convenim sa notam o solutie a problemei printr-un vector (x1, . . . , xn) unde xi reprezinta culoarea varfuluii. De asemenea, presupunem ca G este graf. Astfel, spatiul solutiilor potentiale este 1, . . . , mn si poatefi reprezentat printr-un arbore cu n nivele ın care fiecare nod interior are exact m succesori. De exemplu,graful din fig. 12.9a are spatiul solutiilor potentiale reprezentat de arborele din fig. 12.9b.

Conditia “nu exista muchii cu extremitatile de aceeasi culoare”, prin care se stabileste daca un vector(x1, . . . , xn) ∈ 1, . . . , mn este colorare, se exprima prin:

∀i, j ∈ V : i, j ∈ E ⇒ xi = xj (12.1)

Criteriul de stabilire a unui candidat (de marginire) se obtine restrictionand 12.1 la solutia potentialapartiala (x1 . . . , xk):

∀j : (1 ≤ j ≤ k − 1) ∧ (j, k ∈ E ⇒ xj = xk) (12.2)

Utilizand 12.2 ca functie de taiere, arborele din exemplul de mai sus este transformat ın arborele partialdin fig. 12.10. Orice varf de pe frontiera acestui arbore partial este varf solutie.

Ca algoritm de enumerare utilizam subprogramul de generare a elementelor produsului cartezian.Intrucat, de regula, algoritmul de enumerare este determinat de structura de date aleasa pentru reprezentareasolutiilor, rezulta ca doua sunt elementele ce caracterizeaza un algoritm backtracking: reprezentareasolutiilor si criteriul de marginire.

Page 214: algoritmi_tehnici_dorel lucanu - carte

12.5. PROBLEMA CELOR N REGINE 225

•1 3• •

1 3

• •1 3• •

1 3

1 3

· · ·

· · · · · · · · · · · ·• •

1 3• ••

1 3• ••

2

2

2

2

2

2

2· · · · · ·

b)

••1

2

4

3

a)

Figura 12.9: Colorare grafuri: spatiul solutiilor potentiale

12.4.3 Implementare

Pentru implementare consideram grafurile reprezentate prin matricele de adiacenta.

function C(x, k)begin

candidat← truefor j ← 1 to k-1 do

if ((G.a[j,k]=1) and (x[j]=x[k]))then candidat ← false

return candidatend

12.5 Studiu de caz: Problema celor n regine

12.5.1 Descrierea problemei

Se considera o tabla de sah de dimensiune n × n si n regine. Problema consta ın asezarea pe tabla desah a celor n regine astfel ıncat sa nu se captureze una pe alta. Daca exista mai multe asemenea asezari,atunci se vor determina toate.

Page 215: algoritmi_tehnici_dorel lucanu - carte

226 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

3•

3

1

1 3

2

2 2

3•

1•

•1•

1•

3•

1

3

1•

3•

2 2• •

2 2

Figura 12.10: Colorare grafuri: arbore partial1 2 3 4

1

2

3

4

Figura 12.11: Tabla de sah 4× 4

12.5.2 Modelul matematic

Pozitiile de pe tabla de sah sunt indentificate prin perechi (i, j) cu 1 ≤ i, j ≤ n. De exemplu, pentrun = 4, tabla este cea reprezentata ın fig. 12.11. O solutie poate fi reprezentata printr-o functie Q :1, . . . , n × 1, . . . n → false, true cu semnificatia: Q[i, j] = true daca si numai daca pe pozitia(i, j) se afla o regina. Se observa direct ca spatiul solutiilor potentiale contine 2n2

elemente. O reduceresubstantiala a acestuia se obtine daca se reprezinta solutiile printr-o functie s : 1, . . . , n → 1, . . . , ncu semnificatia: s[i] = j ⇔ Q[i, j] = true. In acest caz, spatiul solutiilor potentiale contine nn elemente.De exemplu, pentru n = 8 avem 2n2

= 264 iar 88 = 224. Asadar alegerea reprezentarii pentru solutiilepotentiale este foarte importanta pentru metoda backtracking: o alegere buna poate conduce la redecereasubstantiala a dimensiunii spatiului acestor solutii. Cele nn elemente ale spatiului solutiilor potentialepot fi reprezentate printr-un arbore cu n nivele ın care fiecare varf are exact n succesori imediati. Pentrucazul n = 4 arborele este cel reprezentat ın fig. 12.12.

In continuare vom cauta criteriul de marginire prin care sa eliminam acei subarbori care nu continvarfuri-solutie. Sa observam ca sk candideaza la solutie daca asezand cea de-a k-a regina pe pozitia(k, sk), ea nu este atacata de si nu ataca nici una din cele k − 1 regine asezate pe liniile 1, . . . , k − 1.Ecuatiile celor patru directii pe care se poate deplasa o regina sunt date de:

regina de pozitia (i, j) se poate deplasa pe pozitia (k, ) daca si numai daca:

• i = k (deplasare pe orizontala), sau• j = (deplasare pe verticala), sau

• i− j = k − (deplasare pe o diagonala principala), sau

• i + j = k + (deplasare pe o diagonala secundara).

Page 216: algoritmi_tehnici_dorel lucanu - carte

12.6. SUBMULTIME DE SUMA DATA 227

• • • •

• • •••

1 2 3 4

3 4 1 2•••

1 2• •3 4

• •3 4

•••1 2

•••1 2

• •3 4

• •3 4

•••1 2

•••1 2

• •3 4

· · ·

· · ·

· · ·

Figura 12.12: 4 regine: reprezentarea spatiului solutiilor potentiale

• • • •

• • •• ••

1 2 3 4

3 4 4 1 1 2

2 1• •

3

•2

•3

4

Figura 12.13: 4 regine: arborele partial

Considerand (i, j) = (i, si) si (k, ) = (k, sk) obtinem conditia care reprezinta criteriul de marginire:

C(s1, . . . , sk) = ∀i(1 ≤ i ≤ k − 1) : ¬Q[i, sk]∧¬(i + si = sk + k ∨ i− si = k − sk))

sau, tinand cont de:

sk + k = i + si ⇒ si = sk + k − i si sk − k = si − i⇒ si = sk − k + i

obtinem forma echivalenta:

C(s1, . . . , sk) = ∀i(1 ≤ i ≤ k − 1) : ¬Q[i, sk] ∧ ¬Q[i, sk + k − i] ∧ ¬Q[i, sk − k + i]

Pentru a ne face o idee cat de mult taie C din arborele spatiului solutiilor potentiale, prezentam arborelepartial obtinut ın urma aplicari criteriului de marginire pentru cazul n = 4 ın fig. 12.13.

O functie s : 1, 2, . . . , n → 1, 2, . . . , n este ın fapt un element din 1, 2, . . . , nn si deci ca algoritmde enumerare poate fi folosita oricare din variantele de generare a elementelor produsului cartezian.

12.6 Studiu de caz: Submultime de suma data

12.6.1 Descrierea problemei

Se considera o multime A cu n elemente, fiecare element a ∈ A avand o dimensiune s(a) ∈ Z+ si unnumar ıntreg pozitiv M . Problema consta ın determinarea tuturor submultimilor A′ ⊆ A cu proprietatea∑

a∈A′ s(a) = M .

Page 217: algoritmi_tehnici_dorel lucanu - carte

228 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

• 1

•1

•1

•0 1

•1

1 •

•0 1

•0 1

•10

••

varf-solutie

varf-solutie

Figura 12.14: Arbore partial pentru submultime de suma data

12.6.2 Modelul matematic

Presupunem A = 1, . . . , n si s(i) = wi, 1 ≤ i ≤ n. Pentru reprezentarea solutiilor avem doua posibilitati.

1. Prin vectori care sa contina elementele care compun solutia. Aceasta reprezentare are dezavantajulca trebuie utilizat un algoritm de enumerare a vectorilor de lungime variabila. De asemenea testareaconditiei a ∈ A\A′? nu mai poate fi realizata ın timpul O(1) daca nu se utilizeaza spatiu de memoriesuplimentar.

2. Prin vectori de lungime n, (x1, . . . , xn) cu xi ∈ 0, 1 avand semnificatia: xi = 1 daca si numaidaca wi apartine solutiei (vectorii caracteristici).

Exemplu: Fie n = 4, (w1, w2, w3, w4) = (4, 7, 11, 14) si M = 25. Exista urmatoarele solutii:

• (4, 7, 14) care mai poate fi reprezentata prin (1, 2, 4) sau (1, 1, 0, 1) si

• (11, 14) care mai poate fi reprezentata prin (3, 4) sau (0, 0, 1, 1).

sfex

Noi vom opta pentru ultima varianta, deoarece vectorii au lungime fixa. Remarcam faptul ca spatiulsolutiilor contine 2n posibilitati (elementele multimii 0, 1n) si poate fi reprezentat printr-un arborebinar. Ca algoritm de enumerare vom utiliza GenProdCart. Asa cum am mai vazut, acesta genereazasolutiile potentiale prin partitionarea multiimi A ın doua: o parte 1, . . . , k care a fost luata ın considerarepentru a stabili candidatii la solutie si a doua parte k + 1, . . . , n ce urmeaza a fi luata ın considerare.Cele doua parti trebuie sa satisfaca urmatoarele doua inegalitati:

• Suma partiala data de prima parte (adica de candidatii alesi) sa nu depaseasca M :

k∑i=1

xi · wi ≤M (12.3)

• Ceea ce ramane sa fie suficient pentru a forma suma M :

k∑i=1

xi · wi +n∑

i=k+1

wi ≥M (12.4)

Cele doua inegalitati pot constitui crieteriul de marginire. Cu acest criteriu de taiere, arborele partialrezultat pentru exemplul anterior este cel reprezentat ın fig. 12.14.

De remarcat ca acest criteriu nu elimina toti subarborii care nu contin varfuri-solutie, dar eliminafoarte multi, restrangıng astfel spatiul de cautare. Atingerea unui varf pe frontiera presupune imediat

Page 218: algoritmi_tehnici_dorel lucanu - carte

12.7. PROBLEMA RUCSACULUI II (CONTINUARE) 229

determinarea unei solutii: suma∑n

i=k+1 wi este zero (deoarece k = n) si dubla inegalitate data de relatiile12.3 si 12.4 implica

∑ni=1 wi = M .

Observatie: Daca se utilizeaza drept criteriu de marginire numai inegalitatea 12.3 atunci atingereaunui varf pe frontiera ın arborele partial nu presupune neaparat si obtinerea unei solutii. Mai trebuieverificat daca suma submultimii alese este exact M . sfobs

12.6.3 Implementare

function C(x, k)begin

s1 ← 0for i ← 1 to k do

s1 ← s1 + w[i]*x[i]s2 ← s1for i ← k+1 to n do

s2 ← s2 + w[i]*x[i]return ((s1 ≤ M) and (s2 ≥ M))

end

12.7 Studiu de caz: Problema rucsacului II (varianta discreta,

continuare)

12.7.1 “Backtracking”

12.7.2 “Branch and bound”

12.7.2.1 Modelul matematic

Convenim sa notam cu (y1, . . . , yn) solutia curenta. Presupunem ca au fost selectate valorile yi, 1 ≤ i ≤ k,si urmeaza sa determinam daca yk poate candida la o solutie optima. Un criteriu de marginire bunobtinem daca dispunem de o margine superioara pentru valoarea celei mai bune solutii ce se poate obtinepentru alegerea facuta pana la momentul considerat. Aceasta margine poate fi obtinuta daca relaxamproblema ın modul urmator:

• functia obiectiv:

maxn∑

i=1

yi · pi

• restrictii:yi ∈ 0, 1, 1 ≤ i ≤ k0 ≤ yi ≤ 1, k + 1 ≤ i ≤ n∑n

i=1 yi · wi ≤M

Reamintim ca valorile pentru yi cu 1 ≤ i ≤ k sunt deja atribuite. Se rezolva problema relaxata utilizandalgoritmul greedy, obtinandu-se o margine superioara fsup (profitul maxim care se poate realiza cu(y1, . . . , yk)). Fie xi ∈ 0, 1, 1 ≤ i ≤ n, o solutie arbitrara. De fapt, vom vedea ca (xi)1≤i≤n vareprezenta cea mai buna solutie determinata pana la momentul curent. Daca

n∑i=1

xi · pi ≥ fsup

atunci, evident, (y1, . . . , yk) nu poate candida la o solutie optima si trebuie facuta o alta alegere pentruprimele k componente. Aceasta noua alegere se face ın maniera urmatoare:

– se determina cel mai mare k′ cu k′ ≤ k si y′k = 1 (k′ este ultimul obiect introdus ın rucsac);

Page 219: algoritmi_tehnici_dorel lucanu - carte

230 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

– se face y′k = 0 (se scoate ultimul obiect introdus) si se testeaza daca (y1, . . . , yk′) poate candida la

o solutie optima.

Acum, ordinea atribuirii de valori pentru yk este urmatoarea: Intai se considera yk egal cu 1 (se ıncearcamai ıntai introducerea obiectului k ın rucsac). Se testeaza daca aceasta alegere poate conduce la o solutiemai buna. Daca da, atunci se determina cea mai buna solutie pentru alegerea facuta pana ın acel momentsi se actualizeaza . Daca aceasta alegere nu poate conduce la o solutie mai buna decat cea ıntalnita panaın acel moment, atunci se atribuie lui yk valoarea zero (obiectul k nu va fi introdus ın rucsac).

Criteriul de marginire se bazeaza pe cunoasterea unei solutii (x1, . . . , xn) care sa reprezinte optimulpeste solutiile potentiale explorate. Valorile initiale pentru xi pot fi alese cu un algoritm greedy: se alegeobiectul ce aduce un profit maxim peste multimea obiectelor nealese. Presupunem p1

w1≥ · · · ≥ pn

wn.

Determinarea solutiei initiale (x1, . . . , xn) coincide cu parcurgerea primelor n varfuri din explorareaDFS a arborelui corespunzator spatiului solutiilor potentiale. Pentru a nu mai calcula ınca o data aceastasolutie, se considera initial (y1, . . . , yn) = (x1, . . . , xn).

12.7.2.2 Implementare

Vom considera un subprogram care determina solutia initiala:

procedure detSolInit(ob, n, M, k, y, pinit, cinit)begin

cinit ← 0pinit ← 0i ← 1while (i ≤ n) do

cinit ← cinit+ob[i].wif (cinit <= M)then ob[i].x← 1

y[i] ← 1pinit ← pinit+ob[i].pi ← i+1

else k ← i-1cinit ← cinit-ob[i].wi ← n+1

end

Procedura care calculeaza problema relaxata are o descriere asemanatoare:

function fSup(ob, n, M, k, ck, pk)begin

ptemp ← pkctemp ← ckfor i ← k+1 to n do

ctemp ← ctemp+ob[i].wif (ctemp < M)then ptemp ← ptemp+ob[i].pelse ptemp ← ptemp+(1-(ctemp-M)/ob[i].w)*ob[i].p

returm ptempreturn ptemp

end

Algoritmul backtracking care rezolva problema rucsacului este descris de urmatorul program:

procedure rucsacIIBack(ob, n, M, copt, popt)begin

detSolInit(ob, n, M, k, y, ptemp, ctemp)popt ← ptempwhile (k > 0) do

Page 220: algoritmi_tehnici_dorel lucanu - carte

12.8. SEND + MORE = MONEY 231

while (fsup(ob, n, k, M, ctemp, ptemp) ≤ popt) dowhile ((k > 0) and (y[k] = 0)) do

k ← k-1if (k > 0)then y[k] ← 0

ctemp ← ctemp-ob[k].wptemp ← ptemp-ob[k].pwhile ((k < n) and (ob[k+1].w+ctemp ≤ M)) do

k ← k+1y[k] ← 1ctemp ← ctemp+ob[k].wptemp ← ptemp+ob[k].p

if (k=n)then popt ← ptemp

copt ← ctempfor i ← 1 to n do

ob[i].x← y[i]else k ← k+1

y[k] ← 0end

Exemplu: Presupunem n = 4 si greutatile si profiturile date de urmatorul tabel:

i 1 2 3 4pi 40 50 55 70wi 30 40 45 60

Spatiul solutiilor potentiale este reprezentat de arborele din fig. 12.15. Pentru varfurile de pe frontierasunt trecute greutatile si profiturile corespunzatoare solutiilor date de solutiile potentiale date de acestevarfuri. Consideram doua cazuri.

1. M = 100. Arborele partial parcurs de algoritmul backtracking este cel din fig. 12.16. Calculelecorespunzatoare varfurilor A, B, C, D, alese la ıntamplare, sunt:

A : fsup = 40 + 55 + 2560 · 70 > popt = 90

B : fsup = 40 + 70 = 110 > popt = 95C : fsup = 50 + 55 + 15

60 · 70 > popt = 110D : fsup = 55 + 55

60 · 70 = 330 + 3856 = 715

6 < popt = 120

2. M = 80. Arborele partial parcurs de algoritmul backtracking este cel din fig. 12.17. Calculelecorespunzatoare varfurilor A, B, C, D sunt:

A : fsup = 40 + 55 + 560 · 70 > popt = 95

B : fsup = 40 + 5060 · 70 = 240 + 350

6 = 5906 > popt = 95

C : fsup = 50 + 4045 · 85 = 450 + 40

4 = 8909 > popt = 95

D : fsup = 55 + 3560 · 70 = 330 + 245

6 = 5757 < popt = 95

sfex

12.8 Studiu de caz: SEND + MORE = MONEY

12.8.1 Descrierea problemei

Se considera expresia: SEND +MORE = MONEY . Sa se scrie un program care sa ınlocuiasca literelecu cifre zecimale astfel ıncat, facand calculele, sa obtinem egalitate.

Page 221: algoritmi_tehnici_dorel lucanu - carte

232 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

•1 0175 115

•1 0130 70

•1 0

•1 0135 75

•1 090 30

•1 0

•1 0

•1 0145 85

•1 0100 40

•1 0

•1 0105 45

•1 060 0

•1 0

•1 0

•01

W :P :215 145 160 90 165 95 110 40 175 105 120 50 125 55 70 0

Figura 12.15: Problema rucsacului: arborele solutiilor potentiale

• 070

•0

• •

•1 0

•1 0

•0

•1 0

•01

W :P : 90 95 110

DCA

B075

190

•0

1100120

Figura 12.16: Problema rucasacului: arborele partial pentru M = 100

12.8.2 Modelul matematic

O ınlocuire a literelor cu cifre poate fi reprezentata de o functie:

f : S, E, N, D, M, O, R, Y → 0, 1, 2, . . . , 9Exista 108 asemenea functii. Acest numar poate fi micsorat daca studiem ecuatiile ce trebuie sa lesatisfaca o ınlocuire (aceste ecuatii sunt date de algoritmul de adunare):

f(D) + f(E) = f(Y ) + t1 × 10 (12.5)f(N) + f(R) + t1 = f(E) + t2 × 10 (12.6)f(E) + f(O) + t2 = f(N) + t3 × 10 (12.7)f(S) + f(M) + t3 = f(O) + t4 × 10 (12.8)

f(M) = t4 (12.9)

unde ti ∈ 0, 1 sunt cifrele de transport. Presupunand ca determinam numai ınlocuirile cu proprietateaf(M) = 0, rezulta f(M) = 1 = t4. Daca f(D) si f(E) sunt cunoscute, atunci f(Y ) si t1 sunt unic

• 070

•0

• 075

•1 0

•1 0

•0

•1 0

•01

W :P : 90 95

DCA

B

Figura 12.17: Problema rucasacului: arborele partial pentru M = 80

Page 222: algoritmi_tehnici_dorel lucanu - carte

12.8. SEND + MORE = MONEY 233

determinate:f(Y ) = (f(D) + f(E)) mod 10t1 = (f(D) + f(E)) div 10

Din ecuatia 12.6 avem:f(N) = f(E)− (f(R) + t1) + t2 × 10

Daca f(E) ≥ f(R) + t1 atunci t2 = 0, pentru ca f(N) ≤ 9. Daca f(E) < f(R) + t1 atunci t2 = 1. Decidaca f(E), f(R), t1 sunt cunoscute atunci f(N) si t2 sunt determinate. Din ecuatia 12.7 avem:

f(O) = f(N)− (f(E) + t2) + t3 × 10

Rationand ca mai sus, obtinem ca daca f(N) ≥ f(E)+ t2 atunci t3 = 0 iar daca f(N) < f(E)+ t2 atuncit3 = 1. Deci f(N), f(E) si t2 determina ın mod unic pe f(O) si t3. Din ecuatia 12.8 rezulta:

f(S) = −f(M)− t3 + f(O) + t4 × 10 = f(O) − t3 + 9

Deoarece f(S) ≤ 9 rezulta f(O)− t3 + 9 ≤ 9 si de aici:

0 ≤ f(O) ≤ t3 ≤ 1

Combinand toate relatiile de mai sus, obtinem ca este eficient sa determinam valorile lui f ın or-dinea: f(D), f(E), f(Y ), f(R), f(N), f(O), f(S). Componentele f(D), f(E) si f(R) pot lua orice valoaredin 0, 1, 2 . . . , 9. Pentru f(D), F (E), f(R) cunoscute, toate celelalte elemente sunt unic determinate.Rezulta ca numarul de ınlocuiri ce urmeaza a fi testate este cel mult 103.

12.8.3 Implementare

Problema s-a simplificat atat de mult ıncat nici nu mai este nevoie de un algoritm de enumerare. Deoarecenumai trei variabile, D, E si R, pot lua toate valorile de la 0 la 9, rezulta enumerarea tuturor solutiilorpotentiale poate fi realizata prin trei instructiuni for incluse una ın alta.

procedure SENDplusMOREegalMONEY()begin

M ← 1nr ← 0for D ← 0 to 9 do

for E ← 0 to 9 dofor R ← 0 to 9 do

Y ← (D+E) mod 10t1 ← (D+E) div 10if (E ≥ R+t1)then t2 ← 0else t2 ← 1N ← E-R-t1+t2*10if (N ≥ E+t2)then t3 ← 0else t3 ← 1O ← N-E-t2+t3*10if ((0 ≤ O) and (O ≤ t3))then nr ← nr+1

S ← O-t3+9scrie(S,E,N,D,’ + ’,M,O,R,E,’ = ’,M,O,N,E,Y)

end

Exercitiul 12.8.1. In enuntul problemei nu se face precizarea daca litere diferite trebuie ınlocuite cucifre diferite, i.e. atribuirile sa fie functii injective. Sa se rezolve problema pentru cazul cand specificatiainclude si aceasta conditie suplimentara.

Page 223: algoritmi_tehnici_dorel lucanu - carte

234 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

A B

C D E

F G H

Figura 12.18: Jocul “Perspico”

2 3

4 5 6

7 8 9

1

Figura 12.19: Jocul “Perspico” – varianta simplificata

12.9 Programarea logica si “backtracking”

Scopul acestei sectiuni este de a face un prim pas ın ıntelegerea modului ın care interpretoarele si compila-toarele de limbaje de programare logica utilizeaza strategia backtracking ın executia unui program logic.Mentionam ca strategia backtracking este ıncorporata ın interpretor/compilator si utilizatorul nu trebuiesa o descrie explicit ın program. Prezentarea este informala si se bazeaza pe studierea unui exemplu astfelıncat sa fie accesibila si cititorilor care nu sunt familiari cu programarea logica. Consideram urmatoareavarianta simplificata a jocului “Perspico”. Fie o retea formata din 3×3 patrate, numite locatii. In ultimele8 locatii se gasesc 8 piese etichetate cu litere de la A la H, de dimensiuni potrivite astfel ıncat sa poatafi deplasate pe orizontala sau verticala atunci cand exista o locatie vecina libera (a se vedea fig. 12.18).Numim aceasta asezare a pieselor configuratie initiala si o notam cu C0. O mutare consta ın deplasareaunei piese ın locatia libera atunci cand este posibil. Problema este urmatoarea: data o configuratie finalaCf , sa se decida daca exista o lista de mutari care sa permita obtinerea lui Cf din C0.

Un program logic consta din descrierea problemei prin formule logice de o forma particulara, numiteclauze. Simplificam problema si presupunem ca cele 8 piese sunt identice (s-au sters literele scrise peele). O configuratie pentru noua problema este unic determinata de pozitia locatiei libere. Locatiile leidentificam prin numere de la 1 la 9 ca ın fig. 12.19. Acum, problema poate fi descrisa cu ajutorul a douapredicate:

• ad(x,y) – care este adevarat daca din pozitia x se poate ajunge ın pozitia y, si

• cnf(x,L) – care este adevarat daca din configuratia initiala (cu locatia libera pe pozitia 1) se poateajunge ın configuratia cu locatia x libera aplicand mutarile din lista L.

Page 224: algoritmi_tehnici_dorel lucanu - carte

12.9. PROGRAMAREA LOGICA SI “BACKTRACKING” 235

“Baza de cunostinte” corespunzatoare problemei noastre este urmatoarea:

(C1) ad(1, 2)← true (C7) ad(1, 4)← true(C2) ad(2, 3)← true (C8) ad(4, 7)← true(C3) ad(4, 5)← true (C9) ad(2, 5)← true(C4) ad(5, 6)← true (C10) ad(5, 8)← true(C5) ad(7, 8)← true (C11) ad(3, 6)← true(C6) ad(8, 9)← true (C12) ad(6, 9)← true(C13) ad(y, x)← ad(x, y)(C14) cnf(x, y.L)← ad(x, y) ∧ cnf(y, L)(C15) cnf(1, nil)← true

Clauzele C1-6 descriu pozitiile adiacente, C13 spune ca relatia de adiacenta (vecinatate) este simetrica,iar C14 spune ca daca se obtine configuratia cu locatia y libera aplicand regulile din lista L si locatia xeste adiacenta cu y atunci configuratia cu x libera se obtine prin mutatarea piesei din x ın y. O intrarepentru programul logic (un scop) este de forma cnf(a, L) cu a ∈ 1, . . . , 9 (din punct de vedere alprogramarii logice trebuie scris true ← cnf(a, L)). Un interpretor/compilator de limbaj de programarelogica va aplica urmatoarele reguli de deductie, obtinute ca instante ale rezolutiei peste intrari si clauzeleC1-14 prin unificare:1

(D1) A ∪ ad(x, 2)A[1/x] (D7) A ∪ ad(x, 4)

A[1/x]

(D2) A ∪ ad(x, 3)A[2/x] (D8) A ∪ ad(x, 7)

A[4/x]

(D3) A ∪ ad(x, 5)A[4/x] (D9) A ∪ ad(x, 5)

A[2/x]

(D4) A ∪ ad(x, 6)A[5/x] (D10) A ∪ ad(x, 8)

A[5/x]

(D5) A ∪ ad(x, 8)A[7/x] (D11) A ∪ ad(x, 6)

A[3/x]

(D6) A ∪ ad(x, 9)A[8/x] (D12) A ∪ ad(x, 9)

A[6/x]

(D13) A ∪ ad(x, y)A ∪ ad(y, x)

(D14.1) A ∪ cnf(1, L)A[nil/L] (D14.4) A ∪ cnf(4, L)

A ∪ ad(4, y), cnf(y, L′)(D14.2) A ∪ cnf(2, L)

A ∪ ad(2, y), cnf(y, L′) (D14.5) A ∪ cnf(5, L)A ∪ ad(5, y), cnf(y, L′)

(D14.3) A ∪ cnf(3, L)A ∪ ad(3, y), cnf(y, L′) (D14.6) A ∪ cnf(6, L)

A ∪ ad(6, y), cnf(y, L′)unde prin A[a/x] am notat multimea clauzelor din A ın care s-a ınlocuit x cu a, iar ın regulile D14.2-6 avemL = y.L′. Pentru simplitatea prezentarii sunt date numai o parte din regulile de deductie. De exemplu,putem considera la fel de bine simetricele regulilor D1-12 si D.14.2-6. Interpretorul/compilatorul de limbajlogic nu va genera simultan toate aceste reguli din care apoi sa aleaga una; el le va genera succesiv pemasura ce va explora “noi cai de rationament” pentru a obtine multimea vida de clauze (care semnificaun calcul cu succes). Prin determinarea tuturor regulilor ce se pot aplica la un moment dat putemconstrui arborele solutiilor potentiale. Un drum ın acest arbore corespunde unei aplicari a unei secventede reguli. Functia de marginire (ıncorporata ın interpretor/compilator) va taia acei subarbori care nuau pe frontiera clauza vida sau care corespund unor rationamente circulare ce conduc la calcule infinite.Performantele unui program logic depind direct de aceasta functie. Programatorul (utilizatorul limbajuluilogic) poate influienta aplicarea functiei de marginire prin modul si ordinea ın care scrie clauzele si prinprecizarea explicita a unor “puncte” de taiere ın arborele solutiilor potentiale. De aceea consideram cafiind esentiala ıntelegerea strategiei backtracking ın scrierea de programe logice corecte si eficiente.

O executie cu succes a programului logic pentru o intrare cnf(a, L) va fi o derivare

cnf(a, L) = A0 A1 · · · ∅1Cititorul nu trebuie sa fie panicat daca nu stie ınca ce ınseamna rezolutie sau unificare. Se poate considera pur si simplu

ca regulile de deductie D1-14.6 sunt date si trebuie gasita o strategie de aplicare a acestor reguli pentru ca, plecand de la ointrare cnf(a, L), sa se obtina clauza vida.

Page 225: algoritmi_tehnici_dorel lucanu - carte

236 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

cnf(5, L)

ad(5, y), cnf(y, L′)

ad(y, 5), cnf(y, L′)

cnf(4, L′)

ad(4, y), cnf(y, L′′)

ad(y, 4), cnf(y, L′′)

cnf(1, L′′)

D14.5

D13

D3

D14.4

D13

D7

D14.1

cnf(2, L′)

ad(2, y), cnf(y, L′′)

ad(y, 2), cnf(y, L′′)

cnf(1, L′′)

D9

D14.2

D13

D1

D14.1

Figura 12.20: Subarborele solutiilor

obtinuta prin aplicarea regulilor de deductie de mai sus. Obtinerea multimii vide de clauze are semnificatiaca ¬cnf(a, L), cu lista L calculata din secventa regulilor de deuctie aplicate, este falsa, i.e. cnf(a, L) =true. O astfel de derivare se obtine prin explorarea sistematica a arborelui ce corespunde tuturorposibilitatilor de aplicare a regulilor de deductie. In fig. 12.20 este reprezentat subarborele core-spunzator tuturor executiilor cu succes pentru intrarea cnf(5, L). Pentru ramura din stanga avemL = y.L′ = 4.L′ = 4.y.L′′ = 4.1.L′′ = 4.1.nil, iar pentru cea din dreapta avem L = y.L′ = 2.L′ =2.y.L′′ = 2.1.L′′ = 2.1.nil. Alte executii pot fi obtinute daca se considera si celelalte instante ale rezolutieipeste clauze si intrarile respective. De exemplu, din ad(5, y), cnf(y, L′) se poate obtine cnf(6, L′) saucnf(8, L′). Interpretorul/compilatorul limbajului de programare logica va gasi unul dintre aceste dru-muri si anume primul parcurs prin explorarea DFS. Notam faptul ca nu ıntotdeauna arborele tuturordeductiilor este finit si de multe ori programul logic trebuie sa contina specificari explicite a locurilorunde interpreterul(compilatorul) va face taieri ın arborele deductiilor. Un exemplu de arbore infinit seobtine aplicand regula D13 de o infinitate de ori.

12.10 Referinte bibliografice

Prezentarea de aici se bazeaza pe [HS84, LG86]. In [Luc93] este descris un algoritm backtracking pentrurezolvarea ecuatiilor diofantice liniare.

12.11 Exercitii

Exercitiul 12.1. Sa se proiecteze un algoritm backtracking pentru problema din exercitiul 9.3 (Schim-barea banilor).

Page 226: algoritmi_tehnici_dorel lucanu - carte

12.11. EXERCITII 237

Exercitiul 12.2. (Problema labirintului) Se considera un tablou bidimensional cu elemente 0 si 1 reprezentındun labirint: 1 blocheaza calea iar 0 semnifica o pozitie deschisa. Sa se scrie un algoritm backtracking careıncearca sa traseze un drum de la pozitia (1, 1) la pozitia (n, n).

Exercitiul 12.3. [HS84] (Marcile postale) Se considera n denumiri de marci postale si se presupune canu se permit mai mult de m marci postale pe o scrisoare. Sa se scrie un algoritm backtracking caredetermina cel mai mare domeniu (multime de numere consecutive) de valori postale ce pot fi puse pe oscrisoare si toate combinatiile posibile de denumiri care realizeaza domeniul.

Exercitiul 12.4. [HS84] (Conectarea tranzistorilor) Se considera:

– n componente electrice (tranzistori) ce urmeaza a fi plasati pe o placa de circuite pe care suntmarcate n poztii;

– o matrice de conectare CON cu CON [i, j] reprezentand numarul de conectari ce trebuie facuteıntre componentele i si j;

– o matrice de distante DIST cu DIST [r, s] reprezentand distanta de la pozitia r la pozitia s a placiide circuite;

– costul unei conectari este∑

i,j CON [i, j] ·DIST [i, j].

Sa se scrie un algoritm backtracking care determina o plasare a componentelor pe pozitiile placii astfelıncat costul de conectare sa fie minim.

Exercitiul 12.5. [HS84] (Procesare paralela) Exista n programe ce urmeaza a fi executate de k pro-cesoare care lucreaza ın paralel. Timpul necesar executarii programului i este ti. Scrieti un algoritmbacktracking care sa determine ce programe sa fie executate de fiecare procesor si ın ce ordine astfel ıncattimpul dupa ce se termina ultimul program sa fie minim.

Exercitiul 12.6. (Mutarea calului) Se considera o tabla de sah n × n pe care se plaseaza arbitrar uncal pe pozitia (x, y). Sa se determine n2 − 1 mutari ale calului astfel ıncat fiecare pozitie a tablei sa fievizitata de catre acesta exact o data. Exista asemenea secvente de mutari pentru orice n?.

Exercitiul 12.7. [MS91] (Mozaic) O placuta de mozaic are forma patrata de dimensiune 1 si estedivizata ın patru parti colorate diferit. Fiecare parte colorata este unic determinata de o latura si centrulpatratului.

cul.1

cul.2

cul.3

cul.4

Exista m tipuri de placute, i.e. m aranjamente coloristice diferite. De fiecare tip exista ti placuteastfel ıncıt

∑mi=1 ti = n2. Sa se scrie un algoritm backtrack care sa determine o amplasare a placutelor

ıntr-un patrat de latura n astfel ıncat ori de cate ori doua placute au o latura comuna sa existe aceeasiculoare de o parte si de alta a laturii comune. Sa se considere si cazul cand pe o placuta pot sa fie maiputin de patru culori distincte.

Exercitiul 12.8. [MS91] (Galeriile de arta) Sa se scrie un algoritm backtracking care, pentru un poligonsimplu ın plan dat, determina numarul minim de varfuri astfel ıncat reuniunea campurilor interne devizibilitate acopera tot interiorul poligonului.

Page 227: algoritmi_tehnici_dorel lucanu - carte

238 CAPITOLUL 12. “BACKTRACKING” SI “BRANCH AND BOUND”

Exercitiul 12.9. [MS91] (Fortareata) Sa se scrie un un algoritm backtracking care, pentru un poligonsimplu ın plan dat, determina numarul minim de varfuri astfel ıncat reuniunea campurilor externe devizibilitate acopera tot exteriorul poligonului.

Exercitiul 12.10. [MS91] (Curtea ınchisorii) Sa se scrie un algoritm backtracking care, pentru unpoligon simplu ın plan dat, determina numarul minim de vırfuri astfel ıncıt reuniunea cımpurilor in-terne si externe de vizibilitate acopera tot planul.

Exercitiul 12.11. Sa se arate ca orice numar natural n > 2 se poate scrie ca o suma de numere prime.Sa se scrie un program care pentru un numar natural n > 2 dat, determina o secventa de lungime minimade numere prime a caror suma este egala cu n.