Documente Academic
Documente Profesional
Documente Cultură
- adresa unui nod, denumit i pointerul sau referina acelui nod, reprezint locaia din
memorie a primului cuvnt aparinnd nodului;
- coninutul oricrui cmp al unui nod poate reprezenta numere, caractere alfabetice,
referine la alte noduri sau orice altceva dup necesitile de programare;
- pentru reprezentarea referinei nule se va folosi, n cele ce urmeaz, litera ;
- n memoria calculatorului va fi reprezentat printr-o valoare uor de recunoscut, care
nu poate reprezenta adresa unui nod;
- introducerea de referine ctre alte elemente de date reprezint o idee deosebit de
valoroas pentru programarea calculatoarelor; acesta constituie cheia reprezentrilor complexe;
- la ilustrarea reprezentrii n calculator a nodurilor este deseori convenabil ca referinele
s fie reprezentate prin sgei:
Figura
NCEPU
T
2.1.
inserar
e
sau
terger
e
nceput
nodul II
nodul III
sfrit
Figura 2.2. Exemplu de stiv
Definiia 2.2.3. O coad (queue) este o list linear pentru care toate inserrile sunt
fcute la unul din capetele listei; toate tergerile (i, de obicei, orice acces) sunt fcute la cellalt
capt.
tergere
fa
inserare
nod 2
nod 3
spate
nod 2
stnga
nod 3
stnga
inserare
sau
tergere
inserare
sau
tergere
Figura 2.4. Exemplu de coad complet.
Subiectul 2.
Liste simplu nlnuite. Creare i acces.
Lista este o mulime finit i ordonat de elemente de acelai tip. Elementele listei se
numesc noduri.
Listele pot fi organizate sub form static, de tablou, caz n care ordinea este implicit dat
de tipul tablou unidimensional, sau cel mai des, sub form de liste dinamice, n care ordinea
nodurilor este stabilit prin pointeri. Nodurile listelor dinamice sunt alocate n memoria heap.
Listele dinamice se numesc liste nlnuite, putnd fi simplu sau dublu nlnuite.
n continuare se vor prezenta principalele operaii asupra listelor simplu nlnuite.
Structura unui nod este urmtoarea:
3
b)
c)
b)
c)
if(q!=0)
{/*nodul de cheie key are adresa q */
if (q==prim)
{
p->urm=prim; prim=p;
}
else
{
q1->urm=p; p->urm=q;
}
}
d)
if(q->cheie==key) break;
q=q->urm;
}
d2) se insereaz nodul de adres p, fcnd legturile corespunztoare:
if (q !=)0)
{ /* nodul de cheie key are adresa q */
p -> urm = q -> urm;
q -> urm=p;
if (q == ultim) ultim = p;
}
Subiectul 4.
Liste simplu nlnuite. tergerea unui nod dintr-o list simplu nlnuit i tergerea
listei
Structura unui nod este urmtoarea:
typedef struct tip_nod
{
int cheie;
/* cmp neobligatoriu */
// alte cmpuri de date utile;
struct tip_nod *urm;
/* legtura spre urmtorul nod */
} TIP_NOD;
Pointerii prim i ultim vor fi declarai astfel:
TIP_NOD *prim, *ultim;
1. tergerea unui nod.
La tergerea unui nod se vor avea n vedere urmtoarele probleme: lista poate fi vid, lista
poate conine un singur nod sau lista poate conine mai multe noduri.
De asemenea se poate cere tergerea primului nod, a ultimului nod sau a unui nod dat
printr-o cheie key.
a) tergerea primului nod
TIP_NOD *p;
if(prim!=0)
{
/* lista nu este vid */
p=prim; prim=prim->urm;
elib_nod(p);
/*eliberarea spaiului de memorie */
if(prim==0) ultim=0;
/* lista a devenit vid */
}
7
if(prim==0) ultim=0;
/* lista a devenit vid */
}
-
Coada este o list simplu nlnuit, bazat pe algoritmul FIFO (First In First Out), adic
primul element introdus este primul scos. Modelul cozii care se are n vedere n consideraiile
urmtoare, este prezentat n fig.2.7.
Se introduce
un element
nou
p=prim; prim=prim->urm;
elib_nod(p);
/*eliberarea spaiului de memorie */
if(prim==0) ultim=0;
/* lista a devenit vid */
}
tergerea cozii funcia se realizeaz conform
TIP_NOD *p;
while( prim != 0)
{
p=prim; prim=prim->ultim;
elib_nod(p);
/*eliberare spaiu de memorie */
}
ultim=0;
Subiectul 6.
Liste circulare simplu nlnuite. Creare i acces la un nod.
Lista circular simplu nlnuit este lista simplu nlnuit a crei ultim element este legat
de primul element; adic ultim -> urm = prim.
n cadrul listei circulare simplu nlnuite nu exist capete. Pentru gestionarea ei se va folosi
un pointer ptr_nod, care adreseaz un nod oarecare al listei, mai precis ultimul introdus
(fig.2.8).
Ca i la lista simplu nlnuit, principalele operaii sunt:
crearea;
accesul la un nod;
inserarea unui nod;
tergerea unui nod,
tergerea listei.
int cheie;
/* nu este obligatoriu acest cmp */
/*cmpuri;*/
struct tip_nod *urm;
} TIP_NOD;
Crearea listei circulare simplu nlnuite
Iniial lista este vid:
ptr_nod = 0;
Introducerea n list a cte unui nod se va face astfel:
/* crearea nodului */
n = sizeof(TIP_NOD); /* dimensiunea nodului */
p = (TIP_NOD *)malloc(n); /* rezervarea memorie n heap
*/
citire date n nod la adresa p;
if (ptr_nod = = 0)
{ /* lista este vid */
ptr_nod = p;
ptr_nod -> urm = p;
}
else
{ /* lista nu este vid */
p -> urm = ptr_nod -> urm;
ptr_nod -> urm = p;
ptr_nod=p;
/* ptr_nod pointeaz la
ultimul nod inserat */
}
Accesul la un nod
Nodurile pot fi accesate secvenial plecnd de la nodul de pointer ptr_nod:
p=ptr_nod;
if(p! = 0)/* lista nu este vid */
do
{
acceseaaz nodul i preia informaia;
p = p -> urm;
}
while (p! = ptr_nod);
sau cutnd un nod de cheie dat key; n acest caz o funcie care va returna pointerul la nodul
gsit va conine urmtoarea secven de program:
p = ptr_nod;
if (p! = 0)
do
{
if ( p -> cheie == key)
{
/* s-a gsit nodul */
/* nodul are adresa p */
return p;
}
p = p -> urm;
}
while (p! = ptr_nod);
return 0;
Subiectul 7.
Liste circulare simplu nlnuite. Inserare i tergere nod i list.
Inserarea unui nod
Se pun urmtoarele probleme:
- inserarea naintea unui nod de cheie dat;
- inserarea dup un nod de cheie dat.
n ambele cazuri se caut nodul de cheie dat avnd adresa q; dac exist un astfel de nod,
se creeaz nodul de inserat de adres p i se fac legturile corespunztoare.
a) Inserarea naintea unui nod de cheie dat
- se caut nodul de cheie dat (adresa sa va fi q):
TIP_NOD *p,*q,*q1;
q = ptr_nod;
do
{
q1 = q; q = q -> urm;
if(q -> cheie == key ) break;
/* s-a gsit nodul */
}
while (q! = ptr_nod);
- se insereaz nodul de adres p;
if (q -> cheie == key)
{
q1 -> urm = p; p -> urm = q;
}
b) Inserarea dup un nod de cheie dat
- se caut nodul de cheie dat:
13
TIP_NOD *p,*q;
q = ptr_nod;
do
{
if (q -> cheie == key ) break;
q = q -> urm;
}
while(q!=ptr_nod);
- se insereaz nodul de adres p:
if (q -> cheie == key)
{
p -> urm =q -> urm;
q -> urm = p;
}
tergerea unui nod de cheie dat
tergerea unui nod de cheie dat key se va face astfel:
- se caut nodul de cheie dat:
q = ptr_nod;
do
{
q1 = q; q = q -> urm;
if (q -> cheie == key ) break;
/* s-a gsit nodul */
}
while (q! = ptr_nod);
- se terge nodul, cu meniunea c dac se terge nodul de pointer ptr_nod,
atunci ptr_nod va pointa spre nodul precedent q1:
if (q-> cheie == key)
{
if (q==q -> urm) ptr_nod==0;
/* lista a devenit vid */
else
{
q1 -> urm = q -> urm;
if (q == ptr_nod) ptr_nod = q1;
}
elib_nod(q);
}
14
tergerea listei
tergerea listei circulare simplu nlnuite se va face astfel:
p = ptr_nod;
do
{
p1 =p; p = p -> urm;
elib_nod(p1);
}
while (p! = ptr_nod);
ptr_nod = 0;
Subiectul 8.
Liste dublu nlnuite. Creare i acces la nod.
Lista dublu nlnuit este lista dinamic ntre nodurile creia s-a definit o dubl relaie:
de succesor si de predecesor. Modelul listei dublu nlnuite, pentru care se vor da explicaiile n
continuare, este prezentat n figura 2.10.
Figura 2.10. Modelul listei circulare dublu nlnuite
Tipul unui nod dintr-o list dublu nlnuit este definit astfel:
typedef struct tip_nod
{
cheie; /* nu este obligatoriu */
date;
struct tip_nod *urm;
/* adresa urmtorului nod */
struct tip_nod * prec;
/* adresa precedentului nod */
} TIP_NOD;
Ca i la lista simplu nlnuit, principalele operaii sunt:
crearea;
accesul la un nod;
inserarea unui nod;
tergerea unui nod,
15
tergerea listei.
Lista dublu nlnuit va fi gestionat prin pointerii prim i ultim:
TIP_NOD *prim, *ultim;
prim -> prec = 0;
ultim -> urm = 0;
Crearea unei liste dublu nlnuite
Iniial lista este vid:
prim = 0; ultim = 0;
Dup alocarea de memorie i citirea datelor n nod, introducerea nodului de pointer n
list se va face astfel:
if(prim= =0)
{ /* este primul nod n list */
prim = p; ultim = p;
p -> urm = 0; p -> prec = 0;
}
else
{
/* lista nu este vid */
ultim -> urm = p; p -> prec = ultim;
p -> urm = 0; p -> prec = ultim;
ultim = p;
}
Accesul la un nod
Accesul la un nod se poate face:
- secvenial nainte (de la prim spre ultim):
p = prim;
while (p != 0)
{
vizitare nod de pointer p;
p = p -> urm;
}
- secvenial napoi ( de la ultim spre prim):
p = ultim;
while (p != 0)
{
vizitare nod de pointer p;
p = p -> prec;
}
16
- pe baza unei chei; cutarea unui nod de cheie dat key se va face identic ca la lista
simplu nlnuit
TIP_NOD *p;
p=prim;
while( p != 0 )
if (p->cheie == key)
{
/* s-a gsit nodul de cheie dat el are adresa p */
return p;
}
else
p=p->urm;
return 0; /* nu exist nod de cheie = key */
Subiectul 9.
Liste dublu nlnuite. Inserare i tergere nod i list.
Inserarea unui nod ntr-o list dublu nlnuit se poate face astfel:
- naintea primului nod:
if (prim == 0)
{ /* lista este vid */
prim = p; ultim = p;
p -> urm = 0; p -> prec = 0;
}
else
{ /* lista nu este vid /*
p -> urm =prim; p -> prec = 0;
prim -> prec = p; prim = p;
}
- dup ultimul nod:
if (prim == 0)
{ /* lista este vid */
prim = p; ultim = p;
p -> urm = 0; p -> prec = 0;
}
else
{ /* lista nu este vid /*
p -> urm =0; p -> prec = ultim;
utim -> urm = p;
ultim = p;
}
- naintea unui nod de cheie dat key: dup cutarea nodului de cheie key,
presupunnd c acesta exist i are adresa q, nodul de adres p va fi inserat astfel:
p -> prec = q -> prec; p -> urm = q;
if (q -> prec != 0) q -> prec -> urm = p;
q -> prec = p;
if (q == prim) prim = p;
17
- dup un nod de cheie dat key: dup cutarea nodului de cheie key,
presupunnd c acesta exist i are adresa q, nodul de adres p va fi inserat astfel:
p -> prec = q; p -> urm = q -> urm;
if (q -> urm != 0) q -> urm -> prec = p;
q -> urm = p;
if (ultim == q) ultim = p;
tergerea unui nod
Exist urmtoarele cazuri de tergere a unui nod din list:
a) tergerea primului nod; acest lucru se poate face cu secvena de program:
p = prim;
prim = prim -> urm;
/* se consider list nevid */
elib_nod(p); /* eliberarea nodului */
if (prim == 0) ultim = 0;
/* lista a devenit vid */
else prim -> prec = 0;
b) tergerea ultimului nod:
p = ultim;
ultim = ultim -> prec;
/* se consider c lista nu este vid */
if (ultim == 0) prim = 0;
/* lista a devenit vid */
else ultim -> urm = 0;
elib_nod(p); /* tergerea nodului */
c) tergerea unui nod precizat printr-o cheie key. Presupunem c nodul de
cheie key exist i are adresa p (rezult din cutarea sa):
if ((prim == p) && (ultim = =p))
{ /* lista are un singur nod */
prim = 0;ultim = 0;
/*lista devine vid*/
elib_nod(p);/*tergere nod*
}
else if(p == prim)
{ /* se terge primul nod */
prim = prim -> urm; prim -> prec =0;
elib_nod(p);
}
else if (p == ultim)
{ /* se terge ultimul nod */
ultim = ultim -> prec;
ultim -> urm = 0;
elib_nod(p)
}
else
{/*nodul de ters este diferit de
capete */
p -> urm -> prec = p -> prec;
18
n0
y xn .
Drumul este simplu dac
x x0 , xk
x0 , x1 ,..., xn1
sunt distincte.
19
x , x ,..., x
xk 1
pentru
este un
0k n
A
C
nivelul 1
nivelul 2
F
G
nivelul 3
nivelul 4
A1
A2
a b
i (a b c) d
e
f
(1)
20
/
d
Fie
a1 ,..., am
a1 ,..., am
n acest ultim caz nu exist nici un drum de la p la q n arborele dat. n primul caz, fie
subarborele care conine nodul q.
Pasul P2:
ai , atunci fie p i
ai j .
p q.
subarborii lui
ai
p pi q .
rdcina lui i
ai ,
ai
Nodul q este o rdcin sau un nod diferit de rdcin ntr-unul din aceti
arbori.
Pasul P3:
Dup un numr finit de pai P1 i P2, avnd n vedere c arborele este o mulime
finit de puncte, se ajunge la situaia n care q este rdcina unui subarbore i atunci drumul de la
p la q este
p p1 pi j pi j L q .
k
Observaie.
Din algoritmul de construire a drumului de la nodul p la nodul q n arborele a rezult c
ntre cele dou noduri p i q ale unui arbore a exist cel mult un drum n subarborele respectiv.
21
Lungimea drumului, precum i nodurile lui p pot fi deduse cu ajutorul algoritmului matriceal,
asociind fiecrui arc lungimea 1.
Legenda variabilelor folosite n pseudocodul corespunztor algoritmului:
a = arborele n care se caut drumul;
p,q = cele dou noduri;
rad = nodul pentru care se determin subarborii;
drum[i] = ir care conine nodurile ce compun drumul;
nrnod = numrul de noduri ale drumului;
nod[i] = subarborele i al nodului rad;
T(nod[i]) = nodul rdcin al subarborelui i;
S(nod[i]) = mulimea tuturor nodurilor subarborelui i.
Pseudocodul corespunztor algoritmului precedent este urmtorul:
* citete
a, p, q;
rad = p;
nrnod = 1;
drum[nrnod] = p;
repet
*determin nod[1],,nod[m];
indice = 0;
pentru i = 1,m execut
dac q S (nod[i ]) atunci
indice = i
nrnod = nrnod + 1;
drum[nrnod] = T(nod[indice]);
rad = T(nod[indice]);
pn cnd q = rad
sfrit.
Subiectul 12.
Traversarea arborilor binari. Generaliti i exemple
Definiia 4.5.1. Un arbore binar poate fi definit ca fiind o mulime finit de noduri care
este fie vid, fie este format dintr-o tulpin (rdcin) i doi arbori binari.
Aceast definiie sugereaz o cale natural de a reprezenta arborii binari n codul
calculatoarelor.
22
Pot exista dou referine LLINK i RLINK n cadrul fiecrui nod i o variabil de tip
referin T care este un pointer de arbore. Dac un arbore este vid, atunci T ; n caz
contrar, T este adresa tulpinei arborelui, iar LLINK(T) i RLINK(T) sunt pointeri la arborele din
stnga, respectiv din dreapta tulpinei.
Aceste reguli definesc recursiv reprezentarea n memorie a oricrui arbore binar.
Traversarea unui arbore binar reprezint o metod de a examina nodurile unui arbore n
mod sistematic, astfel nct fiecare nod s fie vizitat o singur dat.
Exemplu:
A
C
B
D
--
--
F
--
A
23
/
e
Pasul 1
Pasul 2
Pasul 3
Pasul 4:
Pasul 5
(iniializare):
A (stabilire A vid)
P T.
(testeaz dac P ):
Dac P treci la Pasul 4 altfel treci la Pasul 3.
( P A ):
Se stabilete:
P A (se insereaz nodul P n stiva A)
LLINK(P) P
i se revine la Pasul 2.
Dac stiva este vid ( A ) atunci STOP.
Dac nu, se stabilete:
A P (nodul din vrful stivei trece n P).
(vizitarea lui P):
Se viziteaz NOD(P)
Se stabilete
RLINK(P) P
i se revine la Pasul 2.
codsf 1
altfel
*extrage (P,A);
*viziteaz (P);
P RLINK(P);
altfel
*insereaz (P,A);
P LLINK(P);
pn cnd codsf 1 ;
sfrit.
Traversarea unui arbore binar n preordine
Pentru a realiza un algoritm de treversare a unui arbore binar n preordine, se va face
urmtoarea modificare n algoritmul anterior: vizitarea nodului P se va face ntre paii P2 i P3,
i nu ntre paii P4 i P2.
25
Astfel, algoritmul scris n pseudocod pentru traversarea arborilor binari n preordine arat
astfel:
codsf 0;
va 1;
A(va) 1;
P T;
repet
dac
P 1 atunci
dac A(va ) 1 atunci
codsf 1
altfel
altfel
pn cnd
sfrit.
codsf 1 ;
Subarborii existeni imediat sub un nod oarecare al unui arbore formeaz un arbore.
Exist o cale naural de reprezentare a unei pduri ca un arbore binar; arborele binar se
obine prin legarea mpreun a fiilor fiecrei familii i se nltur legturile verticale, cu excepia
legturii de la tat la primul su fiu.
De exemplu, fie pdurea:
A
C
D
C
(a)
(b)
Figura 9.1 Un graf neorientat i unul din arborii si pariali
Pentru graful din figura 9.1(a), presupunnd c pornim din vrful 1 i c vizitm vecinii
unui vrf n ordine numeric, parcurgerea vrfurilor n adncime se face n ordinea: 1, 2, 3, 6, 5,
4, 7, 8.
Desigur, parcurgerea n adncime a unui graf nu este unic; ea depinde att de alegerea
vrfului iniial, ct i de ordinea de vizitare a vrfurilor adiacente. Ct timp este necesar pentru a
parcurge un graf cu n vrfuri i m muchii?
Deoarece fiecare vrf este vizitat exact o dat, avem n apeluri ale procedurii ad. n
procedura ad, cnd vizitm un vrf, testm marcajul fiecrui vecin al su. Dac reprezentm
graful prin liste de adiacen, adic prin ataarea la fiecare vrf a listei de vrfuri adiacente lui,
atunci numrul total al acestor testri este: m, dac graful este orientat, i 2m, dac graful este
neorientat. Algoritmul necesit un timp n (n) pentru apelurile procedurii ad i un timp n
(m) pentru inspectarea mrcilor. Timpul de execuie este deci n (max(m,n))=(m+n).
Dac reprezentm graful printr-o matrice de adiacen, se obine un timp de execuie n
2
(n ).
Parcurgerea n adncime a unui graf G, neorientat i conex, asociaz lui G un arbore
parial. Muchiile arborelui corespund muchiilor parcurse n G, iar vrful ales ca punct de plecare
devine rdcina arborelui. Pentru graful din figura 9.1(a), un astfel de arbore este reprezentat n
figura 9.1(b) prin muchiile continue; muchiile din G care nu corespund unor muchii ale
arborelui sunt ntrerupte. Dac graful G nu este conex, atunci parcurgerea n adncime asociaz
lui G o pdure de arbori, cte unul pentru fiecare component conex a lui G.
Dac dorim s i marcm numeric vrfurile n ordinea parcurgerii lor, adugm n
procedura ad, la nceput:
29
num
num + 1
preord[v] num
unde num este o variabil global iniializat cu zero, iar preord[1,..,n] este un tablou
care va conine n final ordinea de parcurgere a vfurilor. Pentru parcurgerea din exemplul
precedent, acest tablou devine:
1
Subiectul 16
Sortarea topologic. Parcurgerea grafurilor n lime
n aceast seciune, vom arta cum putem aplica parcurgerea n adncime a unui graf, ntrun procedeu de sortare esenial diferit fa de sortrile ntlnite pn acum. S presupunem c
reprezentm diferitele stagii ale unui proiect complex printr-un graf orientat aciclic: vrfurile sunt
strile posibile ale proiectului, iar muchiile corespund activitilor care se cer efectuate pentru a
trece de la o stare la alta.
Figura 9.2 d un exemplu al acestui mod de reprezentare. O sortare topologic a vrfurilor
unui graf orientat aciclic este o operaie de ordonare liniar a vrfurilor, astfel nct, dac exist o
muchie (i,j), atunci i apare naintea lui j n aceast ordonare.
C
preparat
cafea
A
trezire
B
duul
but
cafea
E
mbrcare
D
plecare
adiacente lui v etc. Spre deosebire de parcurgerea n adncime, parcurgerea n lime nu este n
mod natural recursiv.
Pentru a putea compara aceste dou tehnici de parcurgere, vom da pentru nceput o
versiune nerecursiv pentru procedura ad. Versiunea se bazeaz pe utilizarea unei stive.
Presupunem c avem funcia ftop care returneaz ultimul vrf inserat n stiv, fr s l tearg.
Presupunem date i funciile push (care adaug nodul v n stiva S) i pop (care terge ultimul
nod din stiv i l returneaz).
procedure iterad(v)
S stiva vida
marca[v] vizitat
push(v,S)
while S nu este vida do
while exista un varf w adiacent lui ftop(S)
astfel incat marca[w] = nevizitat do
marca[w] vizitat
push(w,S)
pop(S)
Pentru parcurgerea n lime, vom utiliza o coad i funciile insert-queue (adaug
nodul v n capul cozii C), delete-queue (terge nodul din coada listei i l returneaz).
Iat acum algoritmul de parcurgere n lime:
procedure lat(v)
C
coada vida
marca[v] vizitat
insert-queue(v,C)
while C nu este vida do
u delete-queue(C)
for fiecare vrf w adiacent lui u do
if marca[w] = nevizitat then
marca[w]
vizitat
insert-queue(w, C)
Procedurile iterad i lat trebuie apelate din procedura:
procedure parcurge(G)
for fiecare vV do marca[v] nevizitat
for fiecare vV do
if marca[v]=nevizitat then
{iterad sau lat}(v)
De exemplu, pentru graful din figura 9.1, ordinea de parcurgere n lime a vrfurilor este:
1,2,3,4,5,6,7,8.
Ca i n cazul parcurgerii n adncime, parcurgerea n lime a unui graf G conex asociaz
lui G un arbore parial. Dac G nu este conex, atunci obinem o pdure de arbori, cte unul pentru
fiecare component conex.
Analiza eficienei algoritmului de parcurgere n lime se face la fel ca pentru parcurgerea
n adncime. Pentru a parcurge un graf cu n vrfuri i m muchii timpul este n:
i)
(m+n), dac reprezentm graful prin liste de adiacen;
ii)
(n2), dac reprezentm graful printr-o matrice de adiacen.
Parcurgerea n lime este folosit de obicei atunci cnd se exploareaz parial anumite
grafuri infinite, sau cnd se caut cel mai scurt drum dintre dou vrfuri.
31
Subiectul 17
Grafuri AND/OR
Multe probleme se pot descompune ntr-o serie de subprobleme, astfel nct rezolvarea
tuturor acestor subprobleme, sau a unora din ele, s duc la rezolvarea problemei iniiale.
Descompunerea unei probleme complexe, n mod recursiv, n subprobleme mai simple poate fi
reprezentat printr-un graf orientat. Aceast descompunere se numete reducerea problemei i
este folosit n demonstrarea automat, integrarea simbolic i, n general, n inteligena
artificial. ntr-un graf orientat de acest tip vom permite unui vrf oarecare neterminal v dou
alternative.
Vrful v este de tip AND dac reprezint o problem care este rezolvat doar dac toate
subproblemele reprezentate de vrfurile adiacente lui v sunt rezolvate. Vrful v este de tip OR
dac reprezinta o problem care este rezolvat doar dac cel puin o subproblem reprezentat de
vrfurile adiacente lui v este rezolvat. Un astfel de graf este de tip AND/OR.
De exemplu, arborele AND/OR din figura 9.5 reprezint reducerea problemei A. Vrfurile
terminale reprezint probleme primitive, marcate ca rezolvabile (vrfurile albe), sau
nerezolvabile (vrfurile galbene). Vrfurile neterminale reprezint probleme despre care nu se
tie a priori dac sunt rezolvabile sau nerezolvabile.
A
a
C
E
D
F
if v este rezolvabil
32
Dac n timpul explorrii se poate deduce c un vrf este rezolvabil sau nerezolvabil, se
abandoneaz explorarea descendenilor si. Printr-o modificare simpl, algoritmul sol poate afia
strategia de rezolvare a problemei reprezentate de u, adic subproblemele rezolvabile care
conduc la rezolvarea problemei din u.
Cu anumite modificri, algoritmul se poate aplica asupra grafurilor AND/OR oarecare.
Similar cu tehnica backtracking, explorarea se poate face att n adncime (ca n algoritmul sol),
ct i n lime.
Subiectul 19
Sortarea prin numrare
Aceast metod se bazeaz pe ideea c, n secvena final sortat a " j " a cheie este mai
mare dect a " j 1" a din celelalte chei. Metoda const n compararea fiecrei perechi de chei,
numrnd cte vor fi mai mici dect fiecare cheie particular. Calea evident de a face
comparaiile const n: compar K j cu K i , pentru j 1,i
N
1,i N .
Se observ ns c peste jumtate din aceste comparaii sunt redundante, nefiind necesar a
Kb
Ka .
se compara o cheie cu ea nsi i apoi nu e necesar s se compare K a cuiK b cu
Vom avea nevoie numai de a compara K j cu K i , pentru j 1, N
conduce la urmtorul algoritm:
i i 1, N . Aceasta
R j .
scrie (COUNT(i), i 1, N )
sfrit.
Dac vom considera c pentru execuia fiecrei operaii este necesar o unitate de timp
calculator, atunci timpul total de rulare al acestui program va fi:
T 2 N 2 5N 2 .
Factorul N care apare n relaia de mai sus arat c algoritmul de sortare prin numrare nu
este o cale eficient n cazul n care N este mare.
Deoarece metoda solicit compararea tuturor perechilor de chei distincte
K , K , nu
i
egale cu i)
pune COUNT(i) COUNT(i)+COUNT i 1 pentru
i u 1,..., v.
pune i COUNT K j
Si R j
COUNT K j i 1 .
Subiectul 20
Sortarea prin inserie
nainte de a examina nregistrarea R j vom considera c nregistrrile precedente
R1 ,..., R j 1
R j n locul ce-i
au fost deja sortate, apoi vom insera
revine ntre nregistrrile sortate anterior.
Inseria direct
Sortarea cea mai simpl prin inserie este i cea mai evident. Se consider 1 j N i
nregistrrile precedente R1 ,..., R j 1 aranjate astfel nct:
K1 ... K j 1 .
Vom compara pe rnd noua cheie K j cu K j 1 , K j 2 ,... , pn vom descoperi c K j
trebuie inserat ntre nregistrrile Ri i Ri 1 ; apoi deplasm nregistrrile Ri 1 ,..., R j 1 cu un
spaiu i introducem noua nregistrare n poziia Ri 1 . Din cele descrise anterior obinem:
Algoritmul 5.1.4.1. Sortarea prin inserie direct
nregistrrile R1 ,..., Rn sunt rearanjate pe locurile lor; dup sortare, cheile vor fi n
ordinea K1 ... K n .
Pasul P1: (cicleaz dup j):
Execut paii P2-P5 pentru j = 2,...,N, apoi termin algoritmul.
Pasul P2: (Fixeaz i, k, r):
Pune
i j 1
K Kj
R R j.
poziia
corect,
scrie K L , L 1,..., j ;
i j 1;
K K j ;
repet
dac K K i atunci
K i 1 K i ;
i i 1;
pn cnd i = 0 sau K K i ;
K i 1 K ;
sfrit.
Analiza stocastic a algoritmului
Presupunnd c pentru fiecare operaie este necesar o unitate de timp calculator, timpul total de
rulare a acestei rutine este:
T 1 6 N 1 3B B N 1 A 7 N 4 B A 6 u.t., unde:
A = numrul de cazuri n care i descrete la zero;
B = numrul de deplasri ale nregistrrii cu un pas; B este egal cu numrul de inversiuni
ale permutrii:
1
K
1
2 ... N
.
K 2 ... K N
min A 0 ;
n
1
Hn ;
k 1 k
max A N 1 ;
med A H N 1 ;
dis A
HN HN2 ;
max B C2N
med B
N N 1
pentru K1 ,..., K N ordonate cresctor;
2
N N 1
;
4
dis B
36
N N 1 2 N 5
.
72
T 7N 4
N N 1
H N 1 6 N 2 6N H N 5 .
4
1) parcurgerea unui fiier ordonat pentru a gsi cea mai mare cheie, mai mare sau egal
cu o cheie dat;
2) inserarea unei nregistrri noi ntr-o anumit parte a fiierului ordonat.
Fiierul este, evident, o list liniar i algoritmul de sortare prin inserie direct
(algoritmul 5.1.4.1) va manipula aceast list utiliznd alocarea secvenial.
n concluzie, structura adecvat de date pentru inserie direct este o list liniar cu
legturi, unidirecional. Este convenabil s revedem algoritmul menionat mai sus, astfel ca lista
s fie parcurs n ordine cresctoare.
Astfel, vom obine algoritmul urmtor:
Algoritmul 5.1.4.3. Inserii de liste
Se consider c nregistrrile R1 ,..., RN conin cheile K1 ,..., K N i cmpurile de
legtur L1,..., LN , capabile de a conine numere de 0 la n. Exist un cmp de legtur L0
ntr-o nregistrare K 0 , artificial, la nceputul fiierului. Algoritmul va fixa cmpurile de
legtur, astfel nct nregistrrile s fie legate n ordine ascendent. Astfel, dac
p 1 ,..., p N este o permutare stabil care ordoneaz K p 1 ,..., K p N , acest algoritm
va da:
L0 p 1
Lp i p i 1 , i 1, N 1
Lp N 0.
K1 ... K N .
39
max ( K1 ,..., K j ) K i ) :
cheile
K j , K j 1 ,..., K1
cea
mai
mare
dintre
ele
4
4
6
2
5
5
2
6
7
7
8
8
Subiectul 24
Sortarea prin interclasare
Interclasarea (sau colaionarea) nseamn combinarea a dou sau mai multe fiiere ntr-un singur
fiier ordonat.
Observaie. Cnd unul din fiiere este epuizat este necesar ceva mai mult atenie.
De exemplu putem interclasa dou fiiere :
pentru a obine:
087 503
512
677
703
765 .
K K 1
i i 1.
K K 1
j j 1.
42
De notat c, cu excepia nodurilor externe, numerele din cei doi descendeni ai fiecrui
nod intern difer de numrul nodului printe prin aceeai valoare i aceast valoare este un numr
Fibonacci.
Astfel, din figur:
5 8i
F11
8 F4 .
4
Cnd diferena este F j , diferena Fibonacci corespunztoare pentru urmtoarea
ramificaie la stnga este F j 1 , n timp ce pentru ramificaia la dreapta este F j 2 . De exemplu:
3 5 F3 , iar 10 11 F2 .
Aceste observaii conduc la urmtorul algoritm:
Algoritmul 5.2.6.1
Fiind dat un tabel de nregistrri R1 ,..., RN ale cror chei sunt n ordine cresctoare
K1 , , K N , acest algoritm caut nregistrarea cu cheia dat K.
Pentru uurina calculelor, vom presupune c N + 1 este un numr
Fibonacci FK 1 . Nu este dificil de observat c metoda lucreaz corect pentru N arbitrar, dac se
realizeaz o iniializare corespunztoare.
Pasul P1: (iniializare):
Se stabilete
i FK
p FK 1
q FK 2
p pq
qq p
K l i K u se poate alege
circa K K l / K u K l
urmtorul element de
distana ntre
i u,
presupunnd c cheile sunt numerice i c ele cresc n general n interval n mod constant.
Experimentele de simulare cu calculatorul arat urmtoarele: cutarea prin interpolare nu
micoreaz numrul de comparaii suficient de mult pentru a compensa timpul de calcul
suplimentar necesar n cazul cutrii ntr-un tabel memorat ntr-o oarecare msur. Metoda s-a
dovedit
eficient
numai
ntr-o
oarecare msur, cnd cutarea a fost o cutare extern, folosind o unitate de memorie.
n paragrafele anterioare s-a constatat c o structur implicit de arbore binar uureaz
nelegerea comportrii cutrii binare i a cutrii de tip Fibonacci. Metodele prezentate anterior
sunt adecvate pentru tabelele de dimensiuni fixe, deoarece alocarea succesiv a nregistrrilor
complic operaiile de cutare i tergere.
Dac tabelul se modific dinamic, am pierde mai mult timp pentru ntreinerea lui dect
am economisi n cazul cutrii binare.
Utilizarea unei structuri de arbore binar explicit
Aceasta face posibil inserarea i tergerea rapid din nregistrri, precum i cutarea
eficient a tabelului. n consecin, dispunem de o metod eficient att pentru cutare, ct i
pentru sortare. Acest ctig n flexibilitate se realizeaz prin adugarea la fiecare nregistrare din
tabel a dou cmpuri suplimentare de legturi.
Algoritmul 5.2.8.1
Fiind dat un tabel de nregistrri care formeaz un arbore binar descris ca mai sus,
algoritmul caut nregistrarea cu o anumit cheie K. Dac K nu se gsete n tabel, se insereaz n
arbore la locul potrivit un nod ce conine cheia K. Presupunem c nodurile arborelui conin cel
puin urmtoarele cmpuri:
- CHEIE(P) = cheia nregistrrii n NOD(P);
- LLINK(P) = adresa de legtur la subarborele din stnga lui NOD(P);
- RLINK(P) = adresa de legtur la subarborele din dreapta lui NOD(P).
Subarborii noduri extreme (vizi) sunt reprezentai prin adresa de legtur nul . Variabila
ROOT face legtura la tulpina arborelui. Vom presupune c arborele nu este vid (ROOT ).
Pasul P1: (iniializarea):
Se stabilete P ROOT
(Variabila de legtur P se va deplasa de-a lungul arborelui).
Pasul P2: (comparare):
Dac K < CHEIE(P), se trece la pasul P3.
Dac K > CHEIE(P), se trece la pasul P4.
Dac K = CHEIE(P), cutarea se termin cu succes.
Pasul P3: (deplasarea spre stnga):
Dac LLINK(P) se stabilete
P LLINK(P) i se revine la pasul P2.
n caz contrar, se trece la pasul P5.
Pasul P4: (deplasare spre dreapta):
47
48
Figura 5.8. Schema corespunztoare algoritmului ce utilizeaz structuri de arbore binar explicit
(adugare)
Subiectul 31
METODA GREEDY
Algoritmii greedy (greedy = lacom) sunt n general simpli i sunt folosii la probleme de
optimizare, cum ar fi: s se gseasca cea mai bun ordine de executare a unor lucrri pe
calculator, s se gseasca cel mai scurt drum ntr-un graf etc. n cele mai multe situaii de acest
fel avem:
o multime de candidai (lucrri de executat, vrfuri ale grafului etc);
o funcie care verific dac o anumit mulime de candidai constituie o soluie posibil, nu
neaparat optim, a problemei;
o funcie care verific dac o mulime de candidai este fezabil, adic dac este posibil s
completm aceast mulime astfel nct s obinem o soluie posibil, nu neaprat optim, a
problemei;
o funcie de selecie care indic la orice moment care este cel mai promitor dintre candidaii
nc nefolosii;
o funcie obiectiv care dvaloarea unei soluii (timpul necesar executrii tuturor lucrrilor ntro anumit ordine, lungimea drumului pe care l-am gsit etc); aceasta este funcia pe care urmrim
s o optimizm (minimizm/maximizm).
Pentru a rezolva problema noastr de optimizare, cutam o soluie posibil care s
optimizeze valoarea funciei obiectiv. Un algoritm greedy construiete soluia pas cu pas. Iniial,
mulimea candidailor selectai este vid. La fiecare pas, ncercam s adugm acestei mulimi cel
mai promitor candidat, conform funciei de selecie. Dac, dup o astfel de adugare, mulimea
de candidai selectai nu mai este fezabil, eliminm ultimul candidat adugat; acesta nu va mai fi
niciodat considerat. Dac, dup adugare, mulimea de candidai selectai este fezabil, ultimul
candidat adugat va rmne de acum ncolo n ea. De fiecare dat cnd lrgim mulimea
candidailor selectai, verificm dac aceast mulime nu constituie o soluie posibil a problemei
noastre. Dac algoritmul greedy funcioneaz corect, prima soluie gsit va fi totodat o soluie
optim a problemei. Soluia optim nu este n mod necesar unic: se poate ca funcia obiectiv s
aib aceeai valoare optim pentru mai multe soluii posibile.
Algoritmii de tip greedy, backtracking i de programare dinamic se aplic unor probleme a
cror soluie poate fi exprimat sub forma unui vector sau unei matrice de numere (de obicei
ntregi cu valori ntr-un subdomeniu limitat).
Exemple de probleme cu soluie vectorial i matricial:
- Problema restului: O sum de bani trebuie pltit cu un numr minim de monede de
valori cunoscute. Vectorul soluie conine numrul de monede de fiecare valoare disponibil.
- Problema colorrii nodurilor unui graf cu numr minim de culori. Vectorul soluie are
attea componente cte noduri sunt n graf, iar valoarea fiecrei componente este codul unei
culori.
Problemele menionate sunt probleme de optimizare, n care trebuie gsit soluia optim
dintre toate soluiile posibile. Alte clase de probleme cu soluie vectorial sunt probleme de
enumerare a tuturor soluiilor posibile i probleme de decizie, la care trebuie spus dac exist sau
nu cel puin o soluie.
Prezentarea metodei Greedy
49
1
10
20
2.0
2
3
6
8
10
12
1.66 1.5
Soluia greedy spune c trebuie selectat obiectul 1, valoarea seleciei fiind 20. Vectorul
x[1]=1, x[2]=0, x[3]=0
Soluia optim este cea care ia obiectele 2 i 3, cu valoarea total 22 i greutatea total 14:
x[1]=0, x[2]=1, x[3]=1
51
t t
i a ib
Folosim urmtorul algoritm greedy: alegem o culoare i un vrf arbitrar de pornire, apoi
considerm vrfurile rmase, ncercnd s le colorm, fr a schimba culoarea. Cnd nici un vrf
nu mai poate fi colorat, schimbm culoarea i vrful de start, repetnd procedeul.
muchia de cost minim nealeasa anterior i care nu formeaza cu precedentele un ciclu. Alegem
astfel X1 muchii. Este usor de dedus ca obinem n final un arbore. Este nsa acesta chiar
arborele partial de cost minim cautat?
nainte de a raspunde la ntrebare, sa consideram, de exemplu, graful din Figura 6.1.a. Ordonam
crescator (n functie de cost) muchiile grafului: {1, 2}, {2, 3}, {4, 5}, {6, 7}, {1, 4}, {2, 5},
{4, 7}, {3, 5}, {2, 4}, {3, 6}, {5, 7}, {5, 6} i apoi aplicam algoritmul. Structura componentelor
conexe este ilustrata, pentru fiecare pas, n Tabelul 1.
Pasul
Initializare
{1, 2}
{2, 3}
{4, 5}
{6, 7}
{1, 4}
{2, 5}
{4, 7}
{1, 2, 3, 4, 5, 6, 7}
54
Muchia considerata
W
{1}
{2, 1}
{1, 2}
{3, 2}
{1, 2, 3}
{4, 1}
{1, 2, 3, 4}
{5, 4}
{1, 2, 3, 4, 5}
{7, 4}
{1, 2, 3, 4, 5, 6}
{6, 7}
{1, 2, 3, 4, 5, 6, 7}
Tabelul 6.2 Algoritmul lui Prim aplicat grafului din Figura 6.1a.
55
56