Vous êtes sur la page 1sur 57

Algoritmi definiii fundamentale (I)

Definiia conceptului de algoritm

O procedura de calcul bine definit, care primete ca i intrare un set


de valori i produce la ieire un set de valori

Exemplu: definirea problemei de sortare a unui ir de numere:

a1 , a2 , , a n

Input: o secven de n numere

Output: o permutare (sau o reordonare)


de numere furnizat la intrare, astfel nct

a '1 , a ' 2 , , a' n

a secvenei

a ' 1 a' 2 a ' n

Un algoritm de sortare, pentru o anumit secven de numere input


31, 41, 59, 26 va produce ca i output secvena 26, 31, 41, 59.

O instant a problemei o constituie o secven de intrare care


satisface condiiile problemei

Algoritmi definiii fundamentale (II)

Un algoritm se spune c este corect dac pentru orice secven de


intrare care satisface condiiile problemei va produce la ieire un
rezultat (output) corect

Spunem c algoritmul respectiv rezolv problema computaional


furnizat.

O structur de date reprezint un mod de a organiza i stoca datele


astfel nct s facilitm accesul la ele i modificarea acestora

Tehnici care vor fi acoperite n acest curs:

Tehnici de proiectare a algoritmilor

Tehnici de analiz a algoritmilor astfel nct s putem decide


asupra

corectitudinii algoritmilor i

eficienei acestora

Pseudocod

Modalitate de a descrie algoritmi

Similar cu schemele logice

Un algoritm descris in pseudocod poate apoi sa fie implementat in orice


limbaj de programare (C, Pascal etc).

Convenii de notare
Indentarea descrie o structura de tip bloc
If-then-else, precum si structurile repetitive while, for, repeat-until au
semnificaie similar cu cea din C
// este utilizat pentru comentarii
Variabilele sunt locale fiecarei proceduri
Transmiterea parametrilor in proceduri se realizeaz intotdeauna prin
valoare
Operatorii logici and si or se evalueaz prin scurt-circuitare

Necesitatea studierii algoritmilor

Dac calculatoarele ar avea o vitez de execuie infinit, atunci orice metod


corect de rezolvare a unei probleme ar fi potrivit

Calculatoarele au viteze de execuie limitate

Spaiile de memorare ale calculatoarelor sunt ieftine dar nu gratuite

=> Nu orice algoritm corect funcioneaz n mod utilizabil pe orice resurse de calcul

Eficiena unui algoritm:


se refer la resursele de calcul i memorie necesare pentru execuia
algoritmului
Poate fi mult mai important dect capabilitile hardware i software
ale calculatorului care ruleaz algoritmul

Necesitatea studierii algoritmilor (II)


Analiza unui algoritm

Inseamn s identificm resursele necesare execuiei algoritmului


Memorie, latime de band pentru comunicaii, hardware necesar etc.

Utilizarea unui model generic de calculator


Un singur procesor
Model random-access machine pentru procesor: instructiunile se
execut secvenial (una dup alta), i nu exist posibilitate de
concuren
Se presupune c instruciunile permise pe procesor se execut toate
intr-un timp constant

Complexitatea algoritmilor
divide-and-conquer

Presupunem c procesorul poate lucra cu date de tip intreg sau flotant,


fr ca precizia s fie de larg interes (in demersul nostru de analiz a
algoritmului)

Complexitatea algoritmilor

Problema de dimensiune

1/ b

se imparte in

subprobleme de dimensiune

din problema original

D(n)

C( n) timpul de execuie necesar pentru pasul combine

timpul de execuie necesar pentru pasul divide

Pentru a calcula T(n) se rezolv recurena de mai jos:

T ( n) =

{ ()
aT

( 1 ) , dac n c

n
+ D ( n )+ C ( n ) ,caz contrar
b

Complexitatea sortarii prin interclasare

D ( n )=1

Pasul divide:

Pasul combine: procedura Merge:

Pasul conquer: problema se imparte in 2 subprobleme de mrime


acestea contribuie cu

Cluj-Napoca - 11 Aprilie 2016

n
2T ( )
2

Trebuie rezolvat recurena:

T ( n) =

(1)
dac n=1
n
2T
+(n) dac n>1
2

()

Rezult:

T ( n ) =(n log 2 n)
Heap

C ( n ) =(n)

n/2 , deci

Un heap este un sir de obiecte care pot fi vzute ca i un arbore binar


aproape complet ultimul rand al arborelui se completeaz de la
stnga la dreapta.

Un sir A care reprezint un heap are 2 atribute:

A.length: Lungimea heapului ne furnizeaz numrul de


elemente din sir

A.heap-size: ne spune cte elemente din heap sunt stocate in


sirul A

Pentru un nod i avem:

PARENT(i) = i/2

LEFT(i) = 2i

RIGHT(i) = 2i+1

- imparire intreag

Max-heap:

A [ PARENT ( i ) ] A [ i ]

Min-heap:

A [ PARENT ( i ) ] A [ i ]

Inlimea unui nod: cel mai mare numr de laturi de la nod la o frunz
descend din acel nod

Pentru un heap cu n elemente, nlimea sa este


demonstraie

Meninerea proprietii de heap

(log 2 n) rog

Se presupune c:
LEFT(i) i RIGHT(i) sunt Max-heap
A[i] este mai mic dect copii lui

Max-Heapify coboar A[i] in heap pentru meninerea structurii de heap

Construirea unui heap

Se poate porni de jos n sus (de la frunze) care sunt heap de heapsize=1
pentru a construi heapul

Loop invariant: la nceputul fiecrei iteraii a buclei for, fiecare din nodurile
i+1, i+2, ..., n sunt rdcinile unui heap

Fiecare Max-heapify ruleaz n

Se execut

O(n)

n
log 2
O

apeluri ale lui Max-heapify

=> T ( n ) O(n log 2 n)

- aceast mrginire superioar nu este asimptotic

Se poate deriva mrginirea asimptotic

T ( n ) =O(n)

Heapsort

O(n)

Fiecare apel Build-max-heap se execut n

Pentru fiecare dintre cele n-1 apeluri din bucla for avem timpul de executie
pentru Max-heapify

O(log 2 n)

=> T ( n ) =O(n log 2 n)


Quicksort

Abordare de tip divide-and-conquer

Divide: se partitioneaz irul A[p...r] in 2 subsiruri A[pq-1] si A[q+1r] astfel


incat fiecare element din subsirul A[p..q-1] este mai mic sau egal cu A[q] si care la
randul su este mai mic sau egal dect fiecare element din subirul A[q+1..r]
Conquer: se sorteaz subirurile A[p..q-1] i A[q+1..r] prin apeluri recursive la
funcia quicksort
Combine: sirul A[p,r] este deja sortat, deci combine nu are obiect

Performanta quicksort
Cazul celmaidefavorabil

Atunci cnd partiionarea produce o suproblem cu n-1 elemente i una cu 0

Situaia de mai sus se ntmpl la fiecare apel recursiv

=> partiionarea se execut n

( n)

T ( n ) =T ( n1 )+ T ( 0 ) + ( n )=T ( n1 ) + ( n )=(n2)

Cazul cel mai favorabil

Atunci cand partiionarea produce 2 subsiruri amandou nu mai lungi de n/2

T ( n ) =2T

( n2 )+ ( n) =(n log n)
2

Cazul mediu

Daca presupunem c in fiecare pas are loc o impartire in 2 subsiruri de


lungimi 1/10 si 9/10, atunci

n
n log 10
9n
n
T ( n ) =T
+T
+ cn=O
10
10

( ) ( )

=>performanta quicksort:

O ( n log 2 n )

Randomized quicksort

Programarea dinamic

Divide-and-conquer: se imparte problema in subprobleme disjuncte care apoi


sunt rezolvate recursiv

Programare dinamic: se imparte problema in subprobleme care au pri


comune:
Subproblemele partajeaz cel putin o sub-subproblem comun

PD rezolv fiecare sub-subproblem o singur dat si salveaz rezultatul intro tabel cu rezultate
Se evit astfel ca o sub-subproblem s fie rezolvat de mai multe ori

PD se aplic la probleme de optimizare:


Au mai multe solutii posibile, fiecare caracterizate printr-o valoare

Dorim s identificam o solutie cu valoarea cea mai mica / cea mai mare
Programare dinamic pai
1. Se caracterizeaz structura unui soluii optime
2. In mod recursiv, se definete valoarea unui soluii optime

3. Se calculeaz valoarea unei soluii optime pornindu-se de jos n sus


4. Se calculeaz soluia optim pe baza informaiei obtinute pn n acest pas
Problem tierii unei bare de oel (rod cutting)
Compania Sterling Enterprises cumpr bare de oel lungi si le taie in buci mai
scurte pe care apoi le revinde. Se cunoate preul

pi

cu care compania vinde o

bar de lungime i (lungime intreag). Se cere determinarea locului unde se vor face
taieturile la o bar de lungime n, astfel nct s se obin ctigul maxim

Input: n lungimea iniial a barei, preturile

Output: Se cere partiia

r n= pi + pi ++ pi
1

i1 , i2 , , ik

cu

pi

pentru

rn .

i=1=,n

i 1+i 2 ++i k =n astfel nct suma

este maxim

Numrul maxim de partiii posibil:

2n1

Rezolvare recursiv

Problem cu structur optim: solutia optim a problemei incorporeaz soluii


optime ale subproblemelor

Descompunerea recursiv a problemei tierii barei:


Se taie o pies de lungime i
Bara rmas de lungime n-i trebuie tiat n mod recursiv

r n=max ( pi +r ni )

1 i n

CUT-ROD(p,n)
1. if

n= 0

2.

Return 0

3.

q=

4. for

i=1

5.

q=max ( q , p [ i ] +CUT ROD ( p , ni ))

to n

6. Return q
Analiza CUT-ROD

CUT-ROD(p,n) apeleaz recursiv CUT-ROD(p,n-i) pentru toti i=1..n

Acelasi apel CUT-ROD(p,j) se face de mai multe ori => program ineficient

Timpul de executie T ( n ) =1+ T ( j)=2

Complexitate exponential n n

n1

j =0

Programare dinamic solutie eficient

Incercm s producem un algoritm astfel incat fiecare subproblem s fie


rezolvat o singur dat

Se utilizeaz o zon de memorie suplimentar unde s se salveze rezultatele


fiecrei subprobleme

Timpul de executie exponenial se poate reduce la timp de executie


polinomial dac numrul de subprobleme este polinomial i rezolvarea unei
subprobleme este polinomial

2 abordri:

Abordare top-down cu memo-izare: se scrie procedura recursiv in mod


obisnuit, dar o modificm astfel incat s salvm rezultatul fiecrei
subprobleme intr-un sir. Inainte s se apeleze recursivitatea, se verific daca
rezultatul dorit este deja salvat in sir

Abordare bottom-up: sortm subproblemele in functie de ordinul lor de


mrime i le rezolvm cele mai mici la inceput

Abordarea top-down
MEMOIZED-CUT-ROD
1. Fie un sir auxiliarr[0..n]
2. for i=0 to n

r [ i ] =

3.

4. return MEMOIZED-CUT-ROD-AUX(p,n,r)
MEMOIZED-CUT-ROD-AUX(p,n,r)
1. if

r [ n] 0

2.

return r[n]

3. if n==0
4.

q=0

q=

5. else
6.

for i=1 to n

7.

q=max(q, p[i]+MEMOIZED-CUT-ROD-AUX(p,n-i,r))

8. r[n]=q
9. return q
Abordarea bottom-up
BOTTOM-UP-CUT-ROD(p,n)
1. fie r[0..n] un sir de numere
2. r[0]=0
3. For j=1 to n
4.
5.
6.
7.

q=
For i = 1 to j
q=max(q, p[i]+r[j-i])
r[j] = q

8. Return r[n]
Ambeleabordri au timp de executie

(n2 )

Programarea dinamic

Pentru a intelege programarea dinamic trebuie s intelegem cum


subproblemele ajut la rezolvarea problemei mari

=> se construieste graful subproblemelor

Graful subproblemelor poate fi considerat o versiune restrans a arborelui de


recursivitate

Mrimea grafului subproblemei ne arat timpul de rulare a algoritmului de


programare dinamic => proporional cu numrul de arcuri care ies dintr-un
nod al acestui graf

Reconstruirea solutiei

Extindem abordarea anterioar prin memorarea in fiecare pas nu doar a


valorii solutiei optime ci si a alegerii fcute pt a se ajunge la solutia optim

EXTENDED-BOTTOM-UP-CUT-ROD(p, n)
1. Fie r[0..n] i s[0..n] douasiruri
2. r[0]=0
3. For j = 1 to n

q=

4.
5.

For i = 1 to j

6.

If q < p[i]+r[j-i]

7.

q = p[i]+r[j-i]

8.

s[j] = i

9.

r[j] = q

10. return r si s
Multiplicarea unui sir de matrici

1:

INMULTIRE-MATRICE(A,B)
If coloane[A]!=linii[B]

2:
3:
4:

scrie dimensiuni incompatibile


else
for i=1 to linii[A]

5:

for j=1 to coloane[B]

6:

C[i,j]=0

7:

for k=1 to coloane[A]

8:

C[i,j]=C[i,j]+A[i,k]*B[k,j]

9:

returneaza C

Multiplicarea unui sir de matrici

A1

A2

de dimensiune 10 x 100,

de dimensiune 100 x 5,

A3

de

dimensiune 5 x 50

A
( 1 A 2) A 3

A 1 ( A2 A 3 ) se execut prin 50000 + 25000 inmuliri = 75000

se execut prin 5000 + 2500 inmultiri = 7500

=>conteaz ordinea in care se consider parantezele

Problem:

Se d un sir de matrici care trebuie nmultite

pi1 x

de dimensiune

( A1 , A 2 , , An ) , matricea

Ai

pi

Sa se pun parantezele in mod corect, astfel nct numrul de inmuliri


scalare s fie minim

Numrul de solutii posibile

P(n) numrul de posibile soluii pentru un sir de n matrici

P ( n )=

dac n=1

P ( k ) P (nk )

dac n 2

n1
k=1

Pentru P(n) avem

Pentru a calcula

(2n )
A i A i+1 A j =A i .. j

punem o parantez intre


Costul lui

A i .. j

A k +1 deci

este egal cu costul lui

Dac costurile lui

A i .. j

Ak

trebuie s gasim k optim astfel ncat s

este optim

A i .. k

A k +1.. j

A i .. k

plus costul lui

A k +1.. j

sunt optime, atunci i costul lui

Notm cu m[i,j] numrul optim de inmuliri pentru a calcula

m [ i , j ]=

A i .. j , atunci

0
dac i= j
min {m [ i, k ] +m [ k +1, j ] + pi 1 pk p j } dac i j

ik j

Exercitiu: scrieti algoritmul recursiv care rezolv problema dat

Determinarea subproblemelor

Avem cte o subproblem pentru orice i i j astfel nct

In total avem

Abordare bottom-up. Rezolvarea fiecrei subprobleme

(n2)+n= ( n )
2

subprobleme

un tabel de dimensiuni n x n cu liniile i i coloanele j


Algoritmul bottom-up

1 i j n

A i .. j

o pstrm intr-

Construirea solutiei optime


PRINT-OPTIMAL-PARENS(s, i, j)
1. If i == j
2.

Print

3. Else

Ai
print (

4.

PRINT-OPTIMAL-PARENS(s, i, s[i, j])

5.

PRINT-OPTIMAL-PARENS(s, s[i, j] + 1, j)

6.

Print )

Cand aplicm programarea dinamic?

Cand o problem prezint o sub-structur optimal, este un candidat pentru


programarea dinamic

Se construieste solutia optim a problemei prin combinarea unor solutii


optimale la subprobleme
Descoperirea sub-structurii optimale:

1. Artm c solutia problemei se obtine printr-o alegere, care implic


rezolvarea a unei sau mai multe subprobleme
2. La o problem, presupunem c ni se furnizeaz alegerea care s conduc la
solutia optimal
3. Avand aceast alegere, determinm care sunt subproblemele, si cum
caracterizam cel mai bine spatiul rezultat al subproblemelor
4. Artm c solutiile la subproblemele utilizate in cadrul solutiei optimale sunt
ele la randul lor optimale, prin repetarea rationamentului de mai sus
Identificm urmtoarele
1. Cate subprobleme utilizeaz solutia optimal a problemei
2. Cate posibiliti de alegere avem pentru a determina subproblemele utilizate
de solutia optimal
Greedy

Greedy intotdeauna face alegerea care pare cea mai bun n fiecare moment,
in sperana c aceast alegere va conduce la soluia optim

Greedy nu conduce induce la alegerea optimal

Pentru o problem de optimizare, in primul rnd trebuie s cautm soluia


prin prograre dinamic si abia apoi soluia greedy
Problema seleciei activitilor

Se pune problema planificrii unor activiti care necesit utilizarea unei


resurse comune

Input: o mulime

S={a1 , a2 , , a n }

de activiti care necesit o resurs ce

poate fi utilizat doar de o activitate la un moment dat

Fiecare activitate
terminare

f i , cu

Dou activiti

ai

ai

si

are un moment de start

0 s i< f i < . O activitate


i

aj

ai

i un moment de
are loc n intervalul

sunt compatibile dac intervalele lor nu se

suprapun

Output: dorim s selectm subsetul maximal de activiti compatibile


Exemplu

f 1 f 2 f n1 f n

Considerm activitile ordonate astfel nct

Subsetul maximal de activiti compatibile este

{a 2 , a 4 , a9 , a11 }

Structura optimal

Fie

S ij

multimea activitilor care ncep dup finalizarea activitii

ncep nainte de nceputul activitii

Incluzand

ak

subprobleme

S ij

este

A ij

S kj

S ij

, am mprit problema

S ij

Dac

A ik = Aij S ik

n 2

crora trebuie s le gsim subsetul maximal de

activiti

i acesta

ak .

n soluia pentru

S ik

aj

Presupunem c subsetul maximal de activiti din


include o activitate

ai

A kj =A ij S kj , atunci

A ij = Aik {ak } A kj

Structura optimal: soluia optimal pentru

S ik

pentru

S ij

include soluiile optimale

S kj

=> problema se poate rezolva utiliznd programare dinamic

Dac

c [i , j ]

este mrimea unei soluii optimale pt

S ij , atunci

c [ i , j ] =c [ i , k ] +c [ k , j ] +1
Pentru

c [i , j ]=

S ij , trebuie s determinm aceea activitate

dac S ij=

max { c [ i , k ] +c [ k , j ] +1 }

dac S ij

ak Sij

ak

pt care are loc:

Alegerea greedy

Se pune problema dac putem face o asemenea alegere pe care s o


adugm la soluie fr s rezolvm subproblemele?

Intuitiv, alegerea greedy este accea activitate care las resursele disponibile
pentru ct de multe activiti posibile, deci s alegem activitatea cu cel mai
devreme moment de terminare

Fcnd o alegere greedy, ne rmne doar o subproblem de rezolvat

Alegerea greedy:
compatibile cu

a1 , apoi rmne s determinm doar activitile

a1

Condiia structurii optimale ne spune c dac alegerea greedy este optimal,


atunci si rezultatul optim al problemei se compune din alegerea greedy si
rezultatul optimal al subproblemei rmase

Notm

S k = { ai S , astfel nct s i f k }

Teorem: dac avem subproblema

Sk

si fie activitatea

am

care se

termin cel mai rapid, atunci aceasta face parte din solutia optim a problemei

Sk

Solutia greedy

Alegem activitatea care se termin prima

Alegem activitile compatibile cu aceasta si repetm, pn cand nu mai


rmn alte activiti

Algoritmii greedy sunt top-down: facem o alegere, o adugm la soluie, apoi


rezolvm o subproblem similar

Se consider activitatea fictiv

Procedura trebuie apelat ca i RECURSIVE-ACTIVITY-SELECTOR(s,f,0,n)

Timp de execuie :

a0

cu

f 0=0

(n)

Solutia iterativ

Solutia anterioar este recursiv cu recursivitatea la capt

Strategii greedy
Determinm structura optimal a problemei
2. Dezvoltm o soluie recursiv pe baza soluiei optimale

3. Artm c dac se efectueaz o alegere greedy, rmne doar o


subproblem
4. Artm c alegerea greedy este sigur
5. Dezvoltm un algoritm recursiv pentru rezolvarea problemei greedy
6. Convertim algoritmul recursiv intr-unul iterativ
Proprietatea alegerii greedy: alegem alternativa care apare ca si cea mai
promittoare la problema curent, fr a rezolva subproblemele
Backtracking

Brute force search: se caut in setul tuturor solutiilor posibile

Backtracking: reprezint o reformulare a cutrii de tip brute force


1. Presupunem c o solutie este format din vectorul

backtracking vom traversa n adncime domeniile vectorilor

S= { v 1 , v 2 , , v m } . Prin
vi

pn cnd

identificm o solutie
2. Pornim de la solutia vid
3. La pasul pasul
elemente posibile pentru

S=

introducem n soluie o un element din spaiul

Si

de

vi

4. Dac un vector construit partial

{ v1 , v 2 , , v i }

nu poate conduce la o

soluie, atunci revenim i realizm urmtoarea alegere posibil pentru


5. Dac toate elementele din

Si

v i Si

s-au epuizat, atunci se revine la

S i1

Esentiale sunt conditiile de continuare care ne spun dac un vector parial

{ v1 , v 2 , , v i }

poate conduce la o solutie

Backtracking algoritm
. k = 1, si

S=

2. While k>0
3.

If k>n

4.

Print S // afiseaz soluia s

5.

k = k -1

6.

Else

7.

v Sk

If exist

neconsiderat pn in acest moment

S={v 1 , , v k1 , v }

8.
9.

If

(S)

10.

adevrate // testarea conditiilor de continuare

k = k +1

11.

else k = k-1 // pasul de backtracking

Algoritmul afiseaz toate soluiile posibile, prin backtracking


Problema celor 8 dame

Pe o tabl de sah de dimensiune nxn, s se aseze n dame astfel nct oricare


2 din ele s nu se atace. Dou dame se atac una pe cealalt dac sunt
asezate pe aceai linie, pe aceai coloan sau aceai diagonal

Fie

x i linia pe care va fi asezat dama pe de coloana i. Atunci, pentru o

soluie partial

xi x j

S k = { x1 , , x k } , condiiile de continuare includ:


pentru toti

1 i j k

xi x ji j , pentru toti

Problema celor 8 dame


DAME(n)
1. k=1,

S= { x 1 , x 2 , xn } ={0, , 0 }

2. While k>0
3.

If k > n afiseaz solutia S

4.
5.
6.
7.
8.

k = k-1

x i=x i+1

Else
If

xi n
If

(S)
K = k +1

1 i j k

9.

Else

10.

x k =0

// se face backtracking daca s-a epuizat xi

k = k-1

Tipuri de date
(I) un mod de interpretare a unei valori reprezentate n memoria
calculatorului

Ex:

Valoarea din memorie 01000110 01010010 01000101 01000100

Interpretri:
1179796804 - int reprezentat binar
13457.31640625
FRED

- float

- ir de caractere

(II) o mulime de valori (admise de tipul respectiv)


(III) o modalitate de verificare a validitii unei operaii => type-checking
(IV) o mulime specific de operaii care pot fi efectuate pe un tip
Tipuri abstracte de date - ADT (I)

Un tip de date necesar unui analist, dar care e posibil s nu existe n limbajul
de programare => necesitatea implementrii

Ex. tipul abstrat Boolean: [true, false]


n Basic: implementare prin iruri de caractere (true i false)
In C: implementare prin numere (1, 0)
Specificarea unui ADT
Mulimea valorilor admisibile
Mulimea operaiilor pe acele valori
Tipuri abstracte de date (II)

Ex. ADT queue

Cunotine necesare unui analist (comportamentul cozii):


Inserarea in coad: la sfrit
Extragerea de elemente din coad: la nceput

Analistul nu trebuie s tie implementarea cozii

Implementri posibile
Un masiv + o var. auxiliar care memoreaz sfritul cozii
Un masiv + 2 var auxiliare: sfritul cozii i nceputul acesteia
Impl. cu pointeri: 2 var auxiliare: sfritul listei i nceputul acesteia
Specificarea unui ADT

Specificarea valorilor acceptate

Specificarea operaiilor

Specificarea utilizrilor posibile ale ADT-ului

Implicaii pt. programatorul ADT-ului


Se pot alege structuri de date corespunztoare pentru implementare

Implicaii pt. utilizatorul ADT-ului


Comportamentul ADT-ului e observat prin efectul i rezultatul realizrii
operaiilor specificate
Specificarea operaiilor

Sintaxa operaiei: Maparea datelor de intrare cu datele de ieire

Semantica operaiei
Pre-condiii
Post-condiii

Ex: operaia HEAD.OF.QUEUE inspectarea vrfului cozii


HEAD.OF.QUEUE : queue --> string
x | y
Pre-condiii: x is not empty
Post-condiii: y is the head of the queue x
Implementri ale unui ADT

Secvene, liste sau iruri dinamice: elementele mulimii sunt stocate ntr-o
anumit ordine

Bag sau Heap: nu se specific ordinea elementelor, se permit elemente


duplicate

Arbori

Grafuri sau reele

Principiul ascunderii implementrii: programatorul client nu trebuie s


tie modalitatea de implementare a ADT-ului
Implementarea unui ADT n C

Fiier header (.h)


Conine definia tipului
Conine prototipul operaiilor permise pe tip
Este inclus n toate utilizrile ADT-ului

Fiier implementare (.c)


Conine definirea fiecrei operaie ca i funcie
Este link-editat la mpreun cu programul client
Fisierele header sunt incluse in programul client si in fis implementare
prin directiva #include
ADT Lista

Secven de 0 sau mai multe elemente de acelai tip

Caracteristici:
n: lungimea listei
Se spune ca ai precede pe ai+1 i ai succede pe ai-1

Operaii pe list
Insert(x, p, L)
Locate(x, L)
Retrieve(p, L)
Delete(p, L)
Next(p, L)
Previous(p, L)
Makenull(p, L)
First(L)
Printlist(L)
Implementarea listelor cu iruri

Dezavantaj:

trebuie specificat la compilare dimensiunea maxim a listei

operatiile de insert si delete sunt de complexitate sporit

Avantaj:

regsirea elementelor se face rapid - complexitate O(1)

Implementarea listelor cu pointeri (i)

Dezavantaj:

Regasirea elementelor se face ncet complexitate O(n)

Operatiile de insert si delete se realizeaz uor

Nu trebuie specificat dimensiunea maxim. Gestiune optim a


spaiului de stocare

Avantaj:

Variante de implementare
Acces la list printr-un pointer
Santinele la nceput i/sau sfrit

Santinela:
Un element de list gol care marcheaz nceputul sau sfritul listei
Avantaj: permite inserare uoar de elemente la inceput / sfrit
Liste nlnuite

O structur de date n care obiectele sunt aranjate intr-o ordine liniar

La implementarea prin siruri, ordinea este determinat de indici


La implementarea prin pointeri, ordinea este determinat de un pointer care
arat ctre obiectul urmtor

List simplu nlnuit: fiecare obiect are un atribut cheie i un pointer next

List dublu nlnuit: fiecare obiect are un atribut cheie i doi pointeri: next
i prev

La un element x, x.next arat ctre elementul succesor

La un element x, x.prev arat ctre elementul predecesor

Dac x.prev == NULL, atunci x este primul element, denumit head

Dac x.next == NULL, atunci x este ultimul element, denumit tail

Dac lista este sortat, cheile apar n ordine sortat

Lista circular:
ultimul element din list pointeaz ctre head
primul element din list pointeaz ctre tail

Operaia de cutare n list

Identific primul element cu cheia k in lista L

Pentru o list cu n elemente, timpul de execuie este

(n)

Inserarea unui element in list

Operaia de inserare la inceputul listei

Stergerea unui element din list

Pentru a se sterge un element x, trebuie s avem un pointer ctre acesta

Dac nu avem un pointer ctre elementul x, atunci acesta trebuie gsit prin
List-search

LIST-DELETE(L,x)
1. if x.prev
2.

NIL

x.prev.next = x.next

3. Else L.head = x.next


4. If x.next
5.

NIL

x.next.prev = x.prev

Dac ignorm condiiile de head si tail a listei, operatia de delete se transform n:


LIST-DELETE-SANTINELA(L,x)
1. x.prev.next = x.next
2. x.next.prev = x.prev

=> Necesitatea santinelelor: obiect dummy care marcheaz inceputul sau sfritul
listei. Introducem un element L.nil , astfel ncat orice referin la Nil s se
transforme in referinta la L.nil

LIST-SEARCH-SANTINELA(L, k)
1. x = L.nil.next
2. While x
3.

L.nil and x.key

x = x.next

4. Return x
LIST-INSERT-SANTINELA(L, x)
1. x.next = L.nil.next
2. L.nil.next.prev = x
3. L.nil.next = x
4. x.prev = L.nil
Stive

Last-in, first-out

INSERT -> PUSH, DELETE -> POP

Implementare stiva cu siruri


STACK-EMPTY(S)
1. If S.top == 0
2.

Return true

3. Else return false


PUSH(S,x)
1. S.top = S.top + 1
2. S[S.top] = x
POP(S)
1. If STACK-EMPTY(S)
2.

eroare

3. Else
4.

S.top = S.top 1

Return S[S.top + 1]

Coada

First-in, first-out

INSERT -> ENQUEUE, DELETE -> DEQUEUE


Coada are head si tail; ENQUEUE se face la tail, DEQUEUE se face la head

Operatii de coad
ENQUEUE(Q,x)
1. Q[Q.tail] = x
2. If Q.tail == Q.length
3.

Q.tail = 1

4. Else

Q.tail = Q.tail + 1

DEQUEUE(Q)
1. x = Q[Q.head]
2. If Q.head == Q.length
3.

Q.head = 1

4. Else

Q.head = Q.head + 1

5. Return x
Conceptul de dictionary

Fiecare element din dictionar se caracterizeaz prin (cheie, valoare)

Operatii esentiale pentru dictionare: INSERT, SEARCH, DELETE

Tabela de dispersie: o generalizare a notiunii de array (sir cu index): se


permite examinarea oricrei poziii in timp O(1)

Tabele de dispersie sunt bazate pe conceptul de hashing

Tabele direct adresabile

Presupunem c o aplicaie necesit elemente dintr-un dictionar in care fiecare


element are o cheie asociat din mulimea

U={0,1, , m1}

Pentru reprezentarea multimii dinamice se foloseste o tabel


care fiecare poziie corespunde unei chei din U

Operaii pe tabele direct adresabile:


DIRECT-ADDRESS-SEARCH(T, k)
1. return T[k]
DIRECT-ADDRESS-INSERT(T, x)
1. T[x.key] = x
DIRECT-ADDRESS-DELETE(T, x)
1. T[x.key] = NIL

T [0. . m1]

Tabele de dispersie

Dac universul de chei U este mare (adic valori mari ale lui m), se pune
problema dimensiunii alocrii unui sir T[0..m-1]

In general, numrul de chei K care se stocheaz este mic n comparaie cu


mrimea lui U

Dac numrul de chei K din dicionar este mult mai mic dect
tabelele de dispersie reduc necesarul de memorie la

(|K|)

m= U ,
iar operaiile

de cutare se fac in timp O(1)

La tabele de dispersie, O(1) pentru cutare este valabil pentru cazul mediu
de utilizare,

La tabele direct adresabile O(1) are loc si pentru cazul cel mai ru
Definiie

h :U {0,1, , m1 }

Funcia de dispersie (hash function)

Fiecare element cu cheia k este salvat n locaia T[h(k)]

Pt functia de dispersie are loc condiia

Coliziune: dac dou chei au aceai valoare de hash

mU

Proprieti ale funciei de dispersie

Trebuie s fie o funcie care s minimizeze ansa apariiei coliziunilor

Deoarece

mU , in cel mai ru caz coliziunile nu pot fi evitate

=> metod de rezolvare a coliziunilor


Rezolvarea coliziunilor prin inlnuire

Plasm elementele care au valori de hash egale in acelai slot, ntr-o list
inlnuit

Slotul j conine un pointer ctre lista care salveaz elementele care au j ca si


valoare de hash

Daca nici un element nu are valoare de hash pe j, atunci la T[j] = NIL


CHAINED-HASH-INSERT(T, x)
1. Insert x la varful listei T[h(x.key)]
CHAINED-HASH-SEARCH(T, k)
1. Se caut un element cu cheia k n lista T[h(k)]
CHAINED-HASH-DELETE(T, x)
1. Se sterge x din lista T[h(x.key)]
Analiza tabelelor de dispersie cu inlnuire

Fie o tabel de dispersie T[0..m-1], care salveaz n elemente

Factorul de incarcare a tabelei:

=n /m : numrul mediu de elemente salvat

ntr-o inlnuire

Presupunem c h[k] se calculeaz n O(1)

Cel mai rau caz: toate cele n chei se inlnuiesc pe aceai pozitie, unde avem
o list de lungime n => timp de cutare

(n)

Cazul mediu: funcia de hash distribuie in mod uniform cheile pe cele m


poziii
Notm cu

n j lungimea listei de pe poziia T[j]

Valoarea asteptat pentru

nj

este

n
E[ j]==n /m

Rezultate teoretice in cazul funciilor cu dispersie uniform


1. Intr-o tabel de dispersie cu rezolvarea coliziunilor prin inlnuire, o cutare
fr success are loc in cazul mediu in

(1+)

2. intr-o tabel de dispersie cu rezolvarea coliziunilor prin inlnuire, o cutare


cu success are loc in cazul mediu in

( 1+ )

=> Dac avem n=O(m), atunci operaiile pe tabela de dispersie se fac in O(1)
Adresare deschis

Elementele sunt salvate direct n tabela de dispersie. Deci un slot din tabela
de dispersie contine fie un element fie NIL

La cautare, se examineaz fiecare slot pn la identificarea elementului sau


pn la NIL

Tabela de dispersie se poate umple, deci in mod maxim avem

La cautate, in loc s se urmeze pointerii de la inlnuire, se calculeaz locul


unde s se realizeze cutarea

La inserare, se testeaz locaiile din tabel pn s se gseasc una liber


pentru inserare

Functia de dispersie devine

h :U { 0,1, , m1 } { 0,1, , m1 }

=1

Pentru fiecare cheie k, la inserare se probeaz


care reprezint o permutare a lui

0,1, , m1

HASH-INSERT(T, k)

HASH-SEARCH(T,
k)

1. i = 0

1. i = 0

2. Repeat
3.

j = h(k,i)

4.

If T[j] == NIL

h ( k , 0 ) ,h ( k ,1 ) , , h ( k ,m1 )

2. Repeat
3.

j = h(k,i)

Implementri ale funciei de dispersie

5.

T[j] = k

Functia de dispersie trebuie sa produc o permutare a lui

0,1, , m1

Probarea liniar

Dac

'

h :U {0,1, , m1 } este o funcie de dispersie obinuit auxiliar,

atunci

h ( k , i )=( h' ( k ) +i ) mod m

Probarea ptratic

Dac

h' :U {0,1, , m1 } este o funcie de dispersie obinuit auxiliar,

atunci

h ( k , i )=( h ' ( k ) + c1 i+ c2 i 2) mod m , cu

c1

c 2 dou constante pozitive

Dispersia dubl

Dac se consider dou funcii de dispersie auxiliare

h ( k , i )=( h1 ( k ) +i h2 ( k ) ) mod m

h1

h2 , atunci

De exemplu se poate considera

h1 ( k )=k mod m

h2 ( k )=1+(k mod (m1)) ,

cu m numr prim
Arbore binar de cautare

Fiecare nod de arbore contine cheia, date auxiliare si 3 referinte: left, right si
p care pointeaz ctre nodurile copii stanga respectiv dreapta i ctre nodul
printe

Dac un copil sau un printe lipseste, referinta respectiv va fi Nil

Arbore binar de cutare definire:

Un arbore este binar de cutare dac este un arbore binar (adic fiecare nod
are cel mult 2 copii) si

Daca x este un nod in arbore, si y este un nod in subarborele stang atunci

y .key x . key . Dac y este un nod in subarborele drept, atunci


x . key y . key

Parcurgeri ale arborelui binar de cutare

Parcurgerea in inordine: stang-radacin-drept: produce nodurile arborelui in


ordinea sortat a cheilor

INORDER-TREE-WALK(x)
1. If x != Nil
2.

INORDER-TREE-WALK(x.left)

3.

Print x.key

4.

INORDER-TREE-WALK(x.right)

Parcurgerea in preordine: radacin-stang-drept

Parcurgerea in postordine: stang-drept-radacin

Tem: implementati toate cele 3 proceduri de parcurgere a arborilor

Complexitatea acestor parcurgeri:

(n)

Cutarea unei chei in arbore


TREE-SEARCH(x, k)
1. If x == Nil or k = x.key
2.

Return x

3. If k < x.key
4.

Return TREE-SEARCH(x.left, k)

5. Else

Return TREE-SEARCH(x.right, k)

Cutarea cheii cu valoare minim

TREE-MINIMUM(x)
1. While x.left != Nil
2.

x = x.left

3. Return x

Cutarea cheii cu valoare maxim

TREE-MAXIMUM(x)
1. While x.right != Nil
2.

x = x.right

3. Return x
ITERATIVE-TREE-SEARCH(x, k)
1. while x == Nil or k = x.key
2.

If k < x.key

3.
4.

x = x.left
Else

x = x.right

5. Return x
Cutarea nodului cu cheie succesoare in parcurgerea in inordine
TREE-SUCCESSOR(x)

1. If x.right != Nil
2.

Return TREE-MINIMUM(x.right)

3. y = x.p
4. While y != Nil and x == y.right
5.

x=y

6.

y = y.p

7. Return y
Inserarea unui nod
TREE-INSERT(T, z)
1. y = Nil
2. x = T.root
3. While x != Nil
4.

y=x

5.

If z.key < x.key

6.

x = x.left

7.

Else

x = x.right

8. z.p = y
9. If y == Nil
10.

T.root = z // arborele a fost gol

11. Elseif z.key < y.key


12.

y.left = z

13. Else y.right = z


Stergerea unui nod

3 cazuri:
Se sterge un nod frunz
Se sterge un nod cu un singur copil: acesta urc in sus in arbore
Se sterge un nod cu 2 copii: se gseste succesorul nodului care se
sterge. Subarborele drept este elevat, subarborele stang este agatat in
stanga succesorului

TREE-DELETE(T, z)

1. If z.left == Nil
2.

TRANSPLANT(T, z, z.right)

3. Elseif z.right == Nil


4.

TRANSPLANT(T, z, z.left)

5. Else
6.

y = TREE-MINIMUM(z.right)

If y.p != z

7.

TRANSPLANT(T, y, y.right)

8.

y.right = z.right

9.

y.right.p = y

10.

TRANSPLANT(T, z, y)

11.

y.left = z.left

12.

y.left.p = y

TRASNPLANT(t, u, v)
1. If u.p == Nil
2.

T.root = v

3. Elseif u == u.p.left
4.

u.p.left = v

5. Else u.p.right = v
6. If v != Nil
7.

v.p = u.p

Definire, proprieti

Arbore rou-si-negru: arbore binar de cutare la care fiecare nod are bit
suplimentar, reprezentnd culoarea: rou sau negru.

Fiecare nod de arbore conine urmtoarele campuri: cheia, culoarea, nodul


stng, nodul drept i printele

Proprieti arbore rou-negru:


1. Fiecare nod este sau rou sau negru
2. Rdcina este negru
3. Fiecare frunz (NIL) este neagr
4. Dac un nod este rou, atunci amndoi copii sunt negrii

5. Pentru fiecare nod, toate cile simple de la nodul respectiv la frunzele


descendente conin acelai numr de noduri negre

Se doreste implementarea arborilor balansai

Proprieti

Pentru fiecare nod x, notm cu bh(x) numrul nodurilor negre de la x la


frunzele sale inltimea neagr a lui x. bh(x) nu il numr pe x

Inlimea neagr a unui arbore rou-negru este inlimea neagr a rdcinei

Un arbore rosu-negru cu n noduri interne, are inlime cel mult

Operaiile TREE-INSERT i TREE-DELETE ntr-un arbore cu n noduri se execut


in

O ( log ( n ) )

Aceste operaii schimb arborele, deci arborele rezultat poate s nu mai


indeplineasc condiiile de arbore Rosu-negru => sunt necesare corecii
pentru a pstra proprietile arborelui

LEFT-ROTATE (T,x)

1. y = x.right
2. x.right = y.left
3. If y.left != T.nil
4.

y.left.p = x

5. y.p = x.p
6. If x.p ==T.nil
7.

2 log ( n+ 1)

T.root = y

8. Elseif
9.

x == x.p.left

x.p.left = y

10. Else x.p.right = y


11. y.left = x
12. x.p = y

Inserare
RB-INSERT(T,z)
1. y = T.nil
2. X = T.root
3. While x != T.nil
4.

y=x

5.

If z.key < x.key

6.

x = x.left

7.

Else

x = x.right

8. z.p = y
9. If y == T.nil
10

T.root = z

11. Elseif z.key < y.key


12

y.left = z

13. Else y.right = x


14. z.left = T.nil
15. z.right = T.nil

16. z.color = RED


17. RB-INSERT-FIXUP(T,z)
RB-INSERT-FIXUP(T,z)
1. While z.p.color == RED
2.

If z.p == z.p.p.left

3.

y = z.p.p.right

4.

If y.color == RED

5.

z.p.color = BLACK //caz1

6.

y.color = BLACK

7.

z.p.p.color = RED

8.

Z = z.p.p

9.

Else if z == z.p.right

10

Z = z.p // caz 2

11

LEFT-ROTATE(T,z)

12.

z.p.color = BLACK //caz 3

13.

z.p.p.color = RED

14.

RIGHT-ROTATE(T, z.p.p)

15.

Else (similare cu partea then, doar ca se interschimba intre ele right cu left)

16. T.root.color = BLACK

Condiiile de invariant din cadrul buclei while din RB-INSERT-FIXUP


Nodul z este rosu
Dac z.p este rdcina, atunci z.p este negru
Dac arborele violeaz conditia Rosu-i-negru, atunci violeaz cel mult
o proprietate, adica sau proprietatea 2 sau 4

Stergerea unui nod


Se inlocuiteste subarborele u cu subarborele v in arborele T
RB-TRANSPLANT(T, u, v)
1. If u.p == T.nil
2.

T.root = v

3. Elseif u == u.p.left

4.

u.p.left = v

5. Else u.p.right = v
6. v.p = u.p
TREE-TRASNPLANT(t, u, v)
1. If u.p == Nil
2.

T.root = v

3. Elseif u == u.p.left
4.

u.p.left = v

5. Else u.p.right = v
6. If v != Nil
7.

v.p = u.p

RB-DELETE(T, z)
1. y = z
2. y-original-color = y.color
3. If z.left == T.nil
4.

x = z.right

5.

RB-TRANSPLANT(T, z, z.right)

6. Elseif z.right == T.nil


7.

x = z.left

8.

RB-TRANSPLANT(T, z, z.left)

9. Else y = TREE-MINIMUM(z.right)
10.

y-original-color = y.color

11.

x = y.right

12.

If y.p == z

13.
14.

x.p = y
Else

RB-TRANSPLANT(T, y, y.right)

15.

y.right = z.right

16.

y.right.p = y

17.

RB-TRANSPLANT(T, z, y)

18.

y.left = z.left

19.

y.left.p = y

20.

y.color = z.color

21. If y-original-color == BLACK


RB-DELETE-FIXUP(T,x)
TREE-DELETE(T, z)
1. If z.left == Nil
2.

TRANSPLANT(T, z, z.right)

3. Elseif z.right == Nil


4.

TRANSPLANT(T, z, z.left)

5. Else
6.

y = TREE-MINIMUM(z.right)

If y.p != z

7.

TRANSPLANT(T, y, y.right)

8.

y.right = z.right

9.

y.right.p = y

10.

TRANSPLANT(T, z, y)

11.

y.left = z.left

12.

y.left.p = y

RB-DELETE-FIXUP(T, x)

1. While x != T.root and x.color == BLACK


2.

If x == x.p.left

3.

w = x.p.right

4.

If w.color == RED

5.

w.color = BLACK //caz1

6.

x.p.color = RED

7.

LEFT-ROTATE(T, x.p)

8.

w = x.p.right

9.

If w.left.color == BLACK and w.right.color == BLACK

10.

w.color = RED // caz2

11.

x = x.p

12.

Else if w.right.color == BLACK

13.

w.left.color = BLACK // caz3

14.

w.color = RED

15.

RIGHT-ROTATE(T, w)

16.

w = x.p.right

17.

w.color = x.p.color // caz4

18.

x.p.color = BLACK

19.

w.right.color = BLACK

20.

LEFT-ROTATE(T, x.p)

21.

X = T.root

22.

Else la fel ca si clauza then, cu right si left interschimbate intre ele

23. x.color = BLACK


Reprezentri liste de adiacen

Graf:

G=(V , E)

V multimea nodurilor, E multimea arcelor

V 2
|E| : liste de adiacen

Pentru grafuri cu densitate mic

Pentru grafuri dense: matrice de adiacen

Liste de adiacen:

Reprezint un sir Adj de |V| liste, cate o list pentru fiecare nod din graf

Pentru fiecare

u V ,

exist un arc

(u , v ) E

G. Adj [u]

Adj [ u]

conine toate nodurile v din graf astfel incat

Notatia

Dac G graf orientat, atunci un arc (u,v) este reprezentat prin

Dac G graf neorientat, atunci u apare in Adj[v] i v apare in Adj[u]

Spaiul de memorie necesar:

Dac graful este ponderat cu ponderile

pentru a ne referi la lista de adiacen a nodului u

v Adj [u ]

(V + E)

w : E R , atunci ponderea w(u,v)

se salveaz cu arcul v in lista de adiacen a lui u

Dezavantajul listelor de adiacen: nu permit o cale rapid de a determina


dac un anume arc (u,v) se alf in graf

Reprezentri matrice de adiacen

Presupunem c nodurile sunt numerotate cu 1, 2, ..., |V|

Folosim o matrice de dimensiune

aij =

V V ,

A=(aij ) astfel nct

1, dac(i , j) E
0, n caz contrar

Matricea de adiacen necesit spaiu de memorie

(V 2) , indiferent de

numrul de noduri

A= A

Pentru un graf neorientat, matricea este simetric:

Dac graful este ponderat, atunci in matrice se salveaz ponderile w(u,v)

Notaii:

Pentru a nota un atribut d al unui nod, folosim notatia v.d

Pentru a nota un atribut f a unui arc, folosim notatia (u,v).f

Parcurgerea in latime (breadth-first)

Dac se d ca i start un nod s din graf, parcurgerea in latime exploreaz in


mod sistematic arcele din G pentru a descoperi fiecare nod care poate fi
identificat pornind de la s

Calculeaz distana de la s la fiecare nod din graf care este conectat la s

Algoritmul exploreaz frontiera dintre nodurile descoperite si cele


nedescoperite n laime, adic descoper toate nodurile la distan k, apoi
cele la distan k+1, etc.

Se presupune ca initial toate nodurile din graf sunt colorate alb


(nedescoperite).

Dac

(u , v ) E

i u este nod negru, atunci v va fi sau negru sau gri: toate

nodurile adiacente unui nod negru au fost descoperite

Nodurile gri pot avea noduri albe adiacente: acestea reprezint frontiera
dintre nodurile descoperite sau nu

Parcurgerea in latime calculeaz un arbore de parcurgere in latime cu


radacina in s

De fiecare data cand se descoper un nod v alb la scanarea listei de


adiacen a nodului u, arcul (u,v) se salveaz in arborele de parcurgere

Parcurgere in latime

Reprezentare cu liste de adiacen

BFS(G,s)
1. For fiecare nod

u G .V { s }

2.

u.color = WHITE

3.

u.d =

4.

u. = Nil // predecesorul lui u

5. s.color = GRAY
6. s.d = 0
7. s. = Nil
8. Q =

// se initializeaz coada Q la multimea vid

9. ENQUEUE(Q, s)
10. While

11.

u = DEQUEUE(Q)

12.

For fiecare nod

13.

v G . Adj [u]

If v.color == WHITE

14.

v.color = GRAY

15.

v.d = u.d + 1

16.

v. = u

17.

ENQUEUE(Q,v)

18

u.color = BLACK

Calea cea mai scurt

(s , v) : numrul minim de arce necesar pentru a ajunge de la nodul s la v


Dac nu exist o cale de la s la v notm

( s , v )=

Dac avem un graf G=(V,E), si s un nod arbitrar din V, atunci pentru orice arc

(u , v ) E , avem

( s , v ) ( s ,u )+1

Dac se execut BFS pornind de la un nod s, la terminare, pentru fiecare nod


v pt care exist o cale de la s, valoarea v.d calculat de BFS satisface

v . d= (s , v )
PRINT-PATH(G, s, v)
1. If v == s
2.

Print s

3. Elseif v. == Nil
4.

Print nu exista cale de la s la v

5. Else
6.

PRINT-PATH(G, s, v.)

Print v

Parcurgerea in adancime

Presupune o cutare in graf cat de adnc posibil

Se parcurge pe arcele nodului cel mai recent descoperit

Dac toate arcele unui nod v au fost explorate, atunci algoritmul face backtracking la urmtorul nod care trebuie explorat dup v

Folosim aceasi convenie de colorare: WHITE, GRAY si BLACK

Pentru fiecare nod folosim 2 stampile de timp:


v.d momentul in care nodul a fost descoperit (cand este marcat GRAY)
v.f momentul in care parcurgerea termin lista de adiacen a lui v
(cand nodul este marcat BLACK)

DFS(G)

1. For fiecare nod

2.

u.color = WHITE

3.

u. = Nil

4. Time = 0

5. For fiecare nod

6.

u G .V

u G .V

If u.color == WHITE

7.

DFS-VISIT(G, u)

1. Time = time + 1

2. u.d = time

3. u.color = GRAY

4. For fiecare

5.

If v.color == WHITE

6.

v. = u

7.

DFS-VISIT(G, v)

8. u.color = BLACK

9. Time = time+1

10. u.f = time

Timpul de executie atat a lui DFS este (V+E

Dac notm cu (u momentul descoperirii unui nod u si cu u) momentul in care nodul


u devine BLACK, atunci DFS ne produce o expresie bine-format: parantezele se inchid
corespunztor
Daca intervalele [u.d,u.f] si [v.d, v.f] sunt disjuncte, atunci nici unul dintre u sau v nu este
descendentul celuilalt in arborele de parcurgere
Dac [u.d, u.f] este inclus total n [v.d, v.f], atunci u este un descendent a lui v in arborele
de parcurgere

DFS-VISIT(G, u)

v G . Adj [u]

Sortare topologic

O sortare topologic a unui direct acyclic graph G=(V,E) este o ordonare a


nodurilor din G astfel nct dac G conine un arc (u,v) atunci u apare inaintea
lui v in sirul sortat.

Dac graful contine cicluri, atunci sortarea topologic nu este posibil

TOPOLOGICAL-SORT(G)
1. Apeleaz DFS(G) pentru a calcula v.f pentru fiecare nod v
2. Pe msur ce fiecare nod este terminat de parcurs, inserm acest nod in varful
unei liste inlnuite
3. Return lista inlnuit

Componente tare conexe

Problem: descompunerea unui graf orientat in componentele tare conexe

Pentru un graf orientat G=(V,E), o component tare conex este un set

maximal de noduri

astfel incat pentru orice pereche de noduri u si v din

C exist o cale de la u la v si de la v la u
STRONGLY-CONNECTED-COMPONENTS(G)
1. Apeleaz DFS(G) pentru a calcula u.f pentru fiecare nod u
2. Calculeaz

G =(V , E )

3. Apeleaz DFS( G

) dar in bucla principal a lui DFS considerm ordinea

nodurilor ca fiind ordinea descresctoate a lui u.f


4. Returnm nodurile fiecrui arbore din pdurea format la linia 3 ca si o
component tare conex separat
Definirea arborilor de acoperire
Problem

La proiectarea circuitelor electronice, n pini pot fi conectai cu n-1 cabluri,


fiecare conectand cate 2 pini. Dintre toate aceste cablri posibile, se cere s
se determine cablarea care foloseste cea mai mic cantitate de cabluri
Definire formal a problemei

G=(V , E)

Graf:

w(u,v) repezint costul unui cablu de la pinul u la v

Dorim s determinm o mulime aciclic

V multimea pinilor, E multimea posibilelor cablri

nodurile din V si pentru care

w ( T )=

T E

care conecteaz toate

w(u , v)

(u , v)T

este minim

Deoarece T este aciclic, in fapt se cere determinarea unui arbore T arbore


care poart numele de arbore de acoperire

Algoritmul lui Kruskal

Algoritmul lui Prim


Timp de executie:

O ( E log V )

Metoda generic de cautare


GENERIC-MST(G, w)
1. A =

2. While A nu este un arbore minimal de acoperire


3.

Gseste un arc (u,v) care este safe pentru A

4.

A= A { (u , v ) }

5. Return A

Inainte de fiecare iteratie, A este un subset a unui arbore minimal de


acoperire

La fiecare iteratie, se adaug la A un arc (u,v) safe astfel incat s se


pstreze proprietatea de subset a unui arbore minimal de acoperire

Partea dificil in algoritm: modul de determinare a unui arc safe

Taietura unui graf

O tietur (S, V-S) a unui graf neorientat G=(V,E) este o partitie a lui V

Un arc

(u , v ) E

taie tietura S dac unul din capete este in S si cellalt in

V-S

O tietur S respect o multime A de arce dac nici un arc din A nu taie


tietura S

Un arc este un arc usor care taie o tietur dac costul w a arcului este
minimum dintre costurile tuturor arcelor care taie tietura

Dac G=(V,E) este un graf neorientat conectat si o functie real w definit pe


E. Fie A un subset a lui E care este inclus intr-un arbore minimal de acoperire,
fie (S,V-S) o tietur oarecare care respect pe A si fie (u,v) un arc usor care
taie tietura (S,V-S). Atunci (u,v) este un arc safe pentru A

Dac G=(V,E) este un graf neorientat conectat cu o functie real w definit


pe E. Fie A un subset a lui E care este inclus intr-un arbore minimal de
acoperire si fie

C=( V C , E C )

o component conex (un arbore) in pdurea

G A =(V , A ) . Dac (u,v) este un arc usor care conecteaz C cu alte


componente din

G A , atunci (u,v) este un arc safe pentru A

Algoritmul lui Kruskal

Algoritmul gseste arcul safe (u,v) dintre toate arcele care conecteaz 2
arbori in pdurea de arbori arc cu costul cel mai mic
MST-KRUSKAL(G, w)
1. A =

v V

2. For fiecare
3.

MAKE-SET(v)

4. Sorteaz arcele din E in ordine cresctoare a costului w


5. Pentru fiecare arc (u,v) luat in ordine cresctoare a costului
6.

If FIND-SET(u)

FIND-SET(v)

A= A { (u , v ) }

7.
8.

UNION(u,v)

9. Return A

Algoritmul lui Prim

La fiecare pas se adaug lui A un arc usor care conecteaz pe A cu un nod


izolat
MST-PRIM(G, w, r)
1. For fiecare
2.

u.key =

3.

u. = Nil

u V

4. r.key = 0
5. Q = V
6. While Q !=

7.

u = EXTRACT-MIN(Q)

8.

For fiecare

9.

If

v G . Adj [ u ]

v Q

and w(u,v) < v.key

10

v. = u

11.

v.key = w(u,v)

Algoritmi de cale minima

Dac se d harta unei tri, s se gseasc drumul cel mai scurt intre 2 orase
Definirea problemei

Se d un graf G=(V,E) si o functie de cost w. costul w(p) a unei ci

p= v 0 , v 1 , , v k

este suma tuturor costurilor de pe calea p:

w ( p )= w(v i1 , v i) .
i=1

Calea cu costul minim

(u , v )=

(u , v)

de la u la v este:

min {w ( p ) :u p v } dac exist o cale de la u la v

caz contrar

Variante ale problemei

S se gseasc calea cea mai scurt ctre o anume destinatie t de la fiecare


nod v din graf. Problema poate fi pus si invers: calea cea mai scurt de la o
sursa s la fiecare nod v din graf

S se gseasc calea cea mai scurt dintre 2 noduri u si v


S se gaseasc calea cea mai scurt dintre toate perechile de noduri (u,v)
Structura optim a unei cai minime

Calea de cost minim conine in interiorul su alte ci de cost minim

Dac se d un graf orientat G=(V,E) si o functie de cost w pe graful G, dac

p= v 0 , v 1 , , v k
pentru orice

vi

este calea de cost minim intre 2 noduri

0 i j k

pij = v i , v i+1 , , v j

v0

vk

atunci

este calea de cost minim intre

vj

! O cale minim nu contine cicluri


Reprezentarea cii minime

Fie un graf G=(V,E). Pentru fiecare nod v vom memora predecesorul

v .

acestuia, care poate fi un alt nod sau Nil

Algoritmii de determinare a cii minime seteaza predecesorii astfel nct dac


se merge de la un nod v inapoi, se gseste calea minim de la sursa s la v

Tem: s se scrie o procedura PRINT-PATH(G, s, v) care tiprete calea


minim de la s la v

Arborele cu cai minime

Notm cu

toate nodurile din V care au predecesor diferit de Nil

includem sursa s in

Notm cu

arcele induse de relatia predecesor pe nodurile din

V , E
G = ) este arborele cu cai minime: arborele cu rdcina in

Atunci graful

sursa s care contine cile minime de la s la toate nodurile din graful G


Relaxarea

Pentru fiecare nod v pstrm atributul v.d care reprezint o margine


superioar a costului cii minime de la s la v
INITIALIZE-SINGLE-SOURCE(G, s)
1. For fiecare nod v din graful G
2.

v.d =

3.

v .

= Nil

4. s.d = 0
Tehnica relaxrii: pentru un arc (u,v) inseam a testa dac se poate
imbunti calea cea mai scurt ctre v trecnd prin nodul u
RELAX(u, v, w)
1. If v.d > u.d + w(u,v)
2.
3.

v.d = u.d + w(u,v)

v .

=u

Ideea algoritmilor de cale minim:

Se apeleaz la inceput INITIALIZE-SINGLE-SOURCE

Apoi se apeleaz relaxri ale arcelor

Algoritmii difer prin numrul de relaxri aplicate pentru fiecare arc din graf
Proprieti ale cilor minimale

Inegalitatea triunghiular: pentru orice arc (u,v) avem

( s , v ) ( s ,u )+ w ( u , v )

Proprietatea de margine superioar: intotdeauna


v.d atinge valoarea

(s , v)

v . d (s , v ) . Dac

atunci v.d va rmne neschimbat pentru tot

restul algoritmului

Proprietate lipsei cii: dac nu exist cale de la s la v atunci

v . d= ( s , v )=

Proprietatea de convergen: dac calea cea mai scurt de la s la v trece


prin u si
atunci

u . d= ( s , u )

la orice moment inaintea relaxrii pe arcul (u,v),

v . d= ( s , v ) dup relaxare

Proprietatea de relaxare a cii: dac calea minim de la


este
....,

p= v 0 , v 1 , , v k
(v k1 , v k )

si relaxm arcele din p in ordinea

s=v 0

(v 0 , v 1 ) ,

la

vk

(v 1 , v 2 ) ,

atunci v k . d= ( s , v k ) . Proprietatea are loc indiferent ce alte

relaxri mai sunt realizate de algoritm, si indiferent cum aceste relaxri sunt
mixate cu cele din calea p

Proprietatea subgrafului predecesorilor: daca

v . d= ( s , v ) pentru

toate nodurile v, atunci subgraful predecesorilor este arborele cu caile


minime cu varful in s
Algoritmul Bellman-Ford
BELLMAN-FORD(G, w, s)
1. INITIALIZE-SINGLE-SOURCE(G, s)
2. For i = 1 to |G.V| - 1
3.
4.

For fiecare arc (u,v)


RELAX(u, v, w)

5. For fiecare arc (u,v)


6.

If v.d > u.d + w(u,v)

7.

Return FALSE

8. Return TRUE
Algoritmul indica FALSE in cazul in care gaseste un ciclu cu cost negativ
Timp de executie: O(VE)
Cai minime in grafuri aciclice (DAG)

DAG-SHORTEST-PATH(G, w, s)
1. Se sorteaz[ topologic nodurile din G
2. INITIALIZE-SINGLE-SOURCE(G, s)
3. For fiecare nod u, considerat in ordinea topologica
4.

G.Adj[u]

For fiecare nod v

5.

RELAX(u, v, w)

Timpul total de executie:

(V + E)

Algoritmul lui Dijkstra

w (u , v) 0

Rezolv problema cii minime dac


DIJKSTRA(G, w, s)
1. INITIALIZE-SINGLE-SOURCE(G, s)
2.

S=

3. Q = G.V // coad min-priority


4. While
5.

u = EXTRACT-MIN(Q)

S=S { u }

6.
7.

Q=

For fiecare nod

8.

v G . Adj [ u ]

RELAX(u, v, w)

Invariant: la startul fiecrei iteratii while, are loc


v din S

Timp de executie:

O(V )

dac

V
V /log
E=o
2

v . d= ( s , v ) pentru fiecare

Vous aimerez peut-être aussi