Sunteți pe pagina 1din 334

C

1. Tehnici de programare

I
OG
1.1. Analiza algoritmilor
Prin analiza unui algoritm se identific resursele necesare pentru executarea

AG
algoritmului: timpul de execuie i memoria.
Analiza algoritmilor este necesar atunci cnd exist mai muli algoritmi pentru rezolvarea
aceleiai probleme i trebuie ales algoritmul cel mai eficient.

ED
Eficiena unui algoritm este evaluat prin timpul necesar pentru executarea
algoritmului.
Pentru a compara din punct de vedere al eficienei doi algoritmi care rezolv aceeai
problem, se folosete aceeai dimensiune a datelor de intrare n (acelai numr de

P
valori pentru datele de intrare).
Timpul de execuie al algoritmului se exprim prin numrul de operaii de baz
I
executate n funcie de dimensiunea datelor de intrare: T(n).
Pentru a compara doi algoritmi din punct de vedere al timpului de execuie, trebuie s se stabi-
leasc unitatea de msur care se va folosi, adic operaia de baz executat n cadrul algorit-

milor, dup care, se numr de cte ori se execut operaia de baz n cazul fiecrui algoritm.
IC

Operaia de baz este o operaie elementar sau o succesiune de operaii


elementare, a cror execuie nu depinde de valorile datelor de intrare.
CT

Exist algoritmi la care timpul de execuie depinde de distribuia datelor de intrare. S


considerm doi algoritmi de sortare a unui vector cu n elemente algoritmul de sortare
prin metoda seleciei directe i algoritmul de sortare prin metoda bulelor i ca operaie
de baz comparaia. Dac, n cazul primului algoritm, timpul de execuie nu depinde de
DA

distribuia datelor de intrare (modul n care sunt aranjate elementele vectorului nainte de
n (n 1)
sortarea lui), el fiind T(n) = , n cazul celui de al doilea algoritm timpul de exe-
2
cuie depinde de distribuia datelor de intrare (numrul de execuii ale structurii repetitive
DI

while depinde de modul n care sunt aranjate elementele vectorului nainte de sortare). n
cazul n care numrul de execuii ale operaiilor elementare depinde de distribuia datelor
de intrare, pentru analiza algoritmului se folosesc:
timpul maxim de execuie timpul de execuie pentru cazul cel mai nefavorabil de
RA

distribuie a datelor de intrare; n cazul sortrii prin metoda bulelor, cazul cel mai
nefavorabil este atunci cnd elementele vectorului sunt aranjate n ordine invers
dect aceea cerut de criteriul de sortare;
timpul mediu de execuie media timpilor de execuie pentru fiecare caz de
TU

distribuie a datelor de intrare.


Deoarece, n analiza eficienei unui algoritm, se urmrete comportamentul lui pentru o
dimensiune mare a datelor de intrare, pentru a compara doi algoritmi din punct de vedere
I

al eficienei, este suficient s se ia n considerare numai factorul care determin timpul de


ED

execuie i care este denumit ordinul de complexitate.


4 Tehnici de programare

C
Ordinul de complexitate al unui algoritm l reprezint timpul de execuie estimat
prin ordinul de mrime al numrului de execuii ale operaiei de baz: O((f(n)), unde
f(n) reprezint termenul determinant al timpului de execuie T(n).

I
OG
De exemplu, dac pentru algoritmul de sortare, prin metoda seleciei directe timpul de
n (n 1) n 2 n
execuie este T(n) = , ordinul de complexitate al algoritmului este
2 2 2
2
O(n ), deoarece n calcularea lui se ia n considerare numai factorul determinant din

AG
timpul de execuie.
n funcie de ordinul de complexitate, exist urmtoarele tipuri de algoritmi:
Ordin de Tipul algoritmului

ED
complexitate
O(n) Algoritm liniar.
m Algoritm polinomial. Dac m=2, algoritmul este ptratic, iar dac
O(n )
m=3, algoritmul este cubic.
n n

P
Algoritm exponenial. De exemplu: 2 , 3 etc. Algoritmul de tip O(n!)
O(kn) este tot de tip exponenial, deoarece:
n-1
1234...n > 222...2 = 2 .
I
O(logn) Algoritm logaritmic.
O(nlogn) Algoritm liniar logaritmic.
De exemplu, algoritmul de sortare prin metoda seleciei directe este un algoritm ptratic.

Ordinul de complexitate este determinat de structurile repetitive care se execut cu muli-


IC

mea de valori pentru datele de intrare. n cazul structurilor repetitive imbricate, ordinul de
complexitate este dat de produsul dintre numrul de repetiii ale fiecrei structuri repetitive.
Structura repetitiv Numrul de execuii ale Tipul
CT

corpului structurii algoritmului


for (i=1;i=n;i=i+k) {....} f(n)=n/k O(n)=n Liniar
for (i=1;i=n;i=i*k) {....} f(n)= logkn O(n)= logn Logaritmic
for (i=n;i=n;i=i/k) {....} f(n)= logkn O(n)= logn Logaritmic
DA

for (i=n;i=n;i=i+p) {....} f(n)=(n/p)*(n/q) = n2/(p*q) Polinomial


for (j=n; j=n;j=j+q) {....} O(n)= n2 ptratic
for (i=n;i=n;i=i++) {....} f(n)=1+2+3+ ... +n =(n*(n+1))/2 Polinomial
for (j=i; j=n;j=j++) {....} O(n)= n2 ptratic
DI

Determinai complexitatea urmtorilor algoritmi i precizai tipul algoritmului.


Tem Pentru fiecare algoritm se va considera dimensiunea datelor de intrare n.
a. determinarea valorii minime dintr-un ir de numere;
RA

b. inserarea unui element ntr-un vector, dup un element cu valoare precizat;


c. tergerea dintr-un vector a unui element cu valoare precizat,
d. stabilirea dac un ir de numere conine numai numere distincte;
e. sortarea unui vector folosind metoda bulelor;
TU

f. cutarea unui element cu valoare precizat, ntr-un vector nesortat;


g. cutarea unui element cu valoare precizat, ntr-un vector sortat;
h. determinarea tuturor permutrilor unei mulimi de numere.
I
ED
Informatic 5

C
1.2. Metode de construire a algoritmilor
n funcie de procesul de calcul necesar pentru rezolvarea unei probleme, exist urmtoarele

I
clase de probleme:

OG
Clase de probleme

Probleme de enumerare Probleme de decizie Probleme de optimizare

AG
prin care se gsesc toate prin care se precizeaz dac prin care se identific soluia
soluiile posibile exist sau nu cel puin o optim din mulimea de soluii
soluie posibile

ED
Generarea tuturor permutrilor unei mulimi de numere este o problem de enumerare, cuta-
rea unei valori precizate ntr-un ir de numere este o problem de decizie, iar gsirea modalitii
de plat a unei sume s cu un numr minim de bancnote de valori date este o problem de
optimizare.

P
Pentru rezolvarea aceleiai probleme se pot folosi mai multe metode de construire a
algoritmilor. Ai nvat deja c pentru rezolvarea aceleiai probleme putei folosi un:
algoritm iterativ;
I
algoritm recursiv.
Soluiile recursive sunt mult mai clare, mai scurte i mai uor de urmrit. Alegerea
algoritmului recursiv n locul celui iterativ este mai avantajoas n cazul n care soluiile

problemei sunt definite recursiv sau dac cerinele problemei sunt formulate recursiv.
IC

Timpul de execuie a unui algoritm recursiv este dat de o (1) pentru n=0
formul recursiv. De exemplu, pentru algoritmul de T(n) =
calculare a sumei primelor n numere naturale, funcia (1)+T(n-1) pentru n0
CT

pentru timpul de execuie este prezentat alturat, unde


(1) reprezint timpul de execuie a unei operaii elementare de atribuire a unei valori
sumei. Rezult c T(n)=(n+1)(1), iar ordinul de complexitate a algoritmului este O(n) la
fel ca i cel al algoritmului iterativ. n cazul implementrii recursive, fiecare apel al unui
DA

subprogram recurent nseamn nc o zon de memorie rezervat pentru execuia sub-


programului (variabilele locale i instruciunile). Din aceast cauz, n alegerea ntre un
algoritm iterativ i un algoritm recursiv trebuie inut cont nu numai de ordinul de complexi-
tate, dar i de faptul c, pentru o adncime mare a recursivitii, algoritmii recursivi nu
DI

mai sunt eficieni, deoarece timpul de execuie crete, din cauza timpilor necesari pentru
mecanismul de apel i pentru administrarea stivei de sistem.
Vei nva noi metode de construire a algoritmilor care v ofer avantajul c prezint
RA

fiecare o metod general de rezolvare care se poate aplica unei clase de probleme:
metoda backtracking;
metoda divide et impera;
metoda greedy;
TU

metoda programrii dinamice.


Fiecare dintre aceste metode de construire a algoritmilor se poate folosi pentru anumite clase
de probleme, iar n cazul n care pentru aceeai clas de probleme se pot folosi mai multe
metode de construire a algoritmilor, criteriul de alegere va fi eficiena algoritmului.
I
ED
6 Tehnici de programare

C
1.3. Metoda backtracking
1.3.1. Descrierea metodei backtracking

I
OG
Metoda backtracking se poate folosi pentru problemele n care trebuie s se genereze toate
soluiile, o soluie a problemei putnd fi dat de un vector:
S = {x1, x2, , xn}
ale crui elemente aparin, fiecare, unor mulimi finite Ai (xiAi), iar asupra elementelor

AG
unei soluii exist anumite restricii specifice problemei care trebuie rezolvat, numite
condiii interne. Mulimile Ai sunt mulimi ale cror elemente sunt n relaii bine stabilite.
Mulimile Ai pot s coincid sau nu. Pentru a gsi toate soluiile unei astfel de probleme
folosind o metod clasic de rezolvare, se execut urmtorul algoritm:

ED
PAS1. Se genereaz toate elementele produsului cartezian A1 A2 A3 An.
PAS2. Se verific fiecare element al produsului cartezian, dac ndeplinete condiiile
interne impuse ca s fie soluie a problemei.

P
Scop: identificarea problemelor pentru care trebuie enumerate toate soluiile, fiecare
I
soluie fiind format din n elemente xi, care aparin fiecare unor mulimi finite Ai i care
trebuie s respecte anumite condiii interne.
Enunul problemei 1: S se genereze toate permutrile mulimii {1, 2, 3}.

Cerina este de a enumera toate posibilitile de generare a 3 numere naturale din


mulimea {1, 2, 3}, astfel nct numerele generate s fie distincte (condiia intern a solu-
IC

iei). O soluie a acestei probleme va fi un vector cu 3 elemente: S = {x1,x2,x3}, n care


elementul xi reprezint numrul care se va gsi, n permutare, pe poziia i, iar mulimea Ai
reprezint mulimea numerelor din care se va alege un numr pentru poziia i. n acest
CT

exemplu, mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element reprezentnd un


numr. Ai = {1, 2, 3} = A
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 A2 A3 = A A A = A3, adic mulimea:
DA

{(1,1,1), (1,1,2), (1,1,3), (1,2,1), , (3,3,2), (3,3,3)}


dup care se va verifica fiecare element al mulimii dac este o soluie a problemei, adic
dac cele trei numere dintr-o soluie sunt distincte. Soluiile obinute sunt:
DI

{(1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1)}


Enunul problemei 2: S se genereze toate aranjamentele de 2 elemente ale mulimii {1, 2, 3}.
Cerina este de a enumera toate posibilitile de generare a 2 numere naturale din
mulimea {1, 2, 3}, astfel nct numerele generate s fie distincte (condiia intern a solu-
RA

iei). O soluie a acestei probleme va fi un vector cu 2 elemente: S = {x1,x2}, n care


elementul xi reprezint numrul care se va gsi n aranjament pe poziia i, iar mulimea Ai
reprezint mulimea numerelor din care se va alege un numr pentru poziia i. i n acest
exemplu, mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element reprezentnd un
TU

numr. Ai = {1, 2, 3} = A
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 A2 = A A = A2, adic mulimea:
I

{(1,1), (1, 2), (1,3), (2,1), , (3,2), (3,3)}


ED
Informatic 7

C
dup care se va verifica fiecare element al mulimii, dac este o soluie a problemei,
adic dac cele dou numere dintr-o soluie sunt distincte. Soluiile obinute sunt:
{(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)}

I
Enunul problemei 3: S se genereze toate combinrile de 2 elemente ale mulimii {1, 2, 3}.

OG
Cerina este de a enumera toate posibilitile de generare a 2 numere naturale din muli-
mea {1,2,3}, astfel nct numerele generate s fie distincte (condiia intern a soluiei),
iar soluiile obinute s fie distincte. Dou soluii sunt considerate distincte dac nu conin
aceleai numere. O soluie a acestei probleme va fi un vector cu 2 elemente: S = {x1,x2},

AG
n care elementul xi reprezint numrul care se va gsi n combinare pe poziia i, iar muli-
mea Ai reprezint mulimea numerelor din care se va alege un numr pentru poziia i. i n
acest exemplu, mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element repre-
zentnd un numr. Ai = {1, 2, 3} = A

ED
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 A2 = A A = A2, adic mulimea:
{(1,1), (1, 2), (1,3), (2,1), , (3,2), (3,3)}

P
dup care se va verifica fiecare element al mulimii dac este o soluie a problemei, adic
dac cele dou numere dintr-o soluie sunt distincte i dac soluia obinut este distinct
de soluiile obinute anterior. Soluiile obinute sunt: {(1,2), (1,3), (2,3)}
I
Enunul problemei 4: S se genereze toate permutrile mulimii {1,2,3,4} care ndeplinesc
condiia c 1 nu este vecin cu 3, i 2 nu este vecin cu 4.
Cerina este de a enumera toate posibilitile de generare a 4 numere naturale din mulimea

{1, 2, 3, 4}, astfel nct numerele generate s fie distincte, iar 1 s nu se nvecineze cu 3, i 2
s nu se nvecineze cu 4 (condiia intern a soluiei). O soluie a acestei probleme va fi un
IC

vector cu 4 elemente: S = {x1,x2,x3,x4}, n care elementul xi reprezint numrul care se va


gsi n permutare pe poziia i, iar mulimea Ai reprezint mulimea numerelor din care se va
alege un numr pentru poziia i. n acest exemplu, mulimile Ai coincid. Ele au aceleai 4
CT

elemente, fiecare element reprezentnd un numr. Ai = {1, 2, 3, 4} = A


Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 A2 A3 A4 = A A A A = A4, adic mulimea:
DA

{(1,1,1,1), (1,1,1,2), (1,1,1,3), (1,1,1,4), ,(4,4,4,3), (4,4,4,4)}


dup care se va verifica fiecare element al mulimii dac este o soluie a problemei, adic
dac cele patru numere dintr-o soluie sunt distincte i dac 1 nu se nvecineaz cu 3, iar
2 cu 4. Soluiile obinute sunt:
DI

{(1,2,3,4), (1,4,3,2), (2,1,4,3), (2,3,4,1), (3,2,1,4), (3,4,1,2), (4,1,2,3), (4,3,2,1)}


Enunul problemei 5: S se aranjeze pe tabla de ah opt dame care nu se atac ntre
ele (problema celor 8 dame).
RA

Cerina este de a enumera toate posibilitile de aranjare a 8 dame pe o tabl de ah cu


dimensiunea 8x8 (8 linii i 8 coloane), astfel nct toate cele 8 dame s nu se atace ntre ele
(condiia intern a soluiei). Deoarece nu se pot aranja dou dame pe aceeai coloan (s-ar
ataca ntre ele), nseamn c pe fiecare coloan a tablei de ah se va pune o dam. O soluie
TU

a acestei probleme va fi un vector cu 8 elemente, S = {x1,x2,x3,x4,x5,x6,x7,x8}, n care


elementul xi reprezint numrul liniei pe care se va pune dama n coloana i, iar mulimea Ai
reprezint mulimea liniilor pe care se poate aranja dama din coloana i. i n acest caz
mulimile Ai coincid. Ele au aceleai opt elemente, fiecare element reprezentnd un numr de
I

linie: Ai = {1, 2, 3, 4, 5, 6, 7, 8} = A
ED
8 Tehnici de programare

C
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 A2 A3 ... A8 = A A A A = A8, adic mulimea:
{(1,1,1,1,1,1,1,1), (1,1,1,1,1,1,1,2), (1,1,1,1,1,1,1,3), , (8,8,8,8,8,8,8,7), (8,8,8,8,8,8,8,8)}

I
dup care se va verifica fiecare element al mulimii, dac este o soluie a problemei, adic

OG
dac cele opt numere dintr-o soluie pot reprezenta coloanele pe care pot fi aranjate
damele pe fiecare linie, astfel nct s nu se atace ntre ele. Soluiile obinute sunt:
{(1,5,8,6,3,7,2,4), (1,6,8,3,7,4,2,5), (1,7,4,6,8,2,5,3), , (8,3,1,6,2,5,7,4),
(8,4,1,3,6,2,7,5)}

AG
Observaie. Metoda clasic de rezolvare a acestui tip de probleme necesit foarte multe
operaii din partea calculatorului, pentru a verifica fiecare element al produsului cartezian.
Presupunnd (pentru simplificare) c fiecare mulime Ai are m elemente, atunci algoritmul de
generare a elementelor produsului cartezian are complexitatea O(card(A1) card(A2)
n

ED
card(An)) = Q(m m m m) = O(m ). Considernd c algoritmul prin care se verific
dac un element al produsului cartezian este o soluie a problemei (respect condiia intern
a soluiei) are complexitatea O(p), atunci complexitatea algoritmului de rezolvare a
n
problemei va fi O(pm ). De exemplu, n algoritmul de generare a permutrilor, complexitatea

P
algoritmului de verificare a condiiei interne este dat de complexitatea algoritmului prin care se
verific dac numerele dintr-un ir sunt distincte. n acest algoritm, se parcurge irul de m
numere i pentru fiecare numr din ir se parcurge din nou irul pentru a verifica
I
dac acel numr mai exist n ir. Complexitatea algoritmului este dat de cele dou
2 2
structuri for imbricate: O(m ) p = m .
Metoda recomandat pentru acest gen de probleme este metoda backtracking sau meto-

da cutrii cu revenire prin care se reduce volumul operaiilor de gsire a tuturor soluiilor.
IC

Metoda backtracking construiete progresiv vectorul soluiei, pornind de la


primul element i adugnd la vector urmtoarele elemente, cu revenire la
elementul anterior din vector, n caz de insucces. Elementul care trebuie adugat se
CT

caut n mulime, printre elementele care respect condiiile interne.


Prin metoda backtracking se obin toate soluiile problemei, dac ele exist. Pentru
exemplificarea modului n care sunt construite soluiile, considerm problema generrii
DA

permutrilor mulimii {1, 2, 3, , n} (A1=A2= =An=A={1, 2, 3, , n}).


PAS1. Se alege primul element al soluiei ca fiind primul element din mulimea A. n
exemplu, x1=1, adic primul numr din permutare este 1.
PAS2. Se caut al doilea element al soluiei (x2). Pentru a-l gsi, se parcurg pe rnd ele-
DI

mentele mulimii A i, pentru fiecare element i al mulimii, se verific dac respect


condiiile interne. Cutarea continu pn cnd se gsete primul element din
mulimea A care ndeplinete condiia intern, dup care se oprete. n exemplu, se
caut numrul de pe a doua poziie a permutrii, verificndu-se dac al doilea numr
RA

din permutare este diferit de primul numr. Se parcurg primele dou elemente ale
mulimii A i se gsete elementul x2=2, dup care procesul de cutare se oprete.
PAS3. Se caut al treilea element al soluiei (x3). Cutarea va folosi acelai algoritm de
la Pasul 2. n exemplu, se caut numrul din poziia a treia din permutare. Se
TU

gsete elementul x3=3.


PAS4. Presupunnd c s-au gsit primele k elemente ale soluiei, x1, x2, x3, , xk, se
trece la cutarea celui de al k+1-lea element al soluiei, xk+1. Cutarea se va face
astfel: se atribuie pe rnd lui xk+1 elementele mulimii A, pn se gsete primul
I
ED

element i care ndeplinete condiia intern. n exemplu, condiia intern este ca


Informatic 9

C
numrul din poziia k+1 a permutrii s nu fie egal cu nici unul dintre numerele
din poziiile anterioare lui k+1. Pot s apar dou situaii:
a. Exist un element i n mulimea A, astfel nct xk+1 = i s fie element al soluiei

I
problemei. n acest caz, se atribuie elementului xk+1 al soluiei valoarea i, dup

OG
care se verific dac s-a gsit soluia problemei. n exemplu, presupunem c pe
nivelul k+1 s-a gsit numrul 4. Se verific dac s-au generat toate cele n
elemente ale mulimii S, adic dac s-au gsit numere pentru toate cele n poziii
din permutare (k=n). Dac s-a gsit soluia problemei, atunci se afieaz soluia;

AG
altfel, se caut urmtorul element al soluiei, relundu-se operaiile de la Pasul 4.
b. S-au parcurs toate elementele mulimii A i nu s-a gsit nici un element i care s fie
elementul xk+1 al soluiei problemei. nseamn c trebuie s revenim la elementul k
al soluiei xk. Aadar, se consider generate primele k-1 elemente ale soluiei: x1,
x2, , xk-1 i, pentru elementul xk al soluiei, se reia cutarea, cu urmtorul

ED
element din mulimea A, adic se reiau operaiile de la Pasul 4 pentru elementul
xk al soluiei, ns nu cu primul element din mulimea A, ci cu elementul din muli-
mea A care se gsete imediat dup cel care a fost atribuit anterior pentru elemen-

P
tul xk al soluiei. n exemplu, lund n considerare modul n care au fost generate
primele k numere ale permutrii, n poziia k+1, orice numr s-ar alege, el mai
exist pe una dintre cele k poziii anterioare, i se revine la elementul k, care presu-
I
punem c are valoarea 3. Se genereaz n aceast poziie urmtorul numr din
mulimea A (4) i se verific dac el nu mai exist pe primele k-1 poziii ale permu-
trii, iar dac exist, se genereaz urmtorul element din mulimea A (5) .a.m.d.
PAS5. Algoritmul se ncheie dup ce au fost parcurse toate elementele mulimii A pentru

elementul x1 al soluiei. n exemplu, algoritmul se ncheie dup ce s-au atribuit pe


rnd valorile 1, 2, , n, elementului de pe prima poziie a permutrii.
IC

Generarea tuturor permutrilor mulimii {1, 2, 3}


1 2 3 3 12 2 3
CT

12 2 2 2 3 3 3 3 1
1 1 1 1 1 1 1 1 2 2

1 2 3 3 1 1 23
DA

1 1 1 23 3 3 3 1
2 2 2 2 2 2 2 3 3

1 23
DI

12 2 3 1 Au fost parcurse
1 1 1 2 2 2 2 3 toate elementele
3 3 3 3 3 3 3 mulimii A pen-
tru elementul x1 al soluiei.
RA

Observaie. n metoda backtracking, dac s-a gsit elementul xk al soluiei, elementului


xk+1 al soluiei i se atribuie o valoare numai dac mai exist o valoare care s ndeplineas-
c condiia de continuare a construirii soluiei adic dac, prin atribuirea acelei valori, se
poate ajunge la o soluie final pentru care condiiile interne sunt ndeplinite.
TU

Desenai diagramele pentru generarea prin metoda backtracking a:


Tem a. tuturor aranjamentelor de 2 elemente ale mulimii {1, 2, 3};
b. tuturor combinrilor de 2 elemente ale mulimii {1, 2, 3};
c. tuturor permutrilor mulimii {1, 2, 3, 4} care ndeplinesc condiia c 1 nu este vecin cu 3, i
I
ED

2 nu este vecin cu 4.
10 Tehnici de programare

C
Algoritmul metodei backtracking poate fi generalizat pentru orice problem care ndepli-
nete urmtoarele condiii:
1. Soluia problemei poate fi pus sub forma unui vector S = {x1, x2, , xn} ale crui

I
elemente xi aparin fiecare unei mulimi Ai, astfel: x1A1, x2A2, , xnAn.

OG
2. Mulimile Ai sunt finite, iar elementele lor sunt numere ntregi i se gsesc ntr-o
ordine bine stabilit.
Algoritmul backtracking este urmtorul:
PAS1. Se alege primul element al soluiei S: x1Ai.

AG
PAS2. Ct timp nu au fost parcurse toate elementele mulimii A1 (nu au fost gsite toate
soluiile) execut:
PAS3. Pentru fiecare element al soluiei execut:
PAS4. Se presupune c s-au gsit primele k elemente ale soluiei (x1, x2, , xk)

ED
aparinnd mulimilor A1, A2, A3, , Ak i se trece la cutarea celui de al
k+1-lea element al soluiei, xk+1, printre elementele mulimii Ak+1. Cutarea
se va face astfel: se atribuie, pe rnd, lui xk+1, elementele mulimii Ak+1,
pn se gsete primul element care ndeplinete condiia de continuare.

P
PAS5. Dac exist un element ai n mulimea Ak+1, astfel nct xk+1 = ai s
aparin soluiei problemei, atunci se atribuie elementului xk+1 valoa-
rea ai i se trece la Pasul 7; altfel, se trece la Pasul 6.
I
PAS6. Deoarece s-au parcurs toate elementele mulimii Ak+1 i nu s-a gsit
nici un element ai care s ndeplineasc condiia de continuare, se
revine la elementul xk i se consider generate primele k-1 elemente

ale soluiei: x1, x2, , xk-1, i pentru elementul xk se reia cutarea cu


urmtorul element din mulimea Ak, adic se reiau operaiile de la
IC

Pasul 4 pentru elementul xk al soluiei, ns nu cu primul element din


mulimea Ak ci cu elementul din mulimea Ak care se gsete imediat
dup cel care a fost atribuit anterior elementului xk.
CT

PAS7. Se verific dac s-a gsit soluia problemei, adic dac s-au gsit
toate elementele mulimii S. Dac s-a gsit soluia problemei, atunci
se afieaz soluia; altfel, se trece la cutarea urmtorului element al
soluiei, relundu-se operaiile de la Pasul 4.
DA

1.3.2. Implementarea metodei backtracking


Pentru implementarea metodei se folosesc urmtoarele structuri de date i subprograme.
DI

Date i structuri de date


Pentru a memora elementele xk ale soluiei se folosete o structur de date de tip stiv, care
RA

este implementat static printr-un vector st. Pentru vrful stivei se folosete variabila k.
Cnd s-a gsit elementul xk al soluiei, se urc n stiv, prin incrementarea vrfului cu 1
(k++), pentru a cuta elementul xk+1 al soluiei, iar pentru a reveni la elementul xk-1 al soluiei
se coboar n stiv prin decrementarea vrfului cu 1 (k--). Iniial, stiva are dimensiunea 1
(kmin=1), corespunztoare poziiei de pornire, i conine valoarea primului element al soluiei.
TU

Pentru elementul din vrful stivei (care corespunde elementului xk al soluiei) se va atribui o
valoare din mulimea Ak care poate fi un element al soluiei: st[k]=a[i]. Dup parcurgerea
complet a mulimilor Ak, stiva va avea dimensiunea n (kmax=n) corespunztoare numrului
I
ED
Informatic 11

C
de elemente ale soluiei. Vrful stivei va fi iniial 1, la gsirea unei soluii va avea valoarea n,
iar la terminarea algoritmului vrful stivei va avea valoarea 0.
Se mai folosesc urmtoarele variabile de memorie:

I
as pentru a ti dac pentru elementul xk al soluiei mai exist un succesor, adic dac

OG
mai exist un element n mulimea Ak care ar putea fi elementul xk al soluiei (este o varia-
bil logic ce are valoarea 1 true, dac exist succesor; altfel, are valoarea 0 false),
ev pentru a ti dac succesorul gsit respect condiia de continuare i poate fi
elementul xk al soluiei (este o variabil logic ce are valoarea 1 true, dac

AG
succesorul este element al soluiei; altfel, are valoarea 0 false) i
n pentru dimensiunea soluiei (numrul de elemente ale soluiei, n cazul
problemelor n care toate soluiile au acelai numr de elemente).
typedef int stiva[100];

ED
stiva st; //st=stiva
int n,k,ev,as; //k=vrful stivei
n cazul problemelor prezentate n studiul de caz, un element xk al soluiei este format
dintr-o singur valoare: numrul din poziia k (n cazul permutrilor, al aranjamentelor i

P
al combinrilor), respectiv numrul liniei pe care va fi pus dama din coloana k. n proble-
mele n care trebuie gsit un traseu, un element xk al soluiei este format din dou valori
I
care reprezint coordonatele poziiei n care se face urmtoarea deplasare. n acest caz,
pentru memorarea elementelor xk ale soluiei se va folosi o stiv dubl:
typedef int stiva[100][3];
stiva st;

sau o nregistrare n care cele dou cmpuri reprezint coordonatele deplasrii:


IC

struct element{int x,y;};


typedef element stiva[100];
stiva st;
CT

Elementele mulimii Ak vor fi perechi de valori (i,j) i vor reprezenta coordonatele unei
poziii, iar pentru elementul din vrful stivei se va atribui o valoare, din mulimea Ak, care
poate fi un element al soluiei, astfel: st[k][1]=i i st[k][2]=j, respectiv
st[k].x=i i st[k].y=j.
DA

Pentru simplificarea implementrii, toate aceste date i structuri de date sunt declarate
globale, deoarece valoarea pentru vrful stivei se va transmite mai uor, ntre subpro-
grame ca variabil global.
DI

Subprograme
Algoritmul va fi implementat prin:
un subprogram care va fi acelai pentru toi algoritmii de rezolvare prin metoda
RA

backtracking (parte fix) i care descrie strategia general backtracking i


subprogramele care au aceeai semnificaie pentru toi algoritmii, dar al cror coni-
nut difer de la o problem la alta, depinznd de condiiile interne ale soluiei.
Semnificaia subprogramelor folosite este (se va considera ca exemplu generarea
TU

permutrilor mulimii {1, 2, 3, , n}):


Subprogramul init (funcie procedural). Se iniializeaz elementul din vrful stivei
(elementul k). n acest element se va nregistra urmtorul element al soluiei. Acest
element se iniializeaz cu o valoare care nu face parte din mulimea Ak considerat,
I
ED

urmnd ca n urmtorii pai ai algoritmului s se atribuie acestui element prima


12 Tehnici de programare

C
valoare din mulimea Ak. n exemplu, nivelul k al stivei se va iniializa cu valoarea 0
(st[k]=0), urmnd ca la pasul urmtor s i se atribuie ca valoare 1, adic primul
numr din mulimea {1, 2, 3, ..., n}.

I
void init()

OG
{st[k]=0;}
Subprogramul succesor (funcie operand). Verific dac mai exist n mulimea Ak
un element pentru nivelul k al soluiei (un succesor). Dac mai exist un succesor, se
trece la urmtorul element din mulimea Ak, iar funcia va returna valoarea 1 (true).

AG
Dac nu mai exist un succesor, funcia va returna valoarea 0 (false). Valoarea
returnat de funcie se va atribui variabilei as. Iniial, valoarea variabilei de memorie
as este 1 (true) se presupune c mai exist un succesor. n exemplu, subprogramul
succesor va verifica dac pentru poziia k din permutare mai exist un numr. Dac

ED
numrul i de pe nivelul k este mai mic dect n, poziiei k i se va atribui numrul
urmtor, i+1, i funcia va returna valoarea 1 (true), iar dac numrul de pe nivelul k
este n, nseamn c pe aceast poziie din permutare nu mai poate fi pus nici un
numr i funcia va returna valoarea 0 (false).

P
int succesor()
{if (st[k]<n) {st[k]++; return 1;}
else return 0;}
I
Subprogramul valid (funcie operand). Verific dac valoarea atribuit elementului
xk al soluiei ndeplinete condiia de continuare, adic poate fi considerat c face
parte din soluia problemei (dac succesorul gsit este element al soluiei). Dac este

ndeplinit condiia (se evalueaz expresia prin care este descris condiia), funcia va
returna valoarea 1 (true); altfel, va returna valoarea 0 (false). Valoarea returnat de
IC

funcie se va atribui variabilei ev. Iniial, valoarea variabilei ev este 0 (false) se


presupune c succesorul gsit nu este elementul k al soluiei. n exemplu, subpro-
gramul valid va verifica dac numrul din poziia k nu mai exist n cele k-1 poziii
CT

anterioare. Dac numrul nu ndeplinete aceast condiie, funcia va returna valoarea


0 (false).
int valid()
DA

{for (int i=1;i<k;i++)


if (st[i]==st[k]) return 0;
return 1;}
Subprogramul solutie (funcie operand). Verific dac s-au obinut toate elementele
DI

soluiei. n exemplu, subprogramul solutie va verifica dac au fost gsite toate cele
n elemente ale soluiei, adic dac s-au gsit soluii de aranjare n permutare pentru
toate cele n numere. Dac s-a gsit soluia, subprogramul ntoarce valoarea 1 (true);
altfel, ntoarce valoarea 0 (false).
RA

int solutie()
{return k==n;}
Subprogramul tipar (funcie procedural). Afieaz elementele soluiei. De obicei,
afiarea soluiei const n afiarea valorilor din stiv.
TU

void tipar()
{for (int i=1;i<=n;i++) cout<<st[i]<<" ";
cout<<endl;}
I
ED
Informatic 13

C
Numrul de ordine al Elementele soluiei
elementelor soluiei
n an1 an2 anj anm xn

I
OG
.. Parcurgerea elementelor se face cu .
.. subprogramul succesor .
i ai1 ai2 aij aim xi

AG
.. k=k+1 . k=k-1
2 a21 a22 a2j a2m x2
1 a11 a12 a1j a1m x1

ED
1 2 j . m
Numrul de ordine al elementelor din mulimea Ak Stiva st[k]

P
Subprogramul valid verific dac este element al soluiei
Subprogramul fix poate fi implementat iterativ sau recursiv.
Implementarea iterativ
I
void bt() //partea fix a algoritmului
{k=1; //se iniializeaz vrful stivei
init(); //se iniializeaz stiva pentru primul element al soluiei

while (k>0) //ct timp stiva nu s-a golit


{as=1; ev=0;
IC

while(as && !ev) // ct timp are succesor i nu s-a gsit


// elementul k al soluiei
{as=succesor(); // se caut succesor
CT

if(as) // dac are succesor, atunci


ev=valid();} // se verific dac este element al soluiei
// se iese din structura repetitiv while dac nu mai exist
DA

// succesor sau dac s-a gsit elementul soluiei


if(as) // dac are succesor, atunci
if (solutie()) //dac s-au obinut toate elementele soluiei,
tipar(); // atunci se afieaz elementele soluiei; _
DI

else {k++; // altfel, se urc n stiv pentru a nregistra


// urmtorul element al soluiei
init();} // i se iniializeaz stiva pentru
// urmtorul element al soluiei;
RA

else k--;} // altfel, se coboar n stiv pentru a reveni


} // la elementul anterior al soluiei
void main() { ... bt(); ... }
Implementarea recursiv Prelucrrile care se fac pentru elementul k al soluiei se fac
TU

i pentru elementul k+1 al soluiei i aceste prelucrri pot fi apelate pentru elementul k+1
al soluiei, iar trecerea de la elementul k al soluiei la elementul k+1 al soluiei se face prin
apelul recursiv al acestor prelucrri. n algoritmul backtracking implementat iterativ, reve-
nirea la nivelul k-1 trebuie s se fac atunci cnd pe nivelul k nu se gsete o valoare
I
ED

care s ndeplineasc condiiile interne. n cazul implementrii recursive, condiia de


14 Tehnici de programare

C
baz este ca pe nivelul k s nu se gseasc o valoare care s ndeplineasc condiiile
interne. Cnd se ajunge la condiia de baz, nceteaz apelul recursiv i se revine la
subprogramul apelant, adic la subprogramul n care se prelucreaz elementul k-1 al

I
soluiei, iar n stiv se vor regsi valorile prelucrate anterior n acest subprogram.

OG
Deoarece apelul recursiv se face n funcie de valoarea vrfului stivei (k), aceast valoare
se va transmite, ntre subprograme, prin intermediul parametrilor de comunicaie.
void bt(int k) //partea fix a algoritmului
{init(k); //se iniializeaz stiva pentru elementul k al soluiei

AG
while(succesor(k))
//ct timp se gsete succesor pentru elementul k al soluiei
if(valid(k)) dac succesorul este element al soluiei
if(solutie(k)) //dac s-au obinut toate elementele soluiei,

ED
tipar(k); // atunci se afieaz elementele soluiei;_
else bt(k+1); //altfel, se apeleaz subprogramul pentru a gsi
} //elementul k+1 al soluiei
void main() { ... bt(1); ... }

P
Complexitatea algoritmului metodei backtracking
Dac fiecare soluie are n elemente i fiecare mulime Ai din care se alege un element al
I
soluiei are m elemente, atunci complexitatea algoritmului metodei backtracking este
n
O(card(A1) card(A2) card(An)) = Q(m m m m) = O(m ). Dac numrul de
elemente ale mulimilor Ai este diferit i notm cu:

mmin= min(card(A1), card(A2), , card(An))


mmax= max(card(A1), card(A2), , card(An))
IC

n
atunci complexitatea algoritmului va fi cuprins ntre o complexitate minim O(mmin ) i o
n
complexitate maxim O(mmax ). Rezult c algoritmul metodei backtracking este un
algoritm exponenial. Avnd o complexitate exponenial, metoda backtracking se reco-
CT

mand numai dac nu se cunoate un algoritm mai eficient.

1.3.3. Probleme rezolvabile prin metoda backtracking


DA

Metoda backtracking este recomandat n cazul problemelor care au urmtoarele


caracteristici:
se cere gsirea tuturor soluiilor posibile;
nu se cunoate un algoritm mai eficient.
DI

Alte exemple de probleme clasice care se pot rezolva folosind metoda backtracking:
generarea tuturor elementelor unui produs cartezian;
generarea tuturor partiiilor unui numr natural;
RA

generarea tuturor partiiilor unei mulimi;


generarea tuturor funciilor surjective;
generarea tuturor funciilor injective;
generarea tuturor posibilitilor de plat a unei sume cu bancnote de valori date;
TU

generarea tuturor posibilitilor de acoperire a tablei de ah prin sritura calului (parcur-


gerea tablei de ah prin sritura calului, fr a se trece de dou ori prin aceeai poziie).
generarea tuturor posibilitilor de ieire dintr-un labirint;
I
ED
Informatic 15

C
1.3.3.1. Generarea permutrilor
Prin asamblarea subprogramelor definite anterior, programul pentru generarea tuturor

I
permutrilor muimii {1, 2, 3, , n} va fi:

OG
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
int n,k,ev,as; int n;

AG
stiva st; stiva st;
void init() void init(int k)
{st[k]=0;} {st[k]=0;}
int succesor() int succesor(int k)

ED
{if (st[k]<n) {if (st[k]<n)
{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1; return 1;}
else return 0;} else return 0;}
int valid() int valid(int k)

P
{for(int i=1;i<k;i++) {for(int i=1;i<k;i++)
if (st[k]==st[i]) return 0; if (st[k]==st[i]) return 0;
return 1;} return 1;}
I
int solutie() int solutie(int k)
{return k==n;} {return k==n;}
void tipar() void tipar()
{for(int i=1;i<=n;i++) {for(int i=1;i<=n;i++)

cout<<st[i]<<" "; cout<<st[i]<<" ";


cout<<endl;} cout<<endl;}
IC

void bt() void bt(int k)


{k=1; {init(k);
CT

init(); while(succesor(k))
while (k>0) if(valid(k))
{as=1; ev=0; if(solutie(k)) tipar();
while(as && !ev) else bt(k+1);}
DA

{as=succesor(); void main()


if(as) ev=valid();} {cout<<"n= "; cin>>n;
if(as) bt(1);}
if (solutie()) tipar();
DI

else {k++; init();}


else k--;}}
void main()
{cout<<"n= "; cin>>n;
RA

bt();}
Algoritmul de generare a permutrilor poate fi folosit i n alte probleme. De exemplu, s se
genereze toate permutrile mulimii {1, 2, 3, , n} n care nu apar numere consecutive.
TU

Aceast problem face parte din categoria de probleme de generare a permutrilor cu


condiie soluia conine o condiie intern suplimentar fa de cea impus de permutare.
n acest exemplu, condiia suplimentar de continuare a construirii soluiei este ca numrul ales
pentru nivelul k al soluiei s nu difere printr-o unitate de numrul care se gsete pe nivelul k-1
I

al soluiei. Modificarea apare n subprogramul valid():


ED
16 Tehnici de programare

C
int valid()
{if (k>1 && abs(st[k]-st[k-1])==1) return 0;
for (int i=1;i<k;i++)if (st[i]==st[k]) return 0;

I
return 1;}

OG
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
Tem generarea tuturor permutrilor.
1. S se genereze toate permutrile unei mulimi de numere oarecare.
Numerele se memoreaz ntr-un vector. (Indicaie. Se permut indicii elementelor din

AG
vectorul v, i n subprogramul tipar() se afieaz elementele v[st[i]]).
2. S se afieze toate anagramele unui cuvnd citit de la tastatur.
3. S se genereze toate matricele binare ptrate, de dimensiune n, care au un singur
element de 1 pe linie i un singur element de 1 pe coloan. O matrice binar este o

ED
matrice ale crei elemente au valoarea 0 sau 1. Indicaie. Soluia are n elemente.
Elementul soluiei xk reprezint numrul coloanei de pe linia k pe care se gsete
elementul cu valoarea 1.
4. S se genereze toate funciile bijective f : AB, unde card(A)=card(B)=n.

P
5. S se genereze toate posibilitile de aranjare pe o tabl de ah, cu dimensiunea nn, a
n ture care s nu se atace ntre ele. Deoarece tura se poate deplasa numai pe linia sau
pe coloana pe care a fost plasat, turele se pot ataca ntre ele pe linie i pe coloan.
I
Indicaie. Se observ c fiecare tur trebuie s fie plasat singur pe o coloan, ca
s nu se atace ntre ele. Soluia problemei este dat de mulimea cu n elemente {x1,
x2, , xn} care se memoreaz n stiv. Elementul soluiei xk reprezint numrul liniei

n care se aaz tura din coloana k i se memoreaz pe nivelul k al stivei st.


Deoarece dou ture nu pot fi aezate pe aceeai linie, stiva trebuie s conin ele-
IC

mente distincte. Problema se reduce la generarea permutrilor mulimii {1, 2, 3, , n}.


Interpretarea soluiei este: fiecare tur se plaseaz n coloana k, pe linia st[k].
6. S se genereze toate permutrile mulimii {1, 2, 3, , n} n care dou numere vecine nu
CT

trebuie s fie ambele pare sau ambele impare. Indicaie. n subprogramul valid() se
mai verific i condiia suplimentar de vecintate.
int valid()
DA

{if (k>1 && (st[k-1]%2==0 && st[k]%2==0)||


(st[k-1]%2==1 && st[k]%2==1)) return 0;
for (int i=1;i<k;i++) if (st[i]==st[k]) return 0;
return 1;}
7. S se genereze toate permutrile mulimii {1, 3, 5, , 2n+1}. Indicaie. Soluia are n
DI

elemente. n subprogramul init() elementul din vrful stivei se iniializeaz cu valoa-


rea -1, iar n subprogramul succesor() se modific modul de determinare a succe-
sorului.
RA

int succesor()
{if (st[k]<2*n+1) {st[k]= st[k]+2; return 1;}
else return 0;}
8. S se genereze toate permutrile unei mulimi de numere oarecare, astfel nct cea mai
TU

mic i cea mai mare valoare s-i pstreze poziiile iniiale.


9. ntr-un ir sunt aranjate n persoane. S se genereze toate posibilitile de rearanjare n
ir a acestor persoane, astfel nct fiecare persoan din ir:
a. s nu aib n faa sa aceeai persoan pe care a avut-o n irul iniial;
I

b. s nu aib aceiai vecini ca n irul iniial;


ED
Informatic 17

C
c. s nu aib n faa sa persoanele pe care le-a avut n irul iniial;
d. s fie desprit de vecinii pe care i-a avut n irul iniial de una sau cel mult p
persoane; valoarea pentru p se citete de la tastatur.

I
OG
1.3.3.2. Generarea produsului cartezian
Se genereaz toate elementele produsului cartezian A1 A2 A3 An, unde Ai={1,
2, , ni}.
O soluie a problemei va fi un element al produsului cartezian i va fi format din n ele-

AG
mente. Un element xk al soluiei poate fi orice element din mulimea Ak (nu exist
condiii interne). Numrul de elemente ale fiecrei mulimi Ai va fi memorat ntr-un
vector m cu lungimea logic n, unde m[i]=ni. Fa de algoritmul pentru generarea per-
mutrilor, apar urmtoarele diferene:

ED
Deoarece fiecare mulime Ak are un numr diferit de elemente, elementul de pe nive-
lul k are succesor dac numrul i de pe acest nivel este mai mic dect m[k].
Deoarece nu exist condiii interne, nu exist restricii nici pentru condiia de conti-
nuare, i subprogramul valid() va furniza valoarea 1.

P
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
I
typedef int stiva[10]; typedef int stiva[10];
int n,k,ev,as,m[10]; int n;
stiva st; stiva st;
void init() void init(int k)

{st[k]=0;} {st[k]=0;}
int succesor() int succesor(int k)
IC

{if (st[k]<m[k]) {if (st[k]<m[k])


{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1; return 1;}
CT

else return 0;} else return 0;}


int valid() int valid(int k)
{return 1;} {return 1;}
int solutie() int solutie(int k)
DA

{return k==n;} {return k==n;}


void tipar() void tipar()
{for(int i=1;i<=n;i++) {for(int i=1;i<=n;i++)
cout<<st[i]<<" "; cout<<st[i]<<" ";
DI

cout<<endl;} cout<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()
RA

{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n;


for(int i=1;i<=n;i++) for(int i=1;i<=n;i++)
{cout<<"Nr. de elemente multimea " {cout<<"Nr. de elemente multimea "
<<i<<" "; <<i<<" ";
TU

cin>>m[i];} cin>>m[i];}
bt();} bt(1);}
Algoritmul de generare a produsului cartezian poate fi folosit i n alte probleme. De exemplu,
I

pentru generarea tuturor submulimilor unei mulimi.


ED
18 Tehnici de programare

C
O submulime este format din elemente ale mulimii A. Pentru simplificarea algoritmului,
vom considera mulimea A={1,2,3,,n}. Considerm mulimea B={0,1}. Pentru construirea
submulimilor, pentru fiecare submulime se definete funcia Submulimile Stiva

I
f:AB, astfel: dac elementul i din mulimea A aparine sub- 000

OG
{}=
mulimii, atunci f(i)=1; altfel, f(i)=0. Problema se reduce la {3} 001
n
generarea produsului cartezian B . Soluia va fi memorat n {2} 010
stiv i va avea n elemente, fiecare element k al soluiei avnd {2, 3} 011
valoarea 0 sau 1, cu semnificaia c elementul k din mulimea {1} 100

AG
A aparine, respectiv nu aparine submulimii. Alturat, sunt {1,3} 101
prezentate toate submulimile mulimii {1,2,3} i coninutul {1,2} 110
stivei pentru fiecare dintre ele. {1,2,3} 111
Fa de programul anterior, apar urmtoarele modificri:

ED
Deoarece mulimile produsului cartezian sunt identice (B={0,1}), s-au modificat: sub-
programul init() iniializarea nivelului k al stivei se face cu valoarea -1 , cu 1 mai
mic dect 0 i subprogramul succesor() elementul are succesor numai dac
este mai mic dect ultimul element din mulime, 1.

P
n subprogramul de afiare a soluiei, va fi afiat numrul nivelului i pentru care, n
stiv, se memoreaz valoarea 1.
I
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
int n,k,ev,as; int n;

stiva st; stiva st;


void init() void init (int k)
IC

{st[k]=-1;} {st[k]=0;}
int succesor() int succesor(int k)
{if (st[k]<1) {if (st[k]<st[k-1]+1)
CT

{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1;return 1;}


else return 0;} else return 0;}
int valid() int valid() {return 1;}
DA

{return 1;} int solutie(int k)


int solutie() {return k==n;}
{return k==n;} void tipar()
void tipar () {int i,x=0; cout<<"{";
DI

{int i,x=0; cout<<"{"; for (i=1;i<=n;i++)


for (i=1;i<=n;i++) if (st[i]==1)
if (st[i]==1) {cout<<i<<","; x=1;}
{cout<<i<<","; x=1;} if (x) cout<<'\b';
RA

if (x) cout<<'\b'; cout<<"}"<<endl;}


cout<<"}"<<endl;} cout<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
TU

void main() void main()


{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n; bt(1);}
bt();}
Observaie. Caracterul escape
'\b' este caracterul Backspace
I

(terge ultimul caracter din ir)


ED
Informatic 19

C
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
Tem generarea produsului cartezian.
1. Se consider n mulimi de cuvinte Ai, fiecare mulime avnd ni

I
cuvinte. S se genereze toate textele de n cuvinte care se pot forma cu cuvintele din aceste

OG
mulimi, cuvntul i din text aparinnd mulimii Ai.
2. ntr-un restaurant, un meniu este format din trei feluri de mncare. Exist patru
preparate culinare pentru felul unu, cinci preparate culinare pentru felul doi i trei prepa-
rate culinare pentru felul 3. S se genereze toate meniurile care se pot forma cu aceste

AG
preparate culinare.
3. ntr-un restaurant, un meniu este format din trei feluri de mncare. Exist patru preparate
culinare pentru felul unu, cinci preparate culinare pentru felul doi i trei preparate culinare
pentru felul 3. Fiecare preparat culinar are un pre i un numr de calorii. S se genereze
toate meniurile pe care le poate comanda o persoan, care s nu depeasc suma s i

ED
numrul de calorii c. Datele se citesc dintr-un fiier text, astfel: de pe primul rnd suma s i
numrul de calorii, de pe rndul urmtor, n ordine, preul fiecrui preparat culinar, i de pe
ultimul rnd, n aceeai ordine, caloriile fiecrui preparat culinar.

P
4. Pentru o mulime oarecare A, cu n elemente, s se genereze toate submulimile care au
suma elementelor egal cu s. Numrul de elemente ale mulimii, elementele mulimii A
i valoarea pentru suma s se citesc de la tastatur.
I
5. S se afieze toate numerele cu n cifre (1n10) care au proprietatea c sunt formate
numai din cifre pare, n ordine descresctoare.
6. S se afieze toate numerele formate din cifre distincte cu proprietatea c suma
cifrelor este S. Valoarea variabilei S se citete de la tastatur.

7. S se afieze toate secvenele de n litere (n numr natural par, citit de la tastatur)


din mulimea {A,B,C,D}, secvene care se construiesc astfel: nu se aaz dou litere
IC

identice una lng alta i trebuie s se foloseasc exact n/2 litere A.


8. Se citesc de la tastatur un numr natural n (0<n10) i apoi n numere naturale a1,
CT

a2, a3, ..., an. S se afieze pe ecran toate posibilitile de a intercala ntre toate cele n
numere operatorii + i - astfel nct, evalund expresia obinut, de la stnga la
dreapta, la fiecare pas, rezultatul obinut s fie strict pozitiv.
9. S se rezolve n mulimea numerelor naturale ecuaia 4x+3y+2xy=48. Indicaie.
DA

Soluia are 2 elemente: x i y. Ele pot lua valori n intervalul [0,16]. Limita inferioar a
intervalului este 0, pentru c numerele sunt naturale. Limita superioar s-a determinat
considernd, pe rnd, situaiile limit x=0 i y=0. Considerm mulimea A={0,2,3,,16}.
Problema se reduce la generarea produsului cartezian cu condiie AA soluia conine
DI

o condiie intern suplimentar: elementele ei trebuie s verifice ecuaia.


10. Se citesc n cifre distincte i un numr natural x. S se genereze toate numerele care se
pot forma cu aceste cifre i sunt mai mici dect numrul x. De exemplu, pentru cifrele 0,
1 i 3 i numrul x=157, se genereaz 1, 3, 10, 11, 13, 30, 31, 33, 100, 101, 103, 110,
RA

111, 113, 130, 131, 133. Indicaie. Se calculeaz numrul de cifre m ale numrului x.
p
Pentru mulimea A format din cele n cifre, se genereaz produsele carteziene A , cu
1pm. Elementele produsului cartezian sunt cifrele numrului care se formeaz.
Pentru ca un element al produsului cartezian s fie soluie, trebuie ca primul element s
TU

fie diferit de 0 (cifra cea mai semnificativ din numr nu trebuie s fie 0), iar numrul
format cu m cifre s fie mai mic dect numrul x.
11. S se genereze toate numerele naturale, cu cel mult n cifre (n10), care sunt formate
numai din cifre pare, n ordine strict cresctoare.
I
ED
20 Tehnici de programare

C
12. S se genereze toate numerele naturale, cu n cifre, care conin p cifre k. Valorile pentru
n, p i k se citesc de la tastatur.
13. Se citete un numr natural n. S se genereze toate numerele naturale care, reprezen-

I
tate n baza 2, au acelai numr de cifre de 0 i acelai numr de cifre de 1 ca i

OG
reprezentarea n baza 2 a numrului n.
14. Pe un bilet exist 12 poziii care pot fi perforate, aranjate pe 4 linii i 3 coloane. S se
genereze toate posibilitile de perforare a celor 12 poziii, astfel nct s nu existe dou
poziii alturate neperforate. Indicaie. Considerm mulimea A, format din 12 elemente,

AG
fiecare element reprezentnd o poziie care poate fi perforat, i mulimea B={0,1}. Se
definete funcia f:AB astfel: dac poziia i este perforat, atunci f(i)=1; altfel, f(i)=0.
12
Problema se reduce la generarea produsului cartezian B soluia conine o condiie
intern suplimentar: poziia k care se adaug, nu trebuie s fie neperforat (nu trebuie

ED
s aib valoarea 0) dac poziia k-1 sau poziia k-3 este neperforat (are valoarea 0).
1.3.3.3. Generarea aranjamentelor
Se genereaz toate aranjamentele de m elemente ale mulimii {1, 2, 3, , n}.

P
O soluie a problemei va fi un aranjament i va avea m elemente. Fa de algoritmul
pentru generarea permutrilor, se modific doar condiia prin care se verific dac s-au
obinut toate elementele soluiei.
I
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];

int n,m,k,ev,as; int n,m;


stiva st; stiva st;
IC

void init() void init(int k)


{st[k]=0;} {st[k]=0;}
int succesor() int succesor(int k)
CT

{if (st[k]<n) {if (st[k]<n)


{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1; return 1;}
else return 0;} else return 0;}
DA

int valid() int valid(int k)


{for(int i=1;i<k;i++) {for(int i=1;i<k;i++)
if (st[k]==st[i]) return 0; if (st[k]==st[i]) return 0;
return 1;} return 1;}
DI

int solutie() int solutie(int k)


{return k==m;} {return k==m;}
void tipar() void tipar()
{for(int i=1;i<=m;i++) {for(int i=1;i<=m;i++)
RA

cout<<st[i]<<" "; cout<<st[i]<<" ";


cout<<endl;} cout<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
TU

void main() void main()


{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n;
cout<<"m= "; cin>>m; bt();} cout<<"m= "; cin>>m; bt(1);}
I
ED
Informatic 21

C
Algoritmul de generare a aranjamentelor poate fi folosit i n alte
probleme. De exemplu, pentru generarea tuturor funciilor injective. Soluia Afiarea
12 x 12
Se genereaz toate funciile injective f:AB, unde card(A)=m i

I
f(x) 1 2

OG
card(B)=n. Pentru simplificarea algoritmului vom considera muli-
mile A={1,2,3,,m} i B={1,2,3,,n}. O soluie este format din m 13 x 12
elemente. Elementul k al soluiei reprezint valoarea funciei f(k). f(x) 1 3
Deoarece valoarea funciei f(k) aparine mulimii B, n stiv se vor
21 x 12
genera numere din mulimea {1,2,3,,n}. Din definiia funciei

AG
f(x) 2 1
injective, f(i)f(j), pentru orice ij. Rezult c, pentru ca funcia s
fie injectiv, trebuie ca mn. Problema se reduce la generarea n 23 x 12
stiv a tuturor aranjamentelor de n elemente luate cte m. Soluiile f(x) 2 3
vor fi afiate sub forma tabelului de variaie al funciei. De 31 x 12

ED
exemplu, dac A={1,2} i B={1,2,3}, soluiile i modul n care vor fi f(x) 3 1
afiate sunt prezentate alturat.
Fa de programul anterior, nu se va modifica dect subprogramul 32 x 12
de afiare a soluiilor tipar(). f(x) 32

P
void tipar()
{int i; cout<<" x | ";
I
for (i=1;i<=m;i++) cout<<i<<" "; cout<<endl;
for (i=1;i<=m;i++) cout<<"-----"; cout<<endl<<"f(x)| ";
for (i=1;i<=m;i++) cout<<st[i]<<" "; cout<<endl<<endl;}
...

void main()
{cout<<"numarul de elemente ale multimii A= "; cin>>m;
IC

cout<<"numarul de elemente ale multimii B= "; cin>>n; bt();}


Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
Tem generarea tuturor aranjamentelor.
CT

1. S se genereze toate posibilitile de aranjare pe m scaune a n per-


soane (mn). Valorile pentru n i m i numele persoanelor se citesc dintr-un fiier text.
2. Se citesc de la tastatur n cifre distincte. S se genereze toate numerele de m cifre
(mn) care se pot forma cu aceste cifre i care conin toate cele n cifre.
DA

3. S se genereze toate anagramele unui cuvnt, din care se elimin p litere oarecare.
Valoarea minim a numrului p este 1, iar valoarea maxim este cu 1 mai mic dect
lungimea cuvntului. Se citesc de la tastatur cuvntul i valoarea numrului p.
4. Se citesc de la tastatur n caractere distincte. S se genereze toate cuvintele de m carac-
DI

tere (mn) care se pot forma cu aceste caractere i care conin toate cele n caractere.
5. Se citete un numr n care are m cifre. S se genereze toate numerele, cu cel mult m
cifre, care se pot forma cu cifrele numrului iniial.
RA

6. Dintr-o mulime de n persoane, aranjate ntr-un ir, se elimin p persoane. S se genereze


toate posibilitile de aranjare ntr-un ir a persoanelor rmase, astfel nct fiecare persoan
s nu aib aceiai vecini ca n irul iniial. Valorile pentru n i p se citesc de la tastatur.
7. S se genereze toate aranjamentele, de m numere, ale unei mulimi de n numere oarecare
TU

astfel nct suma elementelor generate s fie egal cu s. Numrul de elemente ale mulimii,
n, elementele mulimii, valoarile pentru m i pentru suma s, se citesc de la tastatur.
8. S se genereze toate drapelele cu trei culori care se pot forma cu ase culori: alb, gal-
ben, rou, verde, albastru i negru, care au n mijloc culoarea alb, verde sau rou.
I

Indicaie. Soluia are 3 elemente, un element al soluiei fiind indicele din vector al unei
ED
22 Tehnici de programare

C
culori. Se genereaz aranjamente cu condiie de 6 obiecte luate cte 3 soluia conine o
condiie intern suplimentar fa de cea impus de aranjamente: elementul 2 al soluiei
trebuie s fie indicele culorii alb, verde sau rou.

I
9. Se consider n cuburi. Fiecare cub i are latura Li i culoarea ci. S se construiasc toate

OG
turnurile stabile, formate cu m cuburi, astfel nct dou cuburi vecine n turn s nu aib
aceeai culoare. Valorile pentru n i m i atributele celor n cuburi se citesc de la tastatur.
Indicaie. Informaiile despre cuburi se memoreaz ntr-un vector de nregistrri cu n ele-
mente. Soluia are m elemente. Un element al soluiei este indicele din vector al unui cub.

AG
Se genereaz aranjamente cu condiie de n obiecte luate cte m soluia conine o
condiie intern suplimentar fa de cea impus de aranjamente: cubul k care se adaug
la turn trebuie s aib latura mai mic dect a cubului k-1 i culoarea diferit de acesta.

ED
1.3.3.4. Generarea combinrilor
Se genereaz toate combinrile de m elemente ale mulimii {1, 2, 3, , n}.
O soluie a problemei va fi o combinare i va avea m elemente. Fa de algoritmul pentru

P
generarea aranjamentelor, apare o condiie suplimentar: aceea ca soluiile obinute s fie
distincte, adic dou soluii s nu conin aceleai numere. Pentru aceasta, se va aduga o
condiie de continuare suplimentar: valoarea de pe nivelul k trebuie s fie strict mai
I
mare dect oricare dintre valorile de pe nivelele inferioare. Altfel spus, elementele soluiei
trebuie s fie ordonate: st[1]<st[2]< ... <st[k-1]<st[k]. Condiia de continuare este ndeplini-
t dac elementul de pe nivelul k va avea o valoare strict mai mare dect valoarea elemen-
tului de pe nivelul k-1 (se iniializeaz cu o valoare egal cu cea a elementului de pe nivelul

k-1) i o valoare mai mic dect n-m+k (se caut succesorul pn la valoarea n-m+k).
IC

Implementarea iterativ Implementarea recursiv


#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
CT

int n,m,k,ev,as; int n,m;


stiva st; stiva st;
void init() void init(int k)
{if (k==1) st[k]=0; { if (k==1) st[k]=0;
DA

else st[k]=st[k-1];} else st[k]=st[k-1];}


int succesor() int succesor(int k)
{if (st[k]<n-m+k) {if (st[k]<n-m+k)
{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1; return 1;}
DI

else return 0;} else return 0;}


int valid() {return 1;} int valid() {return 1;}
int solutie() int solutie(int k)
{return k==m;} {return k==m;}
RA

void tipar() void tipar()


{for(int i=1;i<=m;i++) {for(int i=1;i<=m;i++)
cout<<st[i]<<" "; cout<<st[i]<<" ";
cout<<endl;} cout<<endl;}
TU

void bt() void bt(int k)


{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()
{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n;
I
ED

cout<<"m= "; cin>>m; bt();} cout<<"m= "; cin>>m; bt(1);}


Informatic 23

C
Algoritmul de generare a combinrilor poate fi folosit n problemele de generare a
tuturor posibilitilor de a forma din n obiecte grupuri de m obiecte care s aib
anumite proprieti. De exemplu, din n obiecte trebuie s se distribuie unei persoane m

I
obiecte, care s conin obligatoriu obiectul p i s nu conin obiectul q. S se genereze

OG
toate posibilitile de a forma grupuri de m astfel de obiecte. Pentru simplificare vom
considera mulimea obiectelor ca fiind {1, 2, 3, , n}. Valorile pentru numrul de obiecte
n, numrul de obiecte din grup, m, i indicii obiectelor p i q se citesc de la tastatur.
Deoarece obiectul p face parte obligatoriu din grupul de obiecte, el va fi memorat ca prim

AG
element al soluiei (st[1]=p), iar subprogramul bt() va genera numai urmtoarele m-1
elemente ale soluiei. Se modific i condiia de continuare a construirii soluiei (subpro-
gramul valid()), deoarece obiectele p i q nu pot fi elemente ale soluiei.
#include<iostream.h>

ED
typedef int stiva[100];
int n,m,p,q,k,ev,as;
stiva st;
void init() {if (k==2) st[k]=0; else st[k]=st[k-1];}

P
int succesor() {//la fel ca n exemplul anterior}
int valid()
I
{return st[k]!=p && st[k]!=q;}
int solutie() {//la fel ca n exemplul anterior}
void tipar() {//la fel ca n exemplul anterior}
void bt()

{k=2;init();
while (k>1)
IC

//la fel ca n exemplul anterior}


void main()
{cout<<"n= "; cin>>n; cout<<"m= "; cin>>m;
CT

cout<<"p= "; cin>>p; cout<<"q= "; cin>>q;


st[1]=p; bt();}
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
DA

Tem generarea tuturor combinrilor.


1. S se genereze toate grupurile de p persoane care se pot forma din n
persoane. Informaiile se citesc dintr-un fiier text unde, pe primul rnd, sunt scrise
valorile pentru p i n, desprite printr-un spaiu, iar pe urmtoarele rnduri numele
DI

persoanelor, cte un nume pe un rnd.


2. Dou persoane i mpart n obiecte astfel: prima persoan ia m obiecte, iar cealalt
persoan restul obiectelor. S se genereze toate posibilitile de distribuire a celor n
obiecte ntre cele dou persoane.
RA

3. Dou persoane i mpart n obiecte. Fiecare obiect are o valoare vi. S se genereze
toate posibilitile de distribuire a celor n obiecte, ntre cele dou persoane, astfel nct
fiecare persoan s primeasc obiecte, care s aib aceeai valoare total.
4. Dou persoane i mpart n obiecte astfel: prima persoan ia m obiecte, iar cealalt
TU

persoan, restul obiectelor. Fiecare obiect are o valoare vi. S se genereze toate
posibilitile de distribuire a celor n obiecte, ntre cele dou persoane, astfel nct fiecare
persoan s primeasc obiecte care s aib aceeai valoare total.
I
ED
24 Tehnici de programare

C
5. S se genereze toate numerele binare de n cifre care au m cifre de 0. Indicaie. O
soluie este format din m elemente, un element fiind poziia din numr n care se poate
gsi cifra 0 exceptnd prima poziie.

I
6. Din n obiecte date, s se genereze toate grupurile de m obiecte care ndeplinesc

OG
urmtoarele condiii:
a. conin exact p obiecte precizate;
b. nu conin nici unul din p obiecte precizate;
c. conin numai un obiect din p obiecte precizate;

AG
d. conin cel puin un obiect din p obiecte precizate;
e. conin exact q obiecte din p obiecte precizate;
f. conin exact q obiecte din p obiecte precizate i nu conin r obiecte precizate;
g. conin exact q obiecte din p obiecte precizate i nu conin s obiecte din r obiecte

ED
precizate.

1.3.3.5. Generarea tuturor partiiilor unui numr natural


O partiie a unui numr natural nenul n este o descompunere a nu-

P
4=1+1+1+1 (m=4)
mrului n n sum de m numere naturale nenule. Soluiile care nu 4=1+1+2 (m=3)
difer dect prin ordinea termenilor nu sunt considerate distincte. 4=1+3 (m=2)
I
Alturat sunt prezentate toate partiiile numrului 4. 4=2+2 (m=2)
O soluie a problemei va fi format din m elemente a cror sum este 4=4 (m=1)
egal cu numrul n. Elementele soluiei reprezint termenii unei descompuneri. Numrul de

elemente ale unei soluii (m) este egal cu valoarea vrfului stivei k atunci cnd s-a obinut
soluia. Soluia se obine atunci cnd suma elementelor din stiv este egal cu n. Altfel
IC

spus, soluia se obine atunci cnd suma s=st[1]+st[2]+ ... +st[k-1]+st[k] are valoarea n.
Pentru a evita repetarea aceleiai descompuneri, valoarea de pe nivelul k trebuie s fie mai
mare sau egal cu oricare dintre valorile de pe nivelele inferioare. Altfel spus, elementele
soluiei trebuie s fie ordonate: st[1]st[2] ... st[k-1]st[k]. Aceast condiie este
CT

ndeplinit dac elementul de pe nivelul k va avea o valoare mai mare sau egal cu
valoarea elementului de pe nivelul k-1 (se iniializeaz cu o valoare mai mic cu 1 dect
cea a elementului de pe nivelul k-1) i o valoare mai mic dect diferena dintre numrul n
DA

i suma termenilor descompunerii gsii pn la nivelul k, s=st[1]+st[2]+ ... +st[k-1].


Condiia de continuare este ca suma termenilor generai, s, s fie mai mic sau egal
cu n (sn), o soluie complet obinndu-se atunci cnd s=n. Iniial, suma s are valoarea
0 i ea trebuie actualizat n permanen. Exist dou cazuri de actualizare:
DI

Atunci cnd se adaug n stiv un nou termen, acesta se adaug i la sum. Altfel
spus, dac succesorul gsit poate fi element al soluiei (prin adugarea lui la sum
aceasta nu va depi valoarea numrului n), atunci el se adaug la sum. Actuali-
RA

zarea sumei se va face n subprogramul valid() (termenul se adaug la sum


numai dac face parte din descompunere): s+=st[k].
Atunci cnd se coboar n stiv, trebuie sczute din sum dou valori: valoarea
elementului din vrful stivei (k) i valoarea elementului de pe nivelul precedent (k-1).
TU

Deoarece n stiv se coboar ntotdeauna dup ce s-a obinut o soluie complet i nu


se mai poate gsi un element pentru nivelul k cu care s se continue dezvoltarea
soluiei, scderea din sum a termenului curent se va face dup ce se afieaz o
soluie complet n subprogramul tipar(): s-=st[k], iar scderea din sum a
I
ED
Informatic 25

C
termenului precedent se face n subprogramul succesor(), atunci cnd nu se
gsete succesor pentru elementul din vrful stivei: s-=st[k-1].
Implementarea iterativ Implementarea recursiv

I
OG
#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
int n,s=0,k,ev,as; int n,s=0;
stiva st; stiva st;
void init () void init (int k)

AG
{if (k==1) st[k]=0; {if (k==1) st[k]=0;
else st[k]=st[k-1]-1;} else st[k]=st[k-1]-1;}
int succesor() int succesor(int k)
{if (st[k]<n-s) {if (st[k]<n-s)

ED
{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1; return 1;}
else {s-=st[k-1]; return 0;}} else {s-=st[k-1]; return 0;}}
int valid() int valid(int k)
{if (s+st[k]<=n) {if (s+st[k]<=n)

P
{s+=st[k]; return 1;} {s+=st[k]; return 1;}
else return 0;} else return 0;}
int solutie() int solutie(int k)
I
{return s==n;} {return s==n;}
void tipar() void tipar(int k)
{for(int i=1;<k;i++) {for(int i=1;<k;i++)

cout<<st[i]<<"+ "; cout<<st[i]<<"+ ";


cout<<st[k]<<endl; cout<<st[k]<<endl;
IC

s-=st[k];} s-=st[k];}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
CT

void main() void main()


{cout<<"n= "; cin>>n; bt();} {cout<<"n= "; cin>>n; bt(1);}
Algoritmul de generare a tuturor partiiilor unui numr natural poate fi folosit i n alte
DA

probleme. De exemplu, generarea tuturor posibilitilor de plat a unei sume cu


bancnote de valori date.
Problema se reduce la generarea tuturor partiiilor unui nu- 25 = 5+5+5+5+5 (m=5)
mr natural nenul suma, o partiie fiind o descompunere a 25 = 5+5+5+10 (m=4)
DI

numrului suma n sum de m numere naturale, nenule, cu 25 = 5+10+10 (m=3)


valori aparinnd mulimii A={a1,a2, , an}. Alturat, sunt
prezentate toate partiiile sumei 25 pentru bancnote cu valori aparinnd mulimii A={5,10}.
RA

Fa de problema anterioar, apar urmtoarele modificri:


Deoarece suma suma se descompune n valori precizate, aparinnd mulimii A,
aceste valori se memoreaz n vectorul a, care are lungimea logic n (numrul de
valori ale bancnotelor).
Un element al soluiei este indicele valorii bancnotei din vectorul a, adic un element
TU

din mulimea {1,2, , n}.


O soluie a problemei va fi format din m elemente, alese astfel nct suma valorilor
bancnotelor corespunztoare lor s fie egal cu numrul suma. Altfel spus, soluia se
I

obine atunci cnd suma s=a[st[1]]+a[st[2]]+ ... + a[st[k-1]]+ a[st[k]] are valoarea suma.
ED
26 Tehnici de programare

C
Condiia de continuare este ca suma valorilor termenilor generai, s, s fie mai mic
sau egal cu suma (ssuma), o soluie complet obinndu-se atunci cnd s=suma.
Atunci cnd se urc n stiv, se adun la sum valoarea bancnotei cu indicele k:

I
s+=a[st[k]], iar cnd se coboar n stiv, se scade din sum valoarea bancnotei

OG
cu indicele k: s-=a[st[k]] i valoarea bancnotei cu indicele k-1: s+=a[st[k-1]].
Deoarece este posibil ca pentru anumite valori ale sumei suma i ale valorilor
bancnotelor s nu existe nici o soluie, se folosete variabila de tip logic este, care
are valoarea 1 (true), dac exist cel puin o soluie, i 0 (false), n caz contrar.

AG
#include<iostream.h>
typedef int stiva[100];
int n,k,ev,as,s=0,suma,este=0,a[10];
stiva st;

ED
void init ()
{if (k==1) st[k]=0;
else st[k]=st[k-1]-1;}
int succesor()

P
{if (st[k]<n) {st[k]=st[k]+1; return 1;}
else {s-=a[st[k-1]]; return 0;}}
int valid()
I
{if (s+a[st[k]]<=suma) {s+=a[st[k]]; return 1;}
else return 0;}
int solutie()

{return s==suma;}
void tipar()
IC

{int i,j,p,este=1;
for (i=1;i<=n;i++)
{for(j=1,p=0;j<=k;j++) if (i==st[j]) p++;
CT

if (p!=0) cout<<p<<"*"<<a[i]<<" + ";}


cout<<'\b'<<'\b'<<" "<<endl; s-=a[st[k]];}
void bt() {//partea fix a algoritmului }
void main()
DA

{cout<<"n= "; cin>>n;


for (int i=1;i<=n;i++)
{cout<<"Valoare bancnota "<<i<<": "; cin>>a[i];}
cout<<"suma= "; cin>>suma; bt();
DI

if (!este) cout<<"Imposibil"; }
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
Tem generarea tuturor partiiior unui numr natural.
RA

1. S se genereze toate descompunerile unui numr natural n n


numere naturale distincte.
2. S se genereze toate descompunerile unui numr natural n n numere prime.
3. S se genereze toate descompunerile unui numr natural n n sum de 3 i 5.
TU

4. O bar are lungimea L. Se consider n repere de lungimi diferite. S se genereze toate


posibilitile de a tia bara dup reperele existente, fr s rmn rest la tiere, un
reper putnd fi folosit de mai multe ori. Se poate ca unele repere s nu fie folosite Se
citesc dintr-un fiier text, de pe primul rnd, lungimea barei L i numrul de repere n,
I

iar de pe urmtorul rnd, reperele. Numerele de pe un rnd sunt separate prin spaiu.
ED
Informatic 27

C
5. Pentru realizarea unui chestionar exist n ntrebri, fiecare ntrebare avnd un punctaj.
Numrul de ntrebri i punctajul fiecrei ntrebri se citesc dintr-un fiier text. S se
genereze toate chestionarele care au ntre a i b ntrebri distincte i un punctaj total

I
ntre p i q puncte. Valorile pentru a, b, p i q se citesc de la tastatur.

OG
6. S se gseasc modalitatea de plat a unei sume cu un numr minim de bancnote cu valori
date.

1.3.3.6. Generarea tuturor partiiilor unei mulimi

AG
O partiie a unei mulimi A este format din mulimile nevide disjuncte Ai a cror reuniune
m
este mulimea A: A i A i A i A j pentru orice i,j = 1m.
i 1

ED
Pentru simplificarea algoritmului vom considera mulimea A={1,2,3, ,n}. O partiie va fi
format din m mulimi, cu 1mn. Soluia va fi memorat n stiv i va avea n elemente,
fiecare element k al soluiei reprezentnd mulimea i (1in) creia i aparine elementul k din
mulimea care se partiioneaz: st[k]=i nseamn c elementul k din mulimea A face parte

P
din mulimea i a partiiei. n cadrul unei partiii nu intereseaz ordinea n care apar elementele
mulimii A. Cel mai mare numr care va fi generat n stiv reprezint numrul de mulimi m n
I
care a fost descompus mulimea A. n plus, numerele generate n stiv trebuie s aparin
unei mulimi de numere consecutive care ncepe cu 1, deoarece
partiia nu conine mulimi vide. Alturat, sunt prezentate toate Partiiile Stiva
partiiile mulimii {1,2,3} i coninutul stivei pentru fiecare dintre ele. n {1, 2, 3} 111

exemplu, nu exist soluia 1 3 3 deoarece aceste valori nu aparin {1, 2} {3} 112
unei mulimi de numere consecutive (nu se poate ca un element din {1, 3} {2 } 121
IC

{1} {2, 3 } 122


mulimea A s aparin mulimii A1, i alte dou elemente mulimii {1} {2} {3 } 123
A3, deoarece ar nsemna c mulimea A2 este vid).
CT

Condiia de continuare este asigurat prin modul n care este ales succesorul st[k]k,
ceea ce nseamn c elementul k din mulimea A nu poate aparine dect unei partiii al crei
numr este mai mic sau cel mult egal cu numrul de ordine al elementului. Altfel spus, dac
pn la nivelul k numrul maxim atribuit pentru o partiie este i, acest numr reprezentnd
DA

numrul de mulimi ale partiiei care exist n soluia parial, pe nivelul k+1 elementul poate
avea una dintre urmtoarele valori:
Orice valoare de la 1 la i, ceea ce nseamn c elementul k+1 din mulimea A se
adaug la una dintre mulimile care exist deja.
DI

Valoarea i+1, ceea ce nseamn c elementul k+1 din mulimea A va genera o nou
mulime n partiie.
Implementarea iterativ Implementarea recursiv
RA

#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
int n,k,ev,as; int n;
stiva st; stiva st;
TU

void init() {st[k]=0;} void init (int k) {st[k]=0;}


int succesor() int succesor(int k)
{if (st[k]<st[k-1]+1) {if (st[k]<st[k-1]+1)
{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1;return 1;}
I

else return 0;} else return 0;}


ED
28 Tehnici de programare

C
int valid() {return 1;} int valid() {return 1;}
int solutie() int solutie(int k)
{return k==n;} {return k==n;}

I
void tipar() void tipar()

OG
{int i,j,max=st[1]; {int i,j,max=st[1];
for(i=2;i<=n;i++) for(i=2;i<=n;i++)
if (st[i]>max) max=st[i]; if (st[i]>max) max=st[i];
for (i=1;i<=max;i++) for (i=1;i<=max;i++)

AG
{cout<<"{"; {cout<<"{";
for (j=1;j<=n;j++) for (j=1;j<=n;j++)
if (st[j]==i) cout<<j<<","; if (st[j]==i) cout<<j<<",";
cout<<'\b'<<"} ";} cout<<'\b'<<"} ";}

ED
cout<<endl;} cout<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()

P
{cout<<"n= "; cin>>n; bt();} {cout<<"n= "; cin>>n; bt(1);}
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
Tem generarea tuturor partiiilor unei mulimi. Se consider mulimea A, cu n
I
numere ntregi. Valorile pentru n i m i pentru elementele mulimii A se
citesc de la tastatur.
1. S se genereze toate partiiile mulimii A formate din dou submulimi care au suma

elementelor egale.
2. S se genereze toate partiiile mulimii A formate din m submulimi.
IC

3. S se genereze toate partiiile mulimii A formate din submulimi care au acelai numr
de elemente.
CT

1.3.3.7. Generarea tuturor funciilor surjective


Se genereaz toate funciile surjective f:AB unde card(A)=m i
Soluia Afiarea
card(B)=n. Pentru simplificarea algoritmului vom considera muli-
112 x 123
DA

mile A={1,2,3,,m} i B={1,2,3,,n}. O soluie este format din m


f(x) 1 1 2
elemente. Elementul k al soluiei reprezint valoarea funciei: f(k).
Deoarece valoarea funciei f(k) aparine mulimii B, n stiv se vor 121 x 123
genera numere din mulimea {1,2,3,,n}. Din definiia funciei f(x) 1 2 1
DI

surjective, trebuie ca, pentru orice jB, s existe iA, astfel nct
122 x 123
f(i)=j. Rezult c pentru ca funcia s fie surjectiv trebuie ca
f(x) 1 2 2
nm. Problema se reduce la generarea n stiv a tuturor elemen-
m 211 x 123
telor produsului cartezian B din care vor fi considerate soluii
RA

numai cele care conin toate elementele din mulimea B. Soluiile f(x) 2 1 1
vor fi afiate sub forma tabelului de variaie a funciei. De 221 x 123
exemplu, dac A={1,2,3} i B={1,2}, soluiile i modul n care vor fi f(x) 2 2 1
afiate sunt prezentate alturat.
TU

212 x 123
Condiia de continuare este asigurat prin modul n care este ales f(x) 2 1 2
succesorul ca element din mulimea B, singurul caz special fiind al
elementului care se adaug pe ultimul nivel din stiv (m). Prin adu- 221 x 123
I

garea acestui element, trebuie ca n stiv s existe toate elementele f(x) 2 2 1


ED
Informatic 29

C
mulimii B. Aceast condiie este verificat prin funcia surjectiva() care furnizeaz un
rezultat logic: 1 (true), dac n stiv exist toate cele n elemente ale mulimii B, i 0 (false), n
caz contrar.

I
Implementarea iterativ Implementarea recursiv

OG
#include<iostream.h> #include<iostream.h>
typedef int stiva[100]; typedef int stiva[100];
int n,m,k,ev,as; int n,m;
stiva st; stiva st;

AG
int surjectiva() int surjectiva()
{int i,j,x; {int i,j,x;
for (j=1;j<=n;j++) for (j=1;j<=n;j++)
{for (i=1,x=0;i<=m && !x;i++) {for (i=1,x=0;i<=m && !x;i++)

ED
if (st[i]==j) x=1; if (st[i]==j) x=1;
if (!x) return 0;} if (!x) return 0;}
return 1;} return 1;}
void init() {st[k]=0;} void init (int k) {st[k]=0;}

P
int succesor() int succesor(int k)
{if (st[k]<st[k-1]+1) {if (st[k]<st[k-1]+1)
{st[k]=st[k]+1; return 1;} {st[k]=st[k]+1;return 1;}
I
else return 0;} else return 0;}
int valid() int valid(int k)
{if (k==m) {if (k==m)
if (!surjectiva()) return 0; if (!surjectiva()) return 0;

return 1;} return 1;}


IC

int solutie() int solutie(int k)


{return k==m;} {return k==n;}
void tipar() void tipar()
CT

{int i; cout<<" x | "; {int i; cout<<" x | ";


for (i=1;i<=m;i++) cout<<i<<" "; for (i=1;i<=m;i++) cout<<i<<" ";
cout<<endl; cout<<endl;
for (i=1;i<=m;i++) cout<<"-----"; for (i=1;i<=m;i++) cout<<"-----";
DA

cout<<endl<<"f(x)| "; cout<<endl<<"f(x)| ";


for (i=1;i<=m;i++) cout<<st[i]<<" "; for (i=1;i<=m;i++) cout<<st[i]<<" ";
cout<<endl<<endl;} cout<<endl<<endl;}
void bt() void bt(int k)
DI

{//partea fix a algoritmului} {//partea fix a algoritmului}


void main() void main()
{cout<<"elemente multimea A= "; {cout<<"elemente multimea A= ";
cin>>m; cin>>m;
RA

cout<<"elemente multimea B= "; cout<<"elemente multimea B= ";


cin>>n; bt();} cin>>n; bt(1);}
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
TU

Tem generarea tuturor funciilor surjective.


1. Se citesc de la tastatur n cifre distincte. S se genereze toate nu-
merele de m cifre (nm) care se pot forma cu aceste cifre i care conin toate cele n cifre.
2. Se citesc de la tastatur n caractere distincte. S se genereze toate cuvintele de m carac-
I

tere (nm) care se pot forma cu aceste caractere i care conin toate cele n caractere.
ED
30 Tehnici de programare

C
3. Profesorul de informatic a pregtit m teme, pentru proiecte pe care trebuie s le repar-
tizeze celor n elevi din clas (mn), astfel nct nici o tem de proiect s nu rmn
nerepartizat. S se genereze toate soluiile de repartizare a temelor pentru proiect.

I
4. O bar are lungimea L. Se consider n repere de lungimi diferite. S se genereze toate

OG
posibilitile de a tia bara dup reperele existente, fr s rmn rest la tiere, fiecare
reper fiind folosit cel puin o dat. Se citesc dintr-un fiier text, de pe primul rnd,
lungimea barei L i numrul de repere n, iar de pe urmtorul rnd, reperele.
Numerele de pe un rnd sunt separate prin spaiu.

AG
5. S se genereze toate construciile corecte de paranteze ( i ); n este numr par i se
citete de la tastatur. De exemplu, pentru n=6, construciile (())() i ()(()) sunt corecte,
iar construcia ())(() nu este corect. Indicaie. Se genereaz funciile surjective f:AB
unde A = {1,2,3,,n} = mulimea poziiilor ocupate de paranteze, i B = {0,1} = mulimea
parantezelor (=0 i )=1 care ndeplinesc urmtoarele condiii:

ED
f(1)=0 i f(n)=1 (expresia ncepe cu parantez deschis i se termin cu o parantez
nchis).
Numrul de valori 0 ale funciei i numrul de valori 1 ale funciei sunt egale cu n/2

P
(numrul de paranteze deschise este egal cu numrul de paranteze nchise).
n timpul construirii soluiei, nu trebuie ca numrul de valori 1 ale funciei s fie mai mare
dect numrul de valori 0 generate pn la acel moment (numrul de paranteze nchise
I
este ntotdeauna cel mult egal cu numrul de paranteze deschise).

1.3.3.8. Problema celor n dame


Se genereaz toate posibilitile de aranjare, pe o tabl de ah, cu dimensiunea nn, a n


dame care s nu se atace ntre ele. Damele se pot ataca ntre ele pe linie, pe coloan i
IC

pe diagonal.
8
Se observ c fiecare dam trebuie s fie plasat singur
7
pe o coloan, ca s nu se atace ntre ele. Soluia proble-
CT

6
mei este dat de mulimea cu n elemente {x1, x2, , xn}
care se memoreaz n stiv. Elementul soluiei xk 5
reprezint numrul liniei n care se aaz dama din 4
coloana k, i se memoreaz pe nivelul k al stivei st. De 3
DA

exemplu, pentru n=8, o soluie este S={4,8,1,5,7,2,6,3} i 2


damele sunt aranjate pe tabla de ah ca n figura 1
alturat. 1 2 3 4 5 6 7 8
DI

Date fiind coordonatele i,j, de pe tabla de


ah ale poziiei unei dame care a fost
C
aezat anterior (linia i este memorat pe
i+p, k
nivelul j n stiv i=st[j]), ca ea s nu atace
RA

dama care urmeaz s fie pus n coloana k


trebuie s fie ndeplinite urmtoarele
A B
condiii interne:
i,j i,k
Dama din coloana k nu trebuie s se
TU

gseasc pe linia i.
Dama din coloana k nu trebuie s se g-
seasc pe diagonala cu dama din coloa- i-p, k
I

na j, adic triunghiul ABC nu trebuie s


ED

fie isoscel. Pentru ca triunghiul ABC s


Informatic 31

C
nu fie isoscel, condiia pe care trebuie s o ndeplineasc dama din coloana k se
poate exprima astfel: oricare ar fi j<k, xj xk i |xk xj| kj.

I
Aceste condiii interne ale soluiei trebuie s se regseasc n condiia de continuare a

OG
soluiei care se verific n subprogramul valid(): st[j]st[k] i abs(st[k]st[j])kj,
pentru orice jk.
#include<iostream.h>
#include<math.h>
typedef int stiva[100];

AG
int n,k,ev,as;
stiva st;
void init() {st[k]=0;}
int succesor()

ED
{if (st[k]<n) {st[k]=st[k]+1; return 1;}
else return 0;}
int valid()
{for(int i=1;i<k;i++)

P
if (st[k]==st[i] || abs(st[k]-st[i])==k-i) return 0;
return 1;}
int solutie() {return k==n;}
I
void tipar()
{for(int i=1;i<=n;i++) cout<<st[i]<<" "; cout<<endl;}
void bt() {//partea fixa a algoritmului }

void main() {cout<<"n= "; cin>>n; bt();}


S se genereze toate posibilitile de aranjare, pe o tabl de ah, cu
IC

Tem dimensiunea nn, a n nebuni, care s nu se atace ntre ei. Nebunul se


poate deplasa numai pe diagonal.
CT

1.3.3.9. Parcurgerea tablei de ah cu un cal


Se caut toate posibilitile de parcurgere a tablei de ah prin sritura calului, fr a trece
de dou ori prin aceeai poziie. Tabla de ah are dimensiunea nn, iar poziia iniial a
DA

calului este dat de i numrul liniei i j numrul coloanei. Se citesc de la tastatur


valorile pentru n, i i j.
Soluia problemei este dat de mulimea cu nn elemente {x1, x2, , xnn} care se
DI

memoreaz n stiv. Elementul soluiei xk reprezint coordonatele i i j ale ptratului n


care se deplaseaz calul la mutarea k i se memoreaz pe nivelul k al stivei st. Pentru
a nregistra traseul strbtut de cal, elementele stivei vor fi de tip nregistrare cu dou
cmpuri, x i y, corespunztoare celor dou coordonate ale ptratului.
RA

struct element{int x,y;};


typedef element stiva[100];
stiva st;
TU

Stiva va avea dimensiunea nn, corespunztoare parcurgerii ntregii table de ah


(kmax=nn), i va conine, n ordine, coordonatele tuturor ptratelor de pe traseul de
parcurgere: st[1].x i st[1].y corespund primei poziii de pe tabl, st[2].x i
st[2].y corespund celei de a doua poziii de pe tabl, , st[n*n].x i st[n*n].y
I

corespund ultimei poziii de pe tabl.


ED
32 Tehnici de programare

C
De exemplu, pentru n=5 i ca poziie de pornire ptratul de pe linia 1 i coloana 1 o
soluie va avea 25 de elemente. Prima dintre soluiile obinute este prezentat mai jos:

I
Ordinea de ocupare a tablei de ah

OG
Soluia 1 1 16 21 10 25
1,1 3,2 5,1 4,3 5,5 2 20 11 24 15 22
3,4 4,2 5,4 3,5 1,4
2,2 4,1 5,3 4,5 2,4 3 17 2 19 6 9

AG
1,2 3,1 5,2 3,3 2,1
4 12 7 4 23 14
1,3 2,5 4,4 2,3 1,5
5 3 18 13 8 5
1 2 3 4 5

ED
Dat fiind o poziie curent i,j a
traseului, variantele posibile 4 3
pentru urmtoarea poziie a i+2, j-1 i+2, j+1

P
calului pe tabla de ah sunt 5 2
prezentate alturat. i+1, j-2 i+1, j+2
I
Se observ c exist 8 variante i,j
posibile pentru continuarea dru-
mului. Coordonatele urmtoru- 6 1
lui ptrat de pe tabla de ah n i-1, j-2 i-1, j+2

care poate sri calul, pentru 7 8


fiecare dintre cele 8 variante, i-2, j-1 i-2, j+1
IC

sunt prezentate n tabel.


Variant Coordonate Variant Coordonate n vectorul p, de dimensiune nn
se pstreaz varianta care s-a ales
CT

1 i-1, j+2 5 i+1, j-2


2 i+1, j+2 6 i-1, j-2 pentru continuarea drumului. Ele-
3 i+2, j+1 7 i-2, j-1 mentele sale sunt de tip ntreg.
4 i+2, j-1 8 i-2, j+1 Elementul k din vector arat care
DA

dintre cele 8 variante s-a ales


pentru a ajunge de la poziia k-1 la poziia k Orice element k al vectorului trebuie s
ndeplineasc urmtoarea condiie: 1 p [k] 8.
Fiecare dintre cele 8 variante de deplasare din ptratul k-1 n ptratul k nseamn
DI

adugarea unei constante de deplasare la coordonata x, respectiv y, a ptratului k-1.


Aceste constante sunt memorate n vectorul d (pentru varianta 0, care nu exist, depla-
sarea este 0):
RA

element d[9]={{0,0},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1}};
Variabila logic este se folosete pentru a ti dac s-a gsit cel puin o soluie (de
exemplu, pentru n=4 problema nu are soluii). Este iniializat cu valoarea 0 (nu s-a gsit
nc nici o soluie). Va lua valoarea 1 (s-a gsit o soluie) n subprogramul tipar() care
TU

se execut numai dac s-a gsit o soluie a problemei.


Subprogramele
Subprogramul init(). Se iniializeaz varianta cu care se trece din ptratul k-1 n
I

ptratul k, adic elementul k din vectorul p: p[k]=0.


ED
Informatic 33

C
Subprogramul succesor(). Se consider c mai exist o posibilitate de continuare a
construirii soluiei pe nivelul k dac mai exist o variant de mutare din ptratul k-1 n
ptratul k, adic dac p[k]<8. Dac mai exist o variant de mutare, pe nivelul k din

I
stiv, se trece la aceast variant (p[k]=p[k]+1) i se nregistreaz coordonatele

OG
ptratului k, care se vor obine prin adugarea, la coordonatele ptratului k-1, a
deplasrilor corespunztoare acestei variante (st[k].x=st[k-1].x+d[p[k]].x i
st[k].y=st[k-1].y+d[p[k]].y).
Subprogramul valid(). Se consider c ptratul k n care s-a ajuns poate fi conside-

AG
rat c este bun pentru a continua construirea soluiei, dac coordonatele sale nu sunt
n afara tablei de ah (coordonatele st[k].x i st[k].y iau valori n intervalul [1,n])
i prin ptratul k nu s-a mai trecut (se verific dac n stiv, pe nivelurile anterioare, nu
mai exist un ptrat cu coordonatele ptratului k).
Subprogramul soluie(). Se verific dac a fost parcurs toat tabla de ah, adic

ED
dac vrful stivei k are valoarea n*n.
Subprogramul bt(). Deoarece coordonatele primului ptrat nu trebuie modificate,
primului element al soluiei (k=1) i se atribuie coordonatele n subprogramul main(),

P
iar n subprogram se va ncepe cu iniializarea nivelului 2 din stiv (k=2); cutarea
tuturor soluiilor se va face pn cnd vrful stivei coboar pn la primul element al
soluiei: while (k>1).
I
#include<iostream.h>
struct element{int x,y;};
element d[9]={{0,0},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1}};

int n,k,ev,as,p[100],este=0;
typedef element stiva[100];
IC

stiva st;
void init() {p[k]=0;}
int succesor()
CT

{if (p[k]<8)
{p[k]=p[k]+1; st[k].x=st[k-1].x+d[p[k]].x;
st[k].y=st[k-1].y+d[p[k]].y; return 1;}
else return 0;}
DA

int valid()
{if (st[k].x<1 || st[k].y<1 || st[k].x>n || st[k].y>n) return 0;
for (int i=1;i<k;i++)
if (st[k].x==st[i].x && st[k].y==st[i].y) return 0;
DI

return 1;}
int solutie() {return k==n*n;}
void tipar()
{int i; este=1;
RA

for (i=1;i<=n*n;i++) cout<<st[i].x<<","<<st[i].y<<" ";


cout<<endl;}
void bt()
{k=2; init();
TU

while (k>1)
{as=1; ev=0;
while(as && !ev)
I

{as=succesor();
ED

if(as) ev=valid();}
34 Tehnici de programare

C
if(as)
if(solutie()) tipar();
else {k++; init();}

I
else k--;}}

OG
void main()
{int i,j; cout<<"n= "; cin>>n;
cout<<"linia de pornire "; cin>>i; st[1].x=i;
cout<<"coloana de pornire "; cin>>j; st[1].y=j; bt();

AG
if (!este) cout<<"Nu exista solutii";}
Observaie. Dac se dorete numai afiarea primei soluii, cutarea soluiei se face
pn cnd variabila este trece de la valoarea 0 (nu s-a gsit soluie) la valoarea 1 (s-a
gsit soluie), modificndu-se n subprogramul bt() condiia de terminare a cutrii tuturor

ED
soluiilor (n loc de while (k>1) se va scrie while (k>1 && !este)) .

S se genereze toate posibilitile de aranjare pe o tabl de ah, cu


Tem dimensiunea nn, a n cai care s nu se atace ntre ei.

P
1.3.3.10. Generarea tuturor soluiilor de ieire din labirint
I
Se caut toate posibilitile unui traseu printr-un labirint, ntre dou poziii, iniial i final,
fr a se trece de dou ori prin aceeai poziie. Labirintul are dimeniunea nm. Poziia
iniial este dat de x1 numrul liniei i y1 numrul Plecare

coloanei care se comunic de la tastatur. Poziia final


corespunztoare ieirii din labirint este dat de x2 numrul
liniei i y2 numrul coloanei care vor fi determinate n
IC

urma gsirii traseului. Deplasarea n labirint se poate face


numai ortogonal (pe vertical i orizontal), nu i pe diagonal.
CT

Soluia problemei este dat de mulimea cu t elemente {x1, x2,


, xt} care se memoreaz n stiv. Numrul de elemente ale
soluiei depinde de soluia gsit. Elementul soluiei xk repre-
zint coordonatele i i j ale ptratului n care se deplaseaz o
DA

persoan n labirint i se memoreaz pe nivelul k al stivei st. Sosire


Pentru a nregistra traseul strbtut, elementele stivei vor fi de
tip nregistrare cu dou cmpuri, x i y, corespunztoare celor dou coordonate ale
ptratului. Stiva va avea dimensiunea t
DI

corespunztoare parcurgerii ntregului traseu,


de la ptratul de plecare pn la ptratul de 1 Nord
sosire, i va conine, n ordine, coordonatele i-1, j
RA

tuturor ptratelor de pe traseul de parcurgere:


st[1].x i st[1].y corespund ptratului de Vest Est
plecare, st[2].x i st[2].y corespund celui 4 i,j 2
de al doilea ptrat n care se trece, , i, j-1 i, j+1
TU

st[t].x i st[t].y corespund ptratului de


sosire, prin care se iese din labirint. 3
Dat fiind o poziie curent i,j a traseului, i+1, j Sud
variantele posibile pentru urmtoarea poziie
I

sunt prezentate alturat.


ED
Informatic 35

C
Se observ c exist 4 variante posibile pentru continuarea drumului. Coordonatele
urmtorului ptrat de pe traseu n care poate s treac persoana, pentru fiecare dintre
cele 8 variante, sunt prezentate n tabel.

I
n vectorul p, de dimensiune nm, se pstreaz varianta

OG
Variant Coordonate
care s-a ales pentru continuarea drumului. Elementele sale
1 i+1, j sunt de tip ntreg. Elementul k din vector arat care dintre
2 i, j+1
cele 4 variante s-a ales pentru a ajunge de la poziia k-1 la
3 i+1, j
poziia k Orice element k al vectorului trebuie s nde-
4 i, j-1

AG
plineasc urmtoarea condiie: 1 p [k] 4.
Fiecare dintre cele 4 variante de deplasare din ptratul k-1 n ptratul k nseamn
adugarea unei constante de deplasare la coordonata x, repsectiv y, a ptratului k-1.
Aceste constante sunt memorate n vectorul d (pentru varianta 0, care nu exist,

ED
deplasarea este 0):
element d[5]={{0,0},{-1,0},{0,1},{1,0},{0,-1}};
Deoarece din ptratul k-1 se poate trece n ptratul k, gsit pe una dintre cele patru

P
direcii de deplasare numai dac cele dou ptrate comunic (exist un culoar ntre ele)
trebuie gsit o metod de descriere a labirintului printr-o matrice L cu dimensiunea nm.
Vor fi prezentate dou metode de reprezentare a labirintului.
I
Varianta 1 Nord: cale blocat;
Fiecare element al matricei L corespunde a patra cifr: 0
unui ptrat din labirint i memoreaz infor-

maii despre micrile care pot fi executate


n ptrat. Fiecrui ptrat i se atribuie un ir Vest: Est:
IC

de patru cifre binare, care va fi construit cale liber; cale liber;


dup urmtoarele reguli: prima cifr: 1 a treia cifr: 1
prima cifr: are valoarea 1, dac se
CT

poate executa un pas spre Vest;


a doua cifr: are valoarea 1, dac se
poate executa un pas spre Sud; Sud: cale blocat;
a treia cifr: are valoarea 1, dac se a doua cifr: 0
DA

poate executa un pas spre Est;


a patra cifr: are valoarea 1, dac se poate executa un pas spre Nord.
Pentru ptratul din exemplu este Elementul matricei corespunztor ptratului
DI

prezentat alturat valoarea ele- 1 0 1 0


mentului care i se asociaz n ma-
tricea L. irul de patru cifre binare prima cifr a patra cifr
formeaz un numr binar, care va fi a doua cifr a treia cifr
RA

transformat ntr-un numr zecimal.

0011 1110 1010 1010 1010 1010 1100 0100 3 14 10 10 10 10 12 4


0100 0101 0010 1010 1010 1100 0111 1001 4 5 2 10 10 12 7 9
TU

0101 0111 1010 1010 1100 0101 0011 1100 5 7 10 10 12 5 3 12


0111 1001 0010 1100 0101 0011 1110 1001 7 9 2 12 5 3 14 9
0111 1110 1000 0101 0111 1100 0011 1000 7 14 8 5 7 10 3 8
0111 1001 0010 1101 0111 1011 1010 1000 7 9 2 13 7 11 10 8
I

0011 1000 0010 1011 1011 1010 1010 1100 3 8 2 11 11 10 10 12


ED
36 Tehnici de programare

C
Pentru a simplifica verificarea condiiei de ieire din labirint, matricea L este bordat cu o
valoare pe care nu o poate lua nici unul dintre elementele ei (de exemplu, valoarea 16).
Matricea L are 7 linii i 8 coloane.
1 1 2

I
Soluia obinut va afia coordonatele ptratelor

OG
2 3
prin care se trece:
3 4 5 6 7
Soluia 4 8
1,1 1,2 2,2 3,2 3,3
5 9
3,4 3,5 4,5 5,5 6,5

AG
7,5 7,6 7,7 7,8 6 10
7 11 12 13 14
Subprogramele
Subprogramul init(). Se iniializeaz varianta 1 2 3 4 5 6 7 8

ED
cu care se trece din ptratul k-1 n ptratul k, adic elementul k din vectorul p: p[k]=0.
Subprogramul succesor(). Se consider c mai exist o posibilitate de continuare a
construirii soluiei pe nivelul k dac mai exist o variant de deplasare din ptratul k-1
n ptratul k, adic dac p[k]<4. Dac mai exist o variant de deplasare, pe nivelul

P
k din stiv, se trece la aceast variant (p[k]=p[k]+1) i se nregistreaz coordo-
natele ptratului k, care se vor obine prin adugarea, la coordonatele ptratului k-1, a
deplasrilor corespunztoare acestei variante (st[k].x=st[k-1].x+d[p[k]].x i
I
st[k].y=st[k-1].y+d[p[k]].y).
Subprogramul valid(). Se consider c ptratul k, n care s-a ajuns, poate fi
considerat c este bun, pentru a continua construirea soluiei, numai dac exist culoar
de trecere ntre ptratul k-1 i ptratul k pe direcia de deplasare aleas (dac n

matricea L, n elementul asociat ptratului k-1, bitul corespunztor direciei de deplasare


IC

are valoarea 1) i dac prin ptratul k nu s-a mai trecut (se verific dac n stiv, pe
nivelurile anterioare, nu mai exist un ptrat cu coordonatele ptratului k).
Subprogramul soluie(). Se verific dac ptratul n care s-a ajuns se afl n afara
CT

matricei (elementul asociat lui n matricea L are valoarea cu care a fost bordat
matricea: L[st[k].x][st[k].y]==16). Pentru a evita soluia prin care se iese din
labirint prin ptratul prin care s-a intrat, n stiv trebuie s existe cel puin dou elemente
(k>2). Deoarece ultimul ptrat din stiv nu face parte din soluia problemei (este ca un
DA

terminator al soluiei), coordonatele lui nu vor fi afiate n subprogramul tipar().


Subprogramul bt(). Deoarece coordonatele primului ptrat nu trebuie modificate, primu-
lui element al soluiei (k=1) i se atribuie coordonatele n subprogramul main(), iar n sub-
program se va ncepe cu iniializarea nivelului 2 din stiv (k=2); cutarea tuturor soluiilor se
DI

va face pn cnd vrful stivei coboar pn la primul element al soluiei: while (k>1).
#include<fstream.h>
struct element{int x,y;};
RA

element d[5]={{0,0},{-1,0},{0,1},{1,0},{0,-1}};
int n,m,k,ev,as,p[100],este=0,L[10][10];
typedef element stiva[100];
stiva st;
TU

fstream f("labirint1.txt",ios::in);
void init() {p[k]=0;}
int succesor()
{if (p[k]<4) {p[k]=p[k]+1;st[k].x=st[k-1].x+d[p[k]].x;
I

st[k].y=st[k-1].y+d[p[k]].y; return 1;}


ED
Informatic 37

C
else return 0;}
int valid()
{int x=st[k-1].x,y=st[k-1].y;

I
for (int i=1;i<k;i++)

OG
if (st[k].x==st[i].x && st[k].y==st[i].y) return 0;
switch (p[k])
{case 1: if (L[x][y] & 1) return 1; break; //spre N
case 2: if (L[x][y] & 2) return 1; break; //spre E

AG
case 3: if (L[x][y] & 4) return 1; break; //spre S
case 4: if (L[x][y] & 8) return 1;} //spre V
return 0;}
int solutie() {return k>2 && L[st[k].x][st[k].y]==16;}

ED
void tipar()
{int i; este=1;
for (i=1;i<k;i++) cout<<st[i].x<<","<<st[i].y<<" ";
cout<<endl;}

P
void bt(){//partea fix a algoritmului ca in exemplul anterior}
void main()
{int i,j; f>>n>>m;
I
for (i=1;i<=n;i++)
for (j=1;j<=m;j++) f>>L[i][j];
cout<<"Intrarea in labirint: "<<endl;
cout<<"x= "; cin>>i; st[1].x=i; cout<<"y= "; cin>>j; st[1].y=j;

for (i=1;i<=n;i++) {L[i][0]=16; L[i][m+1]=16;}


IC

for (i=1;i<=m;i++) {L[0][i]=16; L[n+1][i]=16;}


bt(); if (!este) cout<<"Nu exista solutii";}
Varianta 2
CT

Fiecare element al matricei L corespunde unei poziii din labirint:


1, dac se poate trece prin poziia (i, j) este culoar
L(i , j)
0, dac nu se poate trece prin poziia (i, j) este zid)
DA

Matricea L are 15 linii i 17 coloane. Punctul de intrare n labirint se gsete pe linia 1 i


n coloana 2.
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0
DI

0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 0
0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 0 0
0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0
0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 0
RA

0 1 1 1 0 0 0 0 0 1 0 1 0 0 0 1 0
0 1 1 1 0 1 1 1 0 1 0 1 1 1 1 1 0
0 1 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0
0 1 1 1 1 1 0 1 0 1 1 0 1 1 1 1 0
TU

0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 0 0
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 0
0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
I
ED
38 Tehnici de programare

C
Soluia obinut va afia coordonatele punctelor prin care se trece:
Soluia 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1,2 2,2 2,3 2,4 3,4 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0

I
0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 0

OG
4,4 5,4 6,4 6,5 6,6
0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 0 0
6,7 6,8 6,9 6,10 7,10
0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0
8,10 9,10 10,10 10,11 11,11 0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 0
12,11 12,10 13,10 14,10 14,11 0 1 1 1 0 0 0 0 0 1 0 1 0 0 0 1 0
14,12 14,13 14,14 14,15 14,16 0 1 1 1 0 1 1 1 0 1 0 1 1 1 1 1 0

AG
15,16 0 1 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0
0 1 1 1 1 1 0 1 0 1 1 0 1 1 1 1 0
Subprogramele (sunt prezentate numai 0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 0 0
modificrile fa de varianta anterioar): 0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 0
Subprogramul valid(). Se consider c 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0

ED
poziia k, n care s-a ajuns, poate fi consi- 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
derat c este bun, pentru a continua
construirea soluiei, numai dac ea este culoar de trecere (L[st[k].x][st[k].y]==1)
i dac prin poziia k nu s-a mai trecut (se verific dac n stiv, pe nivelurile anterioare,

P
nu mai exist o poziie cu coordonatele poziiei k).
Subprogramul soluie(). Se verific dac poziia n care s-a ajuns nu se afl la iei-
I
rea din labirint, adic se gsete pe marginea matricei (st[k].x==1 sau
st[k].x==n sau st[k].y==1 sau st[k].y==m).
#include<fstream.h>

struct element{int x,y;};


element d[5]={{0,0},{-1,0},{0,1},{1,0},{0,-1}};
IC

int n,m,k,ev,as,p[100],este=0,L[10][10];
typedef element stiva[100];
stiva st;
CT

fstream f("labirint1.txt",ios::in);
void init() {p[k]=0;}
int succesor()
{if (p[k]<4) {p[k]=p[k]+1;st[k].x=st[k-1].x+d[p[k]].x;
DA

st[k].y=st[k-1].y+d[p[k]].y; return 1;}


else return 0;}
int valid ()
{if (L[st[k].x][st[k].y]==0) return 0;
DI

for (int i=1;i<k;i++)


if (st[k].x==st[i].x && st[k].y==st[i].y) return 0;
return 1;}
int solutie()
RA

{return st[k].x==1 || st[k].x==n || st[k].y==1 || st[k].y==m;}


void tipar()
{for (int i=1,este=1;i<=k;i++) cout<<st[i].x<<","<<st[i].y<<" ";
cout<<endl;}
TU

void bt(){//partea fix a algoritmului ca in exemplul anterior}


void main()
{int i,j; f>>n>>m;
I

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

for (j=1;j<=m;j++) f>>L[i][j];


Informatic 39

C
cout<<"Intrarea in labirint: "<<endl;
cout<<"x= "; cin>>i; st[1].x=i; cout<<"y= "; cin>>j; st[1].y=j;
bt(); if (!este) cout<<"Nu exista solutii";}

I
OG
Observaie. Algoritmul folosit pentru generarea tuturor traseelor de ieire dintr-un labirint poate
fi folosit n orice problem de gsire a unui traseu pe o suprafa mprit n ptrate i pentru
care exist restricii de deplasare de la un ptrat la altul.
1. Problema bilei. Un teren este mprit n mai multe zone, fiecare

AG
Tem zon avnd o nlime h. Pentru simplificare, vom considera fiecare
zon ca fiind un ptrat cu aceeai dimensiune. Terenul poate fi
reprezentat sub forma unei matrice cu n linii i m coloane, fiecare element al matricei
reprezentnd nlimea unei zone de teren. O bil se gsete ntr-o zon cu coordo-
natele x (numrul liniei) i y (numrul coloanei). Ea se poate rostogoli numai ctre o

ED
zon care are nlimea mai mic dect cea a zonei n care se gsete. S se genereze
toate posibilitile de rostogolire a bilei pn la marginea terenului. Indicaie. Construi-
rea soluiei traseului are urmtoarele caracteristici:
O soluie este format din coordonatele zonelor prin care se rostogolete bila.

P
Fiecare soluie are un numr variabil de elemente. Primul element al soluiei conine
coordonatele zonei de plecare a bilei, iar ultimul element al soluiei conine coordo-
I
natele unei zone de la marginea terenului.
Bila se poate rostogoli n 8 direcii (corespunztoare celor 8 ptrate adiacente ptra-
tului n care se gsete), fiecare direcie de deplasare corespunznd unei constante
de deplasare care se adaug la coordonata x, respectiv y, a ptratului n care se

gsete bila.
Condiia de continuare a construirii soluiei este ca ptratul n care a ajuns bila s
IC

aib nlimea mai mic dect a ptratului anterior.


2. Problema capcanelor. Un teren este mprit n mai multe zone. Pentru simplificare
CT

vom considera fiecare zon ca fiind un ptrat cu aceeai dimensiune. Terenul poate fi
reprezentat sub forma unei matrice cu n linii i m coloane, fiecare element al matricei
reprezentnd un ptrat de teren. Anumite ptrate conin diverse capcane ascunse. O
persoan se gsete n ptratul cu coordonatele x1 (numrul liniei) i y1 (numrul
DA

coloanei) i trebuie s ajung n ptratul cu coordonatele x2 i y2 deplasndu-se orto-


gonal i fr s calce n ptratele cu capcane. Datele se citesc dintr-un fiier text, astfel:
de pe primul rnd, n, m i coordonatele ptratului de pornire i ale ptratului destinaie,
iar de pe urmtoarele rnduri perechile de coordonate ale ptratelor cu capcane. S
DI

se gseasc traseele pe care trebuie s le urmeze persoana respectiv. Indicaie.


Construirea soluiei traseului are urmtoarele caracteristici:
O soluie este format din coordonatele zonelor prin care trece persoana.
Fiecare soluie are un numr variabil de elemente. Primul element al soluiei conine
RA

coordonatele ptratului din care pleac persoana, iar ultimul element al soluiei
conine coordonatele ptratului n care trebuie s ajung.
Persoana se poate deplasa n 4 direcii (corespunztoare celor 4 ptrate aflate pe
diagonala ptratului n care se gsete), fiecare direcie de deplasare corespunznd
TU

unei constante de deplasare care se adaug la coordonata x, respectiv y, a


ptratului n care se gsete persoana.
Condiia de continuare a construirii soluiei este ca ptratul n care a ajuns per-
soana s nu conin capcane.
I
ED
40 Tehnici de programare

C
1.4. Metoda Divide et Impera
1.4.1. Descrierea metodei Divide et Impera

I
OG
Metoda divide et impera se poate folosi pentru problemele care pot fi descompuse n
subprobleme similare cu problema iniial (care se rezolv prin aceeai metod) i care
prelucreaz mulimi de date de dimensiuni mai mici, independente unele de altele (care
folosesc mulimi de date de intrare disjuncte).

AG
Scop: identificarea problemelor care pot fi descompuse n subprobleme similare care
folosesc mulimi de date de intrare disjuncte.

ED
Enunul problemei 1: S se calculeze suma elementelor dintr-un vector v care conine
numere ntregi.
Mulimea datelor de intrare o reprezint cele n elemente ale vectorului v. Ele pot fi divizate

P
n cte dou submulimi disjuncte, prin divizarea mulimii indicilor n dou submulimi.
Mulimea iniial a indicilor este determinat de primul indice (s) i de ultimul indice (d), iar
intervalul indicilor care se divizeaz este [s,d]. El se divizeaz n dou submulimi disjuncte,
I
[s,m] i [m+1,d], unde m este indicele din mijlocul intervalului: m=(s+d)/2. Astfel, problema
iniial este descompus n dou subprobleme, fiecare dintre ele constnd n calcularea
sumei numerelor dintr-o submulime de elemente (care corespunde unui subinterval al

indicilor). Descompunerea continu pn cnd fiecare submulime conine un singur


element i se poate calcula suma, obinndu-se soluia subproblemei.
IC

Enunul problemei 2: S se calculeze suma 12+23+ ... +n(n+1).


Mulimea datelor de intrare o reprezint primele n numere naturale. Mulimea iniial este
determinat de primul numr (s=1) i de ultimul numr (d=n), iar intervalul care se divi-
CT

zeaz este [s,d]. El se divizeaz n dou submulimi disjuncte, [s,m] i [m+1,d], unde m
este numrul din mijlocul intervalului: m=(s+d)/2. Astfel, problema iniial este descompus
n dou subprobleme, fiecare dintre ele constnd n calcularea sumei produselor dintre
DA

dou numere consecutive dintr-o submulime de elemente (care corespunde unui subinter-
val al numerelor). Descompunerea continu pn cnd fiecare submulime conine un
singur element i se poate calcula produsul, care se va aduga la sum, pentru a obine
soluia subproblemei.
DI

Enunul problemei 3: S se genereze termenul n al irului lui Fibonacci.


irul lui Fibonacci este definit recursiv: f1=1, f2=1 i fn= fn-2+ fn-1, pentru n3. Problema
determinrii termenului n al irului lui Fibonacci se poate descompune n dou subpro-
bleme: determinarea termenului n-1 i determinarea termenului n-2. Descompu-
RA

nerea continu pn cnd trebuie determinai termenii f1 i f2, a cror valoare este
cunoscut.

Metoda Divide et impera se bazeaz pe descompunerea unei probleme n


TU

subprobleme similare, prin intermediul unui proces recursiv. Procesul recursiv de


descompunere a unei subprobleme n alte subprobleme continu pn se obine
o subproblem cu rezolvarea imediat (cazul de baz), dup care se compun
soluiile subproblemelor pn se obine soluia problemei iniiale.
I
ED
Informatic 41

C
Paii algoritmului sunt:
PAS1. Se descompune problema n subprobleme similare problemei iniiale, de dimen-
siuni mai mici, independente unele de altele (care folosesc mulimi de date de

I
intrare disjuncte di).

OG
PAS2. Dac subproblema permite rezolvarea imediat (corespunde cazului de baz),
atunci se rezolv obinndu-se soluia s; altfel, se revine la Pas1.
PAS3. Se combin soluiile subproblemelor n care a fost descompus (si) o subproble-
m, pn cnd se obine soluia problemei iniiale.

AG
1.4.2. Implementarea metodei Divide et Impera
Deoarece subproblemele n care se descompune problema sunt similare cu problema inii-
al, algoritmul divide et impera poate fi implementat recursiv. Subprogramul recursiv

ED
divide_et_impera(d,s), unde d reprezint dimensiunea subproblemei (corespunde mulimii
datelor de intrare), iar s soluia subproblemei, poate fi descris n pseudocod astfel:
divide_et_impera(d,s)
nceput

P
dac dimensiunea d corespunde unui caz de baz
atunci se determin soluia s a problemei;
I
altfel
pentru i=1,n execut
se determin dimensiunea d i a subproblemei P i;
se determin soluia s i a subproblemei P i prin

apelul divide_et_impera(d_i,s_i);
sfrit_pentru;
IC

se combin soluiile s 1, s 2, s 3, ..., s n;


sfrit_dac;
sfrit;
CT

Implementarea acestui algoritm n limbajul C++ se face astfel:


/*declaraii globale pentru datele de intrare ce vor fi divizate n sub-
mulimi disjuncte pentru subproblemele n care se descompune problema*/
DA

void divizeaza(<parametri: submulimile>)


{//se divizeaz mulimea de date de intrare n submulimi disjuncte d i}
void combina(<parametri: soluiile s i care se combin>)
{//se combin soluiile obinute s i}
DI

void dei(<parametri: mulimea de date d i soluia s>)


{//declaraii de variabile locale
if (<este caz de baz>) {//se obine soluia corespunztoare subproblemei}
else
RA

{divizeaza(<parametri: k submulimi>);
for (i=1;i=k;i++)
dei(<parametri: mulimea de date d i i soluia s i>);
combina(<parametri: soluiile s i>);}}
TU

void main()
{//declaraii de variabile locale
//se citesc datele de intrare ale problemei mulimea d
dei(<parametri: mulimea de date d i soluia s>);
I

//se afieaz soluia problemei s}


ED
42 Tehnici de programare

C
Exemplul 1. S se calculeze suma elementelor pare dintr-un vector v care conine nume-
re ntregi. Numrul de elemente ale vectorului (n) i elementele lui se citesc de la tastatur.
s=1 1 2 3 4 5 d=5

I
OG
5 10 15 20 25
m=(1+5)/2=3
z=z12345= z123+ z45=10+20=30

1 2 3 4 5

AG
s=1 5 10 15 d=3 s=4 20 25 d=5
m=(1+3)/2=2 m=(4+5)/2=4
z123= z12+ z45= z4+ z5=20+0=20
z3=10+0=10

ED
1 2 3 4 5
s=1 5 10 d=2 15 20 25
m=(1+2)/2=1 s=d=3 s=d=4 s=d=5
z12= z1+ z2=0+10=10 z3=0 z4=20 z5=0

1 2
P
I
s=d=1 5 10 s=d=2
z1=0 z2=10
Implementarea metodei divide et impera n acest exemplu se face astfel:

Subprogramul divizeaza() Numrul de subprobleme n care se descompune problema


este 2 (k=2). Mulimea datelor de intrare este divizat n dou submulimi disjuncte, prin
IC

divizarea mulimii indicilor n dou submulimi disjuncte de indici, adic mulimea indicilor
[s,d] (unde s este primul indice, iar d ultimul indice) este divizat n dou submulimi disjunc-
te [s,m] i [m+1,d], unde m este indicele din mijlocul intervalului: m=(s+d)/2. n subpro-
CT

gram, procesul de divizare const n determinarea mijlocului intervalului m.


Subprogramul combina() Combinarea soluiei nseamn adunarea celor dou sume
obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele
dou valori obinute din prelucrarea celor dou intervale, adic se adun cele dou
DA

valori x i y, obinndu-se soluia z.


Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd sub-
mulimea conine un singur element (se poate calcula suma, obinndu-se soluia subpro-
blemei). Dac s-a terminat procesul recursiv (prin procesul de divizare, cele dou capete
DI

ale intervalului au ajuns s fie identice), atunci se prelucreaz cazul de baz (se calcu-
leaz suma n variabila z, corespunztoare soluiei, astfel: dac numrul v[s] este par,
atunci suma va fi chiar numrul; altfel, are valoarea 0); altfel, se apeleaz subproramul
pentru divizarea intervalului, se apeleaz subprogramul dei() pentru primul interval, se
RA

apeleaz subprogramul dei() pentru al doilea interval i se combin cele dou rezultate.
#include<iostream.h>
int v[100],n;
TU

void divizeaza(int s,int d,int &m) {m=(s+d)/2;}


void combina(int x,int y,int &z) {z=x+y;}
void dei(int s,int d,int &z)
{int m,x1,x2;
I

if (d==s)
ED
Informatic 43

C
if (v[s]%2==0) z=v[s]; else z=0;
else
{divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}

I
void main()

OG
{int i,z; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}
dei(1,n,z); cout<<"suma= "<<z;}
Exemplul 2: S se calculeze suma 12+23+ ... +n(n+1).

AG
s=1 1 2 3 4 5 d=5
m=(1+5)/2=3
z=z12345= z123+ z45=20+50=70

ED
s=1 1 2 3 d=3 s=4 4 5 d=5
m=(1+3)/2=2 m=(4+5)/2=4
z123= z12+ z3=8+12=20 z45= z4+ z5=20+30=50

s=1 1 2
m=(1+2)/2=1
d=2 3
s=d=3
P 4
s=d=4
5
s=d=5
I
z12= z1+ z2=2+6=8 z3=34=12 z4=45=20 z5=56=30

s=d=1 1 2 s=d=2

z1=12=2 z2=23=6
Implementarea metodei divide et impera n acest exemplu se face astfel:
IC

Subprogramul divizeaza() Numrul de subprobleme n care se descompune pro-


blema este 2 (k=2). Mulimea datelor de intrare este divizat n dou submulimi disjunc-
CT

te, prin divizarea mulimii primelor n numere naturale n dou submulimi disjuncte, adi-
c mulimea [s,d] (unde s este primul numr din mulime, iar d ultimul numr din
mulime) este divizat n dou submulimi disjuncte, [s,m] i [m+1,d], unde m este nu-
mrul din mijlocul intervalului: m=(s+d)/2. n subprogram, procesul de divizare const
DA

n determinarea mijlocului intervalului, m.


Subprogramul combina() Combinarea soluiei nseamn adunarea celor dou sume
obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele
dou valori obinute din cele dou intervale (se adun cele dou valori, x i y) obinn-
DI

du-se soluia z.
Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd sub-
mulimea conine un singur element (se poate calcula termenul sumei produsul celor
dou numere consecutive obinndu-se soluia subproblemei). Dac s-a terminat
RA

procesul recursiv (prin procesul de divizare, cele dou capete ale intervalului au ajuns
s fie identice), atunci se prelucreaz cazul de baz (se calculeaz produsul n variabila
z, corespunztoare soluiei); altfel, se apeleaz subprogramul pentru divizarea inter-
valului, se apeleaz subprogramul dei() pentru primul interval, se apeleaz subpro-
TU

gramul dei() pentru al doilea interval i se combin cele dou rezultate.


#include<iostream.h>
int n;
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}
I
ED

void combina(int x,int y,int &z) {z=x+y;}


44 Tehnici de programare

C
void dei(int s,int d,int &z)
{int m,x1,x2;
if (d==s) z=s*(s+1);

I
else {divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}

OG
void main()
{int z; cout<<"n= ";cin>>n; dei(1,n,z); cout<<"suma ="<<z; }
Exemplul 3: S se calculeze termenul n al irului lui Fibonacci.
f(2) =1

AG
f(3)
f(4) z=1+1=2 f(1) =1
f(5) z=2+1=3 f(2) =1
z=3+2=5

ED
f(2) =1
f(3)
z=1+1=2 f(1) =1

P
f(6) f(2) =1
z=5+3=8 f(3)
z=1+1=2
I
f(4) f(1) =1
z=2+1=3 f(2) =1

Implementarea metodei divide et impera n acest exemplu se face astfel:


Subprogramul divizeaza() Numrul de subprobleme n care se descompune


problema este 2 (k=2): determinarea termenului n-1 i determinarea termenului n-2.
IC

Descompunerea se face implicit, prin parametrul cu care se apeleaz subprogramul


dei(), i subprogramul de divizare nu mai este necesar.
Subprogramul combina() Combinarea soluiei nseamn adunarea celor doi termeni
CT

ai irului (x1 i x2), obinndu-se soluia z.


Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd s-a ajuns
la un termen direct calculabil. Dac s-a terminat procesul recursiv (prin procesul de divizare
s-a ajuns la termenul f1 sau f2), atunci se prelucreaz cazul de baz; altfel, se apeleaz
DA

subprogramul dei() pentru primul termen al descompunerii, se apeleaz subprogramul


dei()pentru al doilea termen al descompunerii i se combin cele dou rezultate.
#include<iostream.h>
int n;
DI

void combina(int x1,int x2,int &z) {z=x1+x2;}


void dei(int n,int &z)
{int x1,x2;
RA

if (n==1 || n==2) z=1;


else {dei(n-1,x1); dei(n-2,x2); combina(x1,x2,z);}}
void main()
{int z; cout<<"n= "; cin>>n; dei(n,z); cout<<z;}
TU

n acest exemplu, problema a fost descompus n probleme care nu


Atenie sunt independente unele de altele i, n apelurile recursive,
aceeai subproblem este rezolvat de mai multe ori: f(4), f(3), f(2),
f(1). Pentru acest tip de problem nu se recomand metoda divide et impera deoarece
I

nu este eficient.
ED
Informatic 45

C
Exemplul 4: S se determine simultan valoarea minim i valoarea maxim dintr-un
vector v care conine numere ntregi. Numrul de elemente ale vectorului (n) i elementele
lui se citesc de la tastatur.

I
Implementarea metodei divide et impera n acest exemplu se face astfel:

OG
Subprogramul divizeaza() Numrul de subprobleme n care se descompune pro-
blema este 2 (k=2). Divizarea mulimii datelor de intrare se face la fel ca la exemplul
pentru calcularea sumei elementelor unui vector i subprogramele sunt identice.
Subprogramul combina() Combinarea soluiei nseamn determinarea minimului (z1)

AG
i a maximului (z2) dintre cele dou valori minime (x1 i y1), respectiv maxime (x2 i y2),
obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele
dou perechi de valori obinute din cele dou intervale. Dac x1>y1, atunci minimul (z1)
este y1; altfel, este x1. Dac x2>y2, atunci maximul (z2) este x2; altfel, este y2.

ED
Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd
submulimea conine un singur element (se pot calcula minimul i maximul; att minimul
ct i maximul vor avea valoarea elementului). Dac s-a terminat procesul recursiv (prin
procesul de divizare cele dou capete ale intervalului au ajuns s fie identice), atunci se

P
prelucreaz cazul de baz (se calculeaz minimul i maximul n variabilele z1 i z2
corespunztoare soluiei); altfel, se apeleaz subprogramul pentru divizarea interva-
lului, se apeleaz subprogramul dei() pentru primul interval, se apeleaz subpro-
I
gramul dei() pentru al doilea interval i se combin cele dou rezultate.
#include<iostream.h>
int v[100],n;

void divizeaza(int s,int d,int &m){m=(s+d)/2;}


void combina(int x1,int y1,int &z1,int x2,int y2,int &z2)
IC

{if (x1>y1) z1=y1; else z1=x1;


if (x2>y2) z2=x2; else z2=y2;}
void dei(int s,int d,int &z1, int &z2) //z1 minim, z2 maxim
CT

{int m,x1,x2,y1,y2;
if (d==s) z1=z2=v[s];
else {divizeaza(s,d,m);
dei(s,m,x1,x2); //x1 minim, x2 maxim
DA

dei(m+1,d,y1,y2); //y1 minim, y2 maxim


combina(x1,y1,z1,x2,y2,z2);}}
void main()
{int i,z1,z2; cout<<"n= ";cin>>n;
DI

for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}


dei(1,n,z1,z2);
cout<<"minimul ="<<z1<<endl<<"maximul ="<<z2<<endl;}
RA

Exemplul 5: S se calculeze suma a dou polinoame. Gradele celor dou polinoame, n


i m, i coeficienii celor dou polinoame se citesc de la tastatur. Coeficienii celor dou
polinoame se memoreaz n vectorii p i q, iar coeficienii polinomului sum se memoreaz
n vectorul r.
TU

Implementarea metodei divide et impera n acest exemplu se face astfel:


Subprogramul divizeaza() Numrul de subprobleme n care se descompune pro-
blema este 2 (k=2). Deoarece exist dou mulimi de date de intrare (vectorii p i q care
memoreaz coeficienii celor dou polinoame), se va lua ca reper mulimea cu cele mai
I

multe elemente. Mulimea datelor de intrare este divizat n dou submulimi disjuncte,
ED
46 Tehnici de programare

C
prin divizarea mulimii indicilor n dou submulimi disjuncte de indici, adic mulimea
indicilor [s,d] (unde s este primul indice, iar d este ultimul indice d=maxim(n,m)+1)
este divizat n dou submulimi disjuncte [s,mijl] i [mijl+1,d], unde mijl este indicele

I
din mijlocul intervalului: mijl=(s+d)/2. Procesul de divizare este identic cu cel de la

OG
exemplele anterioare.
Subprogramul combina() Deoarece n cazul de baz se determin unul dintre coe-
ficienii polinomului sum care se scrie direct n vectorul r, acest subprogram nu mai
este necesar.

AG
Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd submul-
imea conine un singur element (se poate calcula coeficientul polinomului sum). Dac
s-a terminat procesul recursiv (prin procesul de divizare, cele dou capete ale intervalului
au ajuns s fie identice), atunci se prelucreaz cazul de baz, prin care se calculeaz
coeficientul polinomului sum pentru acel indice (dac termenul care se calculeaz are

ED
indicele mai mic dect gradul minim al polinoamelor, atunci el este egal cu suma coefi-
cienilor celor dou polinoame; altfel, dac polinomul p are gradul mai mic dect al polino-
mului q, atunci el este egal cu coeficientul polinomului q; altfel, el este egal cu coeficientul
polinomului p); altfel, se apeleaz subprogramul pentru divizarea intervalului, se apelea-

P
z subprogramul dei() pentru primul interval i apoi pentru al doilea interval.
#include<iostream.h>
I
int p[10],q[10],r[10],n,m;
int maxim(int x,int y) {if (x>y) return x; else return y;}
int minim(int x,int y) {if (x>y) return y; else return x;}
void divizeaza(int s,int d,int &mijl) {mijl=(s+d)/2;}

void dei(int s,int d)


IC

{int mijl;
if (d==s)
if (d<=minim(n,m)) r[d]=p[d]+q[d];
CT

else if(n<m) r[d]=q[d];


else r[d]=p[d];
else {divizeaza(s,d,mijl); dei(s,mijl); dei(mijl+1,d);}}
void main()
DA

{int i; cout<<"n= ";cin>>n; cout<<"m= ";cin>>m;


for(i=1;i<=n+1;i++) {cout<<"p("<<i-1<<")= "; cin>>p[i];}
for(i=1;i<=m+1;i++) {cout<<"q("<<i-1<<")= "; cin>>q[i];}
dei(1,maxim(n,m)+1);
DI

for(i=maxim(n,m)+1;i>=1;i--)
if (r[i]!=0)
{if (r[i]!=1) {cout<<r[i]; if (i!=1) cout<<"*";}
if (i>2) cout<<"x^"<<i-1; else if (i==2) cout<<"x";
RA

if (i!=1) cout<<" + ";}}


1. Programul urmtor afieaz, n ordine invers, elementele unui
Tem vector. Explicai cum a fost folosit metoda divide et impera pentru a
rezolva problema.
TU

#include<iostream.h>
int v[100],n;
void divizeaza(int s,int d,int &m)
I

{m=(s+d)/2;}
ED
Informatic 47

C
void dei(int s,int d)
{int m;
if (d==s) cout<<v[s]<<" ";

I
else {divizeaza(s,d,m); dei(m+1,d); dei(s,m);}}

OG
void main()
{int i; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"a("<<i<<")= "; cin>>v[i];}
dei(1,n);}

AG
2. Determinai ce calculeaz programul urmtor. Explicai cum a fost folosit metoda
divide et impera pentru a rezolva problema.
#include<iostream.h>
int n;

ED
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}
void combina(int x,int y,int &z) {z=x+y;}
void dei(int s,int d,int &z)
{int m,x1,x2;

P
if (d==s) {if(s%2==0) z=-s*5;else z=s*5;}
else
{divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}
I
void main()
{int z; dei(1,20,z); cout<<"suma = "<<z;}
Scriei urmtoarele programe, n care folosii metoda divide et impera.

Tem Valorile pentru datele de intrare se citesc de la tastatur.


1. S se calculeze n!.
IC

2. S se calculeze simultan produsul i suma a n numere memorate ntr-un vector.


3. S se calculeze suma 1+12+123+...+123...n.
4. S se numere elementele pare dintr-un vector.
CT

5. S se verifice dac un vector conine numai numere pozitive sau numai numere negative.
6. S se calculeze c.m.m.d.c. a n numere memorate ntr-un vector.
7. S se determine numrul de apariii ale unei valori x ntr-un vector.
8. S se calculeze valoarea unui polinom P(x) ntr-un punct x precizat.
DA

9. ntr-o matrice cu n linii i m coloane, s se interschimbe coloana p cu coloana q.


10. ntr-o matrice ptrat cu dimensiunea n s se interschimbe linia p cu coloana q.
11. ntr-o matrice ptrat cu dimensiunea n s se interschimbe diagonala principal cu
diagonala secundar.
DI

12. S se determine simultan valoarea minim i valoarea maxim, dintr-o matrice cu n linii
i m coloane.
Complexitatea algoritmului divide et impera
RA

Metoda divide et impera se bazeaz pe rezolvarea recursiv a subproblemelor n care


este divizat problema iniial.
Atunci cnd un algoritm conine un apel recursiv, timpul su de execuie este dat de o formul
TU

recursiv care calculeaz timpul de execuie al algoritmului pentru o dimensiune n a datelor


de intrare, cu ajutorul timpilor de execuie pentru dimensiuni mai mici. Timpul de execuie al
unui algoritm care folosete metoda divide et impera se bazeaz pe calculul timpilor de exe-
cuie ai celor trei etape de rezolvare a problemei. Dac:
I
ED
48 Tehnici de programare

C
problema iniial se divizeaz n a subprobleme, pentru care dimensiunea datelor de
intrare reprezint 1/b din dimensiunea problemei iniiale;
timpul de execuie a problemei iniiale este T(n);

I
timpul necesar pentru a divide problema n subprobleme este D(n);

OG
timpul necesar pentru combinarea soluiilor subproblemelor, pentru a obine soluia
problemei, este C(n);
timpul necesar pentru rezolvarea cazului (1) pentru cazul de baz
de baz este (1); T(n) =
aT(n/b)+D(n)+C(n) n caz contrar

AG
atunci se obine funcia pentru timpul de exe-
cuie care este prezentat alturat.
De exemplu, pentru a calcula suma elementelor unui vector cu n elemente, problema se
descompune n dou subprobleme (a=2) i dimensiunea datelor de intrare pentru o subpro-

ED
blem reprezint jumtate din dimensiunea datelor iniiale (b=2). Pentru divizarea problemei
n subprobleme, se calculeaz mijlocul intervalului de indici i O(D(n))=(1)). Pentru combi-
narea celor dou soluii ale fiecrei subprobleme, se adun cele dou valori, i O(C(n))=(1).
k
Considerm c n=2 . Rezult c:

P
k k-1 k-1 2
T(n)=T(2 )+2(1) = 2(T(2 )+2(1))+2(1 )= 2(T(2 )+2 (1) =
k-2 2 2 k-2 3
2(2T(2 )+2(1))+2 (1)=2 T(2 )+2 (1) = ... =
k 0 k+1 k k+1 k
2 T(2 )+2 (1) = 2 (1)+2 (1) = 2 3 = n3.
I
Ordinul de complexitate al algoritmului este O(n). Algoritmul iterativ pentru rezolvarea
acestei probleme are ordinul de complexitate O(n).
Observaie. Pentru acest gen de probleme, metoda iterativ este mai eficient. Rezolvarea

acestui tip de probleme cu ajutorul metodei divide et impera a avut numai un rol scolastic,
pentru nelegerea metodei i a implementrii ei.
IC

Metoda divide et impera se recomand n urmtoarele cazuri:


algoritmul obinut este mai eficient dect algoritmul clasic (iterativ) de exemplu, algo-
CT

ritmul de cutare ntr-un vector sortat i algoritmii pentru sortarea unui vector;
rezolvarea problemei prin divizarea ei n subprobleme este mai simpl dect rezol-
varea clasic (iterativ) de exemplu, problema turnurilor din Hanoi i generarea unor
modele fractale.
DA

1.4.3. Cutarea binar


S se caute, ntr-un ir de numere ntregi ordonate strict cresctor (sau varianta strict des-
cresctor), poziia n care se gsete n ir o valoare x citit de la tastatur. Dac valoarea
DI

nu se gsete n ir, s se afieze un mesaj de informare.


Algoritmul de cutare secvenial ntr-un vector are ordinul de complexitate O(n). Pornind
de la faptul c vectorul este un vector particular (este ordonat strict cresctor sau strict
RA

descresctor), se poate folosi metoda divide et impera. Pentru un vector ordonat strict
cresctor, paii algoritmului sunt:
PAS1. Se divizeaz vectorul v n doi subvectori, prin divizarea mulimii indicilor [s,d] (unde
s este indicele primului element, iar d indicele ultimului element) n dou submulimi
TU

disjuncte, [s,m] i [m+1,d], unde m este indicele din mijlocul intervalului: m=(s+d)/2.
PAS2. Dac elementul situat pe poziia din mijloc (v[m]) are valoarea x, atunci proble-
ma este rezolvat i poziia este m; altfel, dac elementul din mijlocul vectorului
este mai mic dect valoarea x, atunci cutarea se face printre elementele cu
I

indicii n mulimea [s,m]; altfel, cutarea se face printre elementele cu indicii din
ED
Informatic 49

C
mulimea [m+1,d]. Pasul 2 se execut pn cnd se gsete elementul sau pn
cnd vectorul nu mai poate fi mprit n subvectori.
#include<iostream.h>

I
OG
int v[100],n,x;
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}
void cauta(int s,int d,int &z)
{int m;
if (d>s){divizeaza(s,d,m);

AG
if (v[m]==x) z=m;
else if (x>v[m]) cauta(m+1,d,z);
else cauta(s,m,z);}}
void main()

ED
{int i,z=0; cout<<"n= ";cin>>n; cout<<"x= ";cin>>x;
for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}
cauta(1,n,z);
if(z==0) cout<<"nu exista elementul "<<x<<" in vector";

P
else cout<<"exista pe pozitia "<<z;}
Complexitatea algoritmului de cutare binar. Pentru divizarea problemei n subpro-
bleme, se calculeaz mijlocul intervalului de indici i O(D(n))=(1). Deoarece cutarea se
I
face numai ntr-unul dintre cei doi subvectori (problema iniial se rezolv prin rezolvarea
uneia dintre cele dou subprobleme) i a=1, formula recurent a timpului de execuie
k
este T(n)= T(n/2)+(1). Considerm c n=2 (k=log2n). Rezult c:

k k-1 k-1
T(n)=T(2 )+(1) = (T(2 ) +(1)) +(1)= T(2 )+2(1)) = ... =
0
T(2 )+(k+1)(1) = (1)+ (k+1)(1) = (k+2)(1)= log2n (1).
IC

Ordinul de complexitate al algoritmului este O(log2n).


Aplicarea algoritmului de cutare binar
CT

Exemplu. S se determine, cu o precizie de 4 zecimale, rdcina real, din intervalul [0,1], a


3
ecuaiei x +x-1=0.
S-a identificat pentru aceast ecuaie o rdcin n intervalul [0,1] i ne propunem s locali-
DA

zm aceast rdcin, n limitele unei precizii de 4 zecimale, printr-o valoare x. Pentru cuta-
rea valorii x se va folosi metoda biseciei care const n reducerea intervalului de cutare
prin njumtirea repetat i selectarea subintervalului n care se gsete rdcina. Intervalul
[s,d] este mprit n dou subintervale, [s,m] i [m,d], unde m=(s+d)/2. Cutarea rdcinii
3
DI

se va face n subintervalul n care funcia f(x)=x +x-1 i schimb semnul, astfel: dac
f(s)*f(m)<0, atunci cutarea continu n intervalul [s,m]; altfel, cutarea continu n subinter-
valul [m,d]. Procesul recursiv este ntrerupt cnd se ajunge la intervalul [s,d] pentru care
d-s<r, unde r este eroarea acceptat pentru o precizie de 4 zecimale i are valoarea 0,0001.
RA

#include<iostream.h>
#include<iosmanip.h>
const float r=0.0001;
float f(float x) {return x*x*x+x-1;}
TU

void divizeaza(float s,float d,float &m) {m=(s+d)/2;}


void radacina(float s,float d,float &z)
{float m;
I

if (d-s<r) z=(s+d)/2;
ED

else
50 Tehnici de programare

C
{divizeaza(s,d,m);
if (f(s)*f(m)<0) radacina(s,m,z);
else radacina(m,d,z);}}

I
void main()

OG
{float z=0; radacina(0,1,z); cout<<"radacina= "<<z<<endl;
cout<<"f(x)= "<<setiosflags(ios::fixed)<<f(z); }
1. S se caute, ntr-un ir de numere ntregi, n care mai nti se gsesc
Tem numerele pare i apoi numerele impare, poziia n care se gsete, n

AG
ir, o valoare x citit de la tastatur.
2. S se calculeze radicalul de ordinul 2 din numrul a, cu o aproximaie de 4 zecimale,
fr a folosi funcia matematic de sistem sqrt(). S se compare rezultatul obinut cu
rezultatul furnizat de funcia matematic de sistem. Indicaie. Pornind de la ecuaia

ED
2
x -a=0, se va identifica intervalul n care se gsete soluia i apoi se va localiza, cu o
precizie de 4 zecimale, rdcina real din acest interval.
3. S se calculeze partea ntreag a radicalului de ordinul 3 din numrul a fr a folosi
funcia matematic de sistem.

P
4. S se calculeze radicalul de ordinul 3 din numrul a, cu o aproximaie de 4 zecimale.

1.4.4. Sortarea rapid (QuickSort)


I
Prin aceast metod de sortare se execut urmtoarele operaii prin care sunt rearanjate
elementele din cadrul vectorului:

X1 X2 X3 Xi-1 Xi Xi+1 Xn-1 Xn


IC

Pivotul Vectorul iniial


CT

Primul element din vector, numit pivot, este mutat n cadrul vectorului pe poziia pe
care trebuie s se gseasc n vectorul sortat.
Toate elementele mai mici dect el vor fi mutate n vector n faa sa.
DA

Toate elementele mai mari dect el vor fi mutate n vector dup el.

Xs Xs+1 Xs+2 Xm-1 Xm Xm+1 Xd-1 Xd


DI

Subvectorul din stnga pivotului Subvectorul din dreapta pivotului


(elemente mai mici dect pivotul) Pivotul (elemente mai mari dect pivotul)
RA

De exemplu, dac vectorul conine elementele {3, 4, 1, 5, 2}, dup executarea operaiilor
precizate vectorul va fi {2, 1, 3, 5, 4}.
Folosind metoda divide et impera problema iniial va fi descompus n subprobleme, astfel:
PAS1. Se rearanjeaz vectorul, determinndu-se poziia n care va fi mutat pivotul (m).
TU

PAS2. Problema iniial (sortarea vectorului iniial) se descompune n dou subprobleme,


prin descompunerea vectorului n doi subvectori: vectorul din stnga pivotului i
vectorul din dreapta pivotului, care vor fi sortai prin aceeai metod. Aceti sub-
I

vectori, la rndul lor, vor fi i ei rearanjai i mprii de pivot n doi subvectori etc.
ED
Informatic 51

C
PAS3. Procesul de descompunere n subprobleme va continua pn cnd, prin descom-
punerea vectorului n subvectori, se vor obine vectori care conin un singur element.
Subprogramele specifice algoritmului divide et impera vor avea urmtoarea semnificaie:

I
n subprogramul divizeaza() se va rearanja vectorul i se va determina poziia pivotului

OG
xm, care va fi folosit pentru divizarea vectorului n doi subvectori: [xs, xm-1] i [xm+1, xd].
Subprogramul combina() nu mai este necesar, deoarece combinarea soluiilor se
face prin rearanjarea elementelor n vector.
n subprogramul divizeaza() vectorul se parcurge de la ambele capete ctre poziia n

AG
care trebuie mutat pivotul. Se vor folosi doi indici: i pentru parcurgerea vectorului de la
nceputul lui ctre poziia pivotului (i se va incrementa) i j pentru parcurgerea vectorului
de la sfritul lui ctre poziia pivotului (j se va decrementa). Cei doi indici vor fi iniializai
cu capetele vectorului (i=s, respectiv j=d) i se vor deplasa pn cnd se ntlnesc, adic

ED
att timp ct i<j. n momentul n care cei doi indici s-au ntlnit nseamn c operaiile de
rearanjare a vectorului s-au terminat i pivotul a fost adus n poziia corespunztoare lui n
vectorul sortat. Aceast poziie este i (sau j) i va fi poziia m de divizare a vectorului.
n exemplele urmtoare sunt prezentate dou versiuni pentru subprogramul divizeaza():

P
Versiunea 1. Se folosesc variabilele logice: pi, pentru parcurgerea cu indicele i, i pj,
pentru parcurgerea cu indicele j. Ele au valoarea: 1 se parcurge vectorul cu acel indice,
I
i 0 nu se parcurge vectorul cu acel indice; cele dou valori sunt complementare.
#include<iostream.h>
int x[100],n;

void schimb(int &a, int &b){int aux=a; a=b; b=aux;}


void divizeaza(int s,int d,int &m)
IC

{int i=s,j=d,pi=0,pj=1;
// pivotul fiind pe pozitia s, parcurgerea incepe cu indicele j
while (i<j)
CT

{if (x[i]>x[j]) {schimb(x[i],x[j]); schimb(pi,pj);}


i=i+pi; j=j-pj;}
m=i;}
void QuickSort(int s,int d)
DA

{int m;
if (s<d) {divizeaza(s,d,m);
QuickSort(s,m-1);
QuickSort(m+1,d);}}
DI

void main()
{int i; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"x["<<i<<"]= ";cin>>x[i];}
RA

QuickSort(1,n);
cout<<"vectorul sortat"<<endl; for(i=1;i<=n;i++) cout<<x[i]<<" ";}
Cei doi indici i i j sunt iniializai cu extremitile vectorului i j
(i=1; j=5) i parcurgerea ncepe cu indicele j (pi=0; pj=1) 1 2 3 4 5
TU

3 4 1 5 2
Se compar pivotul (3) cu ultimul element (2). Deoarece i j
pivotul este mai mic, cele dou valori se interschimb, i 1 2 3 4 5
se schimb i modul de parcurgere (pi=1; pj=0 2 4 1 5 3
I

avanseaz indicele i).


ED
52 Tehnici de programare

C
Se compar elementul din poziia i (4) cu elementul din i j
poziia j (3). Deoarece 4 este mai mare dect 3, cele 1 2 3 4 5
dou valori se interschimb, i se schimb i modul de 2 3 1 5 4

I
parcurgere (pi=0; pj=1 avanseaz indicele j).

OG
Se compar elementul din poziia i (3) cu elementul din i j
poziia j (5). Deoarece 3 este mai mic dect 5, cele dou 1 2 3 4 5
valori nu se interschimb, i se pstreaz modul de 2 3 1 5 4
parcurgere (pi=0; pj=1 avanseaz indicele j).

AG
Se compar elementul din poziia i (3) cu elementul din po- ij
ziia j (1). 3 fiind mai mare dect 1, cele dou valori se in- 1 2 3 4 5
terschimb i se schimb i modul de parcurgere (avansea- 2 1 3 5 4
z indicele i). Cei doi indici fiind egali, algoritmul se termin.

ED
Versiunea 2.
void divizeaza(int s,int d,int &m)
{int pivot=x[s],i=s,j=d;
while (i<j) {while(x[i]<pivot) i++;

P
while(x[j]>pivot) j--;
if (i<j) schimb(x[i],x[j]);}
m=i;}
I
Iniial, cei doi indici i i j sunt iniializai cu extremitile i j
vectorului (i=1; j=5) i pivotul are valoarea 3. 1 2 3 4 5
3 4 1 5 2

Elementul din poziia i (3) nu este mai mic dect pivotul; i j


indicele i nu avanseaz (i=1). Elementul din poziia j (2) 1 2 3 4 5
IC

nu este mai mare dect pivotul; indicele j nu avanseaz 2 4 1 5 3


(j=5). Valorile din poziiile i i j se interschimb.
Elementul din poziia i (2) este mai mic dect pivotul; i j
CT

indicele i avanseaz pn la primul element mai mare 1 2 3 4 5


dect pivotul (i=2). Elementul din poziia j (3) nu este mai 2 3 1 5 4
mare dect pivotul; indicele j (j=5) nu avanseaz. Valorile
din poziiile i i j se interschimb.
DA

Elementul din poziia i (3) nu este mai mic dect pivotul; i j


indicele i nu avanseaz (i=2). Elementul din poziia j (4) 1 2 3 4 5
este mai mare dect pivotul; indicele j avanseaz pn la 2 1 3 5 4
primul element mai mic dect pivotul (j=3). Valorile din
DI

poziiile i i j se interschimb.
Elementul din poziia i (1) este mai mic dect pivotul; indi- j i
cele i avanseaz la primul element mai mare dect pivotul 1 2 3 4 5
(i=4). Elementul din poziia j (3) nu este mai mare dect 2 1 3 5 4
RA

pivotul; indicele j nu avanseaz (j=3). Indicele i fiind mai


mare dect indicele j, algoritmul se termin.

Observaie. n ambele cazuri algoritmul continu cu divizarea vectorului n subvectorii cu


indicii [1,2] i [4,5] i rearanjarea elementelor n cei doi subvectori.
TU

Complexitatea algoritmului de sortare rapid. Pentru divizarea problemei n subpro-


bleme se calculeaz mijlocul intervalului de indici i O(D(n))=(1). Pentru combinarea
soluiilor se parcurge vectorul cu ajutorul celor doi indici, de la primul element pn la
ultimul element, i O(D(n))=O(n(1))=O(n). Timpul de execuie este T(n)= 2T(n/2)+n.
I

k
ED

Considernd c n=2 , rezult:


Informatic 53

C
k k k-1 k-1 k k-1 k k
T(n)=T(2 )+2 = 2(T(2 )+ 2 ) +2 = 2T(2 ) +2 +2 = ... =
k-2 k-2 k k 2 k-2 k-2 k k k k
22(T(2 )+ 2 ) +2 +2 = 2 (T(2 )+ 2 ) +2 +2 +2 = k2 = log2n n.
Ordinul de complexitate al algoritmului este O(nlog2n).

I
OG
1.4.5. Sortarea prin interclasare (MergeSort)
Algoritmul de interclasare se execut pe doi vectori, ordonai dup acelai criteriu, pentru a
obine un al treilea vector, care s conin elementele primilor doi vectori, ordonate dup

AG
acelai criteriu. Algoritmul de sortare prin interclasare se bazeaz pe observaia c orice
vector care conine un singur element este un vector sortat. Algoritmul de interclasare se
poate folosi pentru sortarea unui vector cu ajutorul metodei divide et impera, astfel:
PAS1. Se descompune problema n subprobleme
10 8 7 9 5
similare, prin mprirea vectorului n doi sub-

ED
vectori, avnd mulimea indicilor [s,m] i
[m+1,d], unde m este indicele din mijlocul 10 8 7 9 5
intervalului: m=(s+d)/2.
PAS2. Dac subvectorul conine un singur element,

P
atunci se consider sortat (corespunde 10 8 7 9 5
cazului de baz); altfel, se continu descom-
I
punerea lui n subvectorii care au mulimea 10 8
indicilor [s,m] i mulimea indicilor [m+1,d].
PAS3. Se combin soluiile celor dou subpro-
bleme, prin interclasarea celor doi vectori 8 10

sortai, obinndu-se un vector sortat.


Vectorul care se sorteaz este x. Prin subprogramul
IC

interclaseaza() se realizeaz combinarea soluii- 7 8 10 5 9


lor prin interclasarea subvectorului x, care are muli-
mea indicilor [s,m], cu subvectorul x, care are muli-
CT

5 7 8 9 10
mea indicilor [m+1,d], n vectorul auxiliar v. Vectorul v
se copiaz n vectorul x, care are mulimea indicilor [s,d].
#include<iostream.h>
DA

int x[100],n;
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}
void interclaseaza(int s,int d,int m)
{int i=s,j=m+1,k=1,v[100];
DI

while (i<=m && j<=d)


{if (x[i]<x[j]) {v[k]=x[i]; i++;}
else {v[k]=x[j]; j++;}
k++;}
RA

if (i<=m) while (i<=m) {v[k]=x[i]; i++; k++;}


else while (j<=d) {v[k]=x[j]; j++; k++;}
for (k=1,i=s;i<=d;k++,i++) x[i]=v[k];}
void MergeSort(int s,int d)
TU

{int m;
if (s<d) {divizeaza(s,d,m);
MergeSort(s,m);
MergeSort(m+1,d);
I
ED

interclaseaza(s,d,m);}}
54 Tehnici de programare

C
void main()
{int i; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"x["<<i<<"]= ";cin>>x[i];}

I
MergeSort(1,n);

OG
cout<<"vectorul sortat"<<endl; for(i=1;i<=n;i++) cout<<x[i]<<" ";}
Complexitatea algoritmului de sortare prin interclasare. Pentru divizarea problemei n
subprobleme se calculeaz mijlocul intervalului de indici i O(D(n))=(1). Pentru combi-
narea soluiilor se execut interclasarea a doi vectori i O(D(n))=O(n). Timpul de execuie

AG
k
este T(n)= 2T(n/2)+n. Considernd c n=2 , rezult:
k k k-1 k-1 k k-1 k k
T(n)=T(2 )+2 = 2(T(2 )+ 2 ) +2 = 2T(2 ) +2 +2 = ... =
k-2 k-2 k k 2 k-2 k-2 k k k k
22(T(2 )+ 2 ) +2 +2 = 2 (T(2 )+ 2 ) +2 +2 +2 = k2 = log2n n.
Ordinul de complexitate al algoritmului este O(nlog2n).

ED
Observaie. n comparaie cu algoritmii de sortare prin metoda seleciei directe i prin metoda
2
bulelor, care au ordinul de complexitate O(n ), algoritmii de sortare care folosesc strategia
divide et impera sunt mai eficieni.

P
1. S se rearanjeze elementele unui vector astfel nct n vector s se
Tem gseasc mai nti numerele impare i apoi numerele pare. Se vor
realiza dou versiuni ale programului, cte una pentru fiecare meto-
I
d de sortare care folosete strategia divide et impera.
2. ntr-un fiier text sunt scrise urmtoarele informaii: pe primul rnd numrul de elevi din
clas n, iar pe urmtoarele n rnduri urmtoarele informaii despre un elev: numele,
prenumele i mediile semestriale la disciplina informatic. n cadrul unui rnd datele

sunt separate prin spaiu. S se scrie un program care s realizeze urmtoarele cerine.
IC

Fiecare cerin va fi rezolvat printr-un subprogram. Ordonarea elementelor vectorului i


cutarea unui elev n vector se vor face folosind algoritmii cei mai eficieni.
a. Se citesc datele din fiierul text i se calculeaz media anual a fiecrui elev.
CT

b. Se rearanjeaz datele n ordinea alfabetic a numelui i prenumelui elevilor.


c. Pentru numele i prenumele unui elev, citite de la tastatur, se afieaz mediile
semestriale i media anual.
d. Se scriu informaiile obinute n urma prelucrrilor ntr-un alt fiier text.
DA

1.4.6. Problema turnurilor din Hanoi


Pe trei tije notate cu A, B i C se pot monta discuri perforate de diferite dimensiuni. Iniial
DI

pe tija A (tija surs) sunt aezate unele peste altele n discuri n ordinea descresctoare a
diametrelor, iar celelalte tije sunt goale. S se afieze toate mutrile care trebuie fcute
ca discurile de pe tija A s fie aranjate pe tija B (tija destinaie) n aceeai ordine n care
erau pe tija A, folosind tija C ca tij de manevr. O mutare nu se poate face dect cu un
RA

disc i el nu poate fi aezat pe o tij dect peste un disc cu diametrul mai mare.
S analizm mutrile care trebuie fcute pentru n=3:
Se mut discul de pe tija A pe tija B (1).
Se mut discul de pe tija A pe tija C (2).
TU

n discuri

Se mut discul de pe tija B pe tija C (3).


Se mut discul de pe tija A pe tija B (4).
Se mut discul de pe tija C pe tija A (5).
Se mut discul de pe tija C pe tija B (6).
I
ED

Se mut discul de pe tija A pe tija B (7).


Informatic 55

C
B B
1

I
A

OG
C C
3
Mut primele 2

AG
discuri pe tija de
2 manevr
B B

ED
4
A A

P
C C

Mut discul cu
I
diametrul maxim
pe tija destinaie
B B

7
IC

A A
CT

C 6 C

Mut cele dou


discuri pe tija
DA

5 destinaie
Folosind metoda divide et impera problema iniial va fi descompus n subprobleme astfel:
PAS1. Se mut primele n-1 discuri de pe tija surs pe tija de manevr.
PAS2. Se mut discul cu diametrul cel mai mare de pe tija surs pe tija destinaie.
DI

PAS3. Se mut cele n-1 discuri de pe tija de manevr pe tija destinaie.


#include<iostream.h>
RA

void hanoi(int n, char a, char b, char c)


{if (n==1) cout<<"Mutarea: "<<a<<"->"<<b<<endl;
else
{hanoi(n-1,a,c,b);
TU

cout<<"Mutarea: "<<a<<"->"<<b<<endl;
hanoi(n-1,c,b,a);}}
void main()
{int n; char a='A',b='B',c='C'; cout<<"n= "; cin>>n;
I

hanoi(n,a,b,c);}
ED
56 Tehnici de programare

C
1. S se determine numrul de partiii distincte ale 4
Tem unui numr natural n. Indicaie. Se descompune
numrul n n dou numere n1 i n2, dup care 3+1 2+2

I
fiecare numr nou obinut se descompune n alte 2+1

OG
dou numere. Procesul de descompunere continu pn cnd n1<n2.
Numrul de partiii este egal cu numrul de descompuneri obinute. 1 1
2. ntr-un parc cu o suprafa dreptunghiular care are coordonatele colului din stnga sus
(X1,Y1) i ale colului din dreapta jos (X2,Y2) se gsesc n copaci. Poziia fiecrui copac

AG
pe teren este dat de coordonatele (xi,yi). n parc trebuie amenajat un teren de joac
pentru copii, de form dreptunghiular, cu laturile paralele cu laturile parcului. S se
determine dreptunghiul cu arie maxim pe care se poate amenaja terenul de joac fr
s se taie nici un copac. Indicaie. Considernd c un copac i mparte dreptunghiul
iniial n patru dreptunghiuri cu laturile paralele cu dreptunghiul iniial, problema se

ED
descompune n patru subprobleme, fiecare subproblem rezolvnd cazul unuia dintre
cele patru dreptunghiuri, care au coordonatele colurilor ((X1,Y1); (xi, Y2)), ((xi, Y1);
(X2,Y2)), ((X1,Y1); (X2,yi)) i ((X1, yi); (X2,Y2)). La cazul de baz se ajunge atunci cnd
dreptunghiul nu conine nici un copac. Pentru fiecare dreptunghi care nu conine nici un

P
copac se calculeaz aria i se memoreaz coordonatele colurilor. Din combinarea
soluiilor obinute se identific dreptunghiul care are aria cea mai mare.
I
3. ntr-un vector sunt memorate mai multe numere ntregi. S se plieze repetat vectorul,
pn cnd rmne un singur element, i s se afieze valoarea acestui element. Plierea
unui vector nseamn suprapunerea unei jumti (numit donatoare) peste cealalt
jumtate (numit receptoare). Dac numrul de elemente ale vectorului este impar,

elementul din mijloc se elimin. De exemplu, pentru vectorul {1,2,3,4,5,6,7}, considernd


prima jumtate ca fiind cea receptoare, vectorul obinut dup prima pliere este {5,6,7}.
IC

1.4.7. Generarea modelelor fractale


CT

Modelele fractale sunt modele matematice care descriu fenomene sau obiecte care au o
structur periodic. Ele pot fi folosite i n grafic, pentru desenarea unor forme geometrice
complexe.
DA

n descrierea matematic a formei geometrice se pornete de la un nucleu, care, n urma


unui proces iterativ, este generat succesiv la scri diferite. Numrul de iteraii reprezint
ordinul curbei. Un exemplu clasic este forma geometric cunoscut sub numele de curba
lui Koch, care se genereaz astfel:
DI

PAS1. Se pornete de la nucleul care este un triunghi echilateral, cu latura avnd lungi-
mea finit L.
PAS2. Fiecare latur a triunghiului este mprit n trei segmente egale. Segmentul din
mijloc este eliminat i nlocuit cu un unghi care are laturile egale cu el.
RA

PAS3. Pentru fiecare iteraie se repet Pasul 2, pentru fiecare segment al figurii obinute.
TUI
ED
Informatic 57

C
Se obine o construcie perfect regulat. Dup fiecare iteraie cresc: numrul de unghiuri,
numrul de laturi ale poligonului i perimetrul poligonului. Notm cu p perimetrul nucleu
(triunghiul echilateral de la care se pornete). n procesul de construcie a curbei, la fiecare

I
iteraie, fiecare latur Li a triunghiului echilateral este mprit n trei segmente de lungime

OG
egal (Li/3) i este nlocuit cu 4 astfel de segmente (4Li/3). Dup n iteraii, perimetrul
n
poligonului va fi p(4/3) .
Pentru realizarea construciei se folosesc urmtoarele 3 elemente:

AG
iniiator generator nucleu
(n=0) (n=1)

ED
Pentru construirea poligonului trebuie desenat fiecare latur. Pentru fiecare latur se
cunosc: coordonatele x1 i y1, lungimea segmentului L i x2,y2
unghiul . Coordonatele x2 i y2 se pot determina:
L
x2=x1+Lcos() i y2=y1+Lsin().
x1,y1

P
Pentru desenarea segmentului se folosete funcia line()
implementat n biblioteca graphics.h: line(x1,y1,x2,y2).
Desenarea poligonului nseamn desenarea fiecrei laturi, care este determinat de coor-
I
donatele x1 i y1, lungimea segmentului L i unghiul . Problema se reduce la generarea
datelor care caracterizeaz fiecare latur i la desenarea unei linii folosind aceste date.
Generarea laturilor poligonului este un proces recursiv n care iniiatorul care are lungimea

L este nlocuit cu generatorul. Generatorul este format din patru segmente, fiecare segment
avnd lungimea L/3. Acest proces poate fi descompus n patru procese.
IC

Folosind metoda divide et impera pentru a genera curba lui Koch de ordinul n, problema
iniial va fi descompus n patru subprobleme, astfel (subprogramul Koch()):
PAS1. Se genereaz primul segment, care este un segment cu lungimea L/3 i cu aceeai
CT

orientare cu a iniiatorului. El devine iniiatorul curbei lui Koch de ordinul n-1.


0
PAS2. Se genereaz al doilea segment, prin rotirea segmentului obinut cu 60 spre stn-
ga (subprogramul stanga()). El devine iniiatorul curbei lui Koch de ordinul n-1.
0
PAS3. Se genereaz al treilea segment, prin rotirea segmentului obinut cu 120 spre dreap-
DA

ta (subprogramul dreapta()). El devine iniiatorul curbei lui Koch de ordinul n-1.


0
PAS4. Se genereaz al patrulea segment, prin rotirea segmentului obinut cu 60 spre
stnga (subprogramul stanga()). El devine iniiatorul curbei lui Koch de ordinul n-1.
DI

Procesul de descompunere se termin cnd se ajunge la ordinul 0 i se obine iniiatorul, care


se va desena (subprogramul deseneaza()).
Pentru desenarea poligonului, se construiete nucleul (se genereaz cele trei laturi ale
triunghiului echilateral de lungime L) i pentru fiecare latur se construiete curba lui
RA

Koch de ordinul n (subprogramul nucleu_Koch()) .


#include<iostream.h>
#include<math.h>
TU

#include<graphics.h>
int x,y;
float alfa;
void stanga(float unghi)
I

{alfa+=unghi*M_PI/180.;}
ED
58 Tehnici de programare

C
void dreapta(float unghi)
{alfa-=unghi*M_PI/180.;}
void deseneaza(float L)

I
{x1=x; y1=y; x+=(int)(L *cos(alfa); y+=(int)(L*sin(alfa);

OG
line(x,y,x1,y1);}
void Koch(int n, float L)
{if (n==0) deseneaza(L);
else

AG
{Koch(n-1,L/3); stanga(60);
Koch(n-1,L/3); dreapta(120);
Koch(n-1,L/3); stanga(60);
Koch(n-1,L/3);}}

ED
void nucleu_Koch(int n,float L)
{Koch(n,L); dreapta(120);
Koch(n,L); dreapta(120);
Koch(n,L); dreapta(120);}

P
void main()
{int n,L;
cout<<"n= "; cin>>n; cout<<"L= "; cin>>L;
I
nucleu_Koch(n,L);}
1. Desenai praful lui Cantor, care este generat astfel: un segment de
Tem lungimea L, care este paralel cu axa Ox, este mprit n cinci

segmente egale, din care se elimin segmentul din mijoc i se


repet acest proces de n ori pentru fiecare segment rmas.
IC

2. Desenai curba lui Koch, definit prin urmtoarele trei elemente, n care fiecare
segment al generatorului are lungimea L/4, unde L este lungimea segmentului iniiator.
CT

iniiator
(n=0) generator nucleu
DA

(n=1)
3. Desenai curba dragonului, definit prin urmtoarele trei elemente, n care fiecare seg-
ment al generatorului are lungimea L/sqrt(2), unde L este lungimea segmentului iniiator.
DI

iniiator
(n=0)
RA

generator curba de nucleu


(n=1) ordinul n=2
4. S se deseneze figura geometric obinut astfel: se deseneaz un ptrat cu latura L,
se deseneaz un ptrat care unete mijloacele laturilor ptratului iniial i se repet
TU

acest proces de n ori pentru fiecare ptrat obinut.


5. S se deseneze covorul lui Sierpinski, astfel: se deseneaz un ptrat cu latura L, se
mparte acest ptrat n 9 ptrate egale, se haureaz ptratul din mijloc i se repet
acest proces de n ori pentru fiecare ptrat nehaurat.
I
ED
Informatic 59

C
1. 5. Metoda greedy

I
1.5.1. Descrierea metodei greedy

OG
Metoda greedy se poate folosi pentru problemele n care, dndu-se o mulime finit A,
trebuie determinat o mulime SA care s ndeplineasc anumite condiii. Metoda furni-
zeaz o singur soluie, reprezentat prin elementele mulimii S. Ca i n cazul metodei
backtracking, soluia problemei este dat de un vector S = {x1, x2, , xn} ale crui elemente

AG
aparin ns unei singure mulimi A. Spre deosebire de metoda backtracking, metoda Greedy
nu gsete dect o singur soluie i, n general, aceast soluie este soluia optim.

ED
Scop: identificarea problemelor n care soluia optim este o submulime inclus ntr-o
mulime dat, care trebuie s ndeplineasc anumite condiii.
Enunul problemei 1: S se repartizeze optim o resurs (de exemplu, o sal de specta-

P
cole, o sal de conferine, o sal de sport) mai multor activiti (spectacole, prezentri de
produse, respectiv meciuri) care concureaz pentru a obine resursa respectiv.
I
Mulimea A este format din cele n activiti. Fiecare activitate i (1 i n) are un timp de
ncepere ti i un timp de terminare fi, unde ti < fi i ocup resursa n intervalul de timp
[ti,fi]. Dou activiti i i j sunt compatibile dac intervalele lor de ocupare [ti,fi] i [tj,fj] sunt
disjuncte, adic dac fi tj sau dac fj ti. Cerina problemei este de a selecta o mulime

maximal de activiti compatibile. n acest caz, mulimea S este format din activitile
care vor folosi resursa, iar condiia pe care trebuie s o ndeplineasc elementele mulimii S
IC

este ca ele s fie activiti compatibile. n plus, pentru ca repartizarea resursei s fie optim,
trebuie ca mulimea S s conin maximul de elemente care ndeplinesc aceast condiie.
CT

Enunul problemei 2: S se ocupe optim un mijloc de transport (de exemplu, un ruc-


sac, un autocamion) care are o capacitate maxim de ocupare (care poate transporta o
greutate maxim G) cu n obiecte, fiecare obiect avnd greutatea gi i un profit obinut n
urma transportului ci, iar din fiecare obiect putnd s se ia o fraciune xi[0,1] .
DA

Mulimea A este format din cele n obiecte. Fiecare obiect i (1in) are o eficien a trans-
portului ei care reprezint profitul pentru o unitatea de greutate. Cerina problemei este de a
selecta o mulime de obiecte astfel nct eficiena transportului s fie maxim. Mulimea S
este format din obiectele care vor ocupa mijlocul de transport, iar condiia pe care trebuie s
DI

o ndeplineasc elementele mulimii S este ca, prin contribuia adus de fiecare obiect la
eficiena transportului, s se obin o eficien maxim, iar greutatea obiectelor selectate s
fie egal cu greutatea maxim a transportului.
RA

Enunul problemei 3: Pentru dou mulimi de numere ntregi nenule: C cu n elemente,


C = {c1,c2, , cn} i A cu m elemente, A = {a1,a2, , am}, i nm, s se selecteze o
submulime de n numere din mulimea A, astfel nct expresia:
E = c1 x1 + c2 x2 + + cn xn
TU

n care xiA, s aib valoarea maxim.


n acest caz, mulimea S = {x1,x2, , xn}, n care xiA, trebuie s ndeplineasc condiia:
E = c1 x1 + c2 x2 + + cn xn = Emax
Criteriul de alegere a elementelor xi este urmtorul: dac n mulimea A mai exist elemente
I
ED

care au acelai semn cu coeficientul ci, se va alege elementul aj pentru care termenul ci xj
60 Tehnici de programare

C
are valoarea maxim (deoarece acest termen se adun la valoarea expresiei), iar dac n
mulimea A nu mai exist elemente care au acelai semn cu coeficientul ci, se va alege
elementul aj pentru care termenul ci xj are valoarea minim (deoarece acest termen se

I
scade din valoarea expresiei).

OG
Enunul problemei 4: S se plteasc o sum s cu un numr minim de bancnote cu
valori date. Se consider c din fiecare tip de bancnot se poate folosi un numr nelimitat
de bancnote, iar pentru ca problema s aib soluie, vom considera c exist i bancnote
cu valoarea 1.

AG
Mulimea A este format din cele n valori distincte ale bancnotelor. Cerina problemei este
de a selecta o mulime minim de bancnote pentru plata sumei s. n acest caz, mulimea S
este format din valorile cu care se va face plata, iar condiia pe care trebuie s o nde-
plineasc elementele mulimii S este ca, prin adunarea sumelor pariale pltite cu

ED
bancnotele cu valorile alese, s se obin suma de plat s. Pentru ca numrul de
bancnote s fie ct mai mic, trebuie s se caute ca plata s se fac n bancnote cu
valori ct mai mari.

P
Metoda greedy construiete soluia prin selectarea, dintr-o mulime de elemente,
a elementelor care ndeplinesc o anumit condiie. Pentru ca elementele
care se selecteaz s aparin soluiei optime, la pasul k se alege candidatul
I
optim pentru elementul xk al soluiei.
Spre deosebire de metoda backtracking, la metoda greedy, alegerea elementului xk al
soluiei este irevocabil (nu se mai poate reveni asupra alegerii fcute).

Metoda greedy poate duce la obinerea soluiei optime n cazul problemelor care au pro-
IC

prietatea de optim local, adic soluia optim a problemei cu dimensiunea n a datelor de


intrare conine soluiile optime ale subproblemelor similare cu problema iniial, dar de
dimensiune mai mic. Metoda greedy se mai numete i metoda optimului local.
CT

Paii algoritmului greedy sunt:


PAS1. Se iniializeaz mulimea S cu mulimea vid: S.
PAS2. Ct timp S nu este soluie a problemei i A, execut:
PAS3. Se alege din mulimea A elementul a care este candidatul optim al soluiei.
DA

PAS4. Se elimin elementul a din mulimea A.


PAS5. Dac el poate fi element al soluiei, atunci elementul a se adaug la
mulimea S. Se revine la Pasul 2.
PAS6. Dac mulimea S este soluia problemei, atunci se afieaz soluia; altfel, se
DI

afieaz mesajul Nu s-a gsit soluie


Algoritmul greedy este un algoritm iterativ, care determin soluia optim a problemei n
urma unor succesiuni de alegeri care reduc dimensiunea problemei respective: se alege
RA

elementul x1 al soluiei, apoi elementul x2 al soluiei, .a.m.d. Altfel spus, elementul xk al


soluiei este determinat prin alegerea, din elementele rmase n mulimea A, a candidatului
optim pentru elementul xk al soluiei, iar determinarea urmtoarele n-k elemente ale soluiei
(rezolvarea subproblemei) se face numai dup ce a fost determinat elementul xk al soluiei.
TU

Alegerea fcut pentru elementul xk al soluiei poate depinde de alegerile fcute pentru
determinarea primelor k-1 elemente ale soluiei, dar nu depinde de alegerile ulterioare.
Pentru ca algoritmul greedy s conduc la obinerea soluiei optime, trebuie s fie ndepli-
I

nite dou condiii:


ED
Informatic 61

C
1. Alegerea optimului local pentru fiecare element al soluiei duce la alegerea soluiei
optime globale.
2. Soluia optim a problemei conine soluiile optime ale subproblemelor.

I
Aceasta nseamn c, pentru a fi siguri c algoritmul greedy construiete soluia optim a

OG
problemei, trebuie s se demonstreze c sunt ndeplinite cele dou condiii.
n rezolvarea multor probleme folosind strategia greedy, pentru a alege optimul local care
s duc la alegerea soluiei optime globale, mulimea A este ordonat dup criteriul
candidatului optim. Ordonarea mulimii dup criteriul candidatului optim nseamn rearan-

AG
jarea elementelor mulimii A astfel nct, dup extragerea unui element, urmtorul element
din mulimea A s reprezinte elementul care este cel mai ndreptit s fie ales ca element
al mulimii S. De exemplu:
n cazul repartizrii optime a unei resurse, o activitate nu poate ncepe dect dac se

ED
termin cea anterioar. A repartiza optim resursa nseamn a organiza ct mai multe
activiti. Din mulimea activitilor se alege ntotdeauna activitatea care are timpul de
terminare ct mai mic. n acest caz, candidatul optim este activitatea care are timpul de
terminare cel mai mic, iar ordonarea activitilor dup criteriul candidatului optim

P
nseamn ordonarea cresctoare dup timpul de terminare.
n cazul ocuprii optime a mijlocului de transport, trebuie ca eficiena transportului s
fie maxim. Din mulimea obiectelor, se aleg obiectele care au eficiena de transport ct
I
mai mare. n acest caz, candidatul optim este obiectul care are eficiena transportului
cea mai mare, iar ordonarea obiectelor dup criteriul candidatului optim nseamn ordo-
narea descresctoare dup eficiena transportului.
n cazul plii unei sume cu un numr minim de bancnote cu valoare dat, ca s se

foloseasc ct mai puine bancnote, trebuie ca plata s se fac n ct mai multe


IC

bancnote cu valoare foarte mare. n acest caz, candidatul optim este bancnota cu valoa-
rea cea mai mare, iar ordonarea dup criteriul candidatului optim nseamn ordonarea
descresctoare dup valoarea bancnotelor.
CT

1.5.2. Implementarea metodei greedy


Pentru implementarea metodei greedy se vor folosi dou subprograme:
DA

subprogramul sort() care ordoneaz mulimea A dup criteriul candidatului optim;


subprogramul greedy() care implementeaz metoda propriu-zis.
n exemplele urmtoare, datele de intrare vor fi citite dintr-un fiier text.
Exemplul 1. Problema planificrii optime a activitilor.
DI

Se folosesc urmtoarele date i structuri de date:


Pentru numrul de elemente ale celor dou mulimi se folosesc variabilele n numrul
de activiti (numrul de elemente ale mulimii A) i m numrul de activiti selectate
RA

pentru a forma soluia problemei (numrul de elemente ale mulimii S).


Pentru mulimea activitilor (mulimea A) se folosete vectorul a, ale crui elemente
sunt de tip nregistrare activitate care conine trei cmpuri, x i y pentru ora la
care ncepe activitatea, respectiv ora la care se termin activitatea i k pentru numrul
TU

activitii (este folosit ca un identificator al activitii).


Soluia (mulimea S) va fi memorat n vectorul s. n fiecare element al vectorului s se
memoreaz indicele elementului selectat din vectorul a, dup ce a fost sortat dup
criteriul candidatului optim.
I

Se folosesc urmtoarele subprograme:


ED
62 Tehnici de programare

C
Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd este scris numrul de activiti n, iar pe urmtoarele n rnduri perechi de
numere ntregi, separate prin spaiu, care reprezint ora de nceput i ora de sfrit ale

I
unei activiti. Fiecrei activiti i se atribuie ca identificator numrul de ordine de la citi-

OG
rea din fiier. n urma execuiei acestui subprogram, se creeaz vectorul activitilor a.
Subprogramul sort() sorteaz vectorul a cresctor dup timpul de terminare a
activitilor (cmpul y).
Subprogramul greedy() implementeaz strategia greedy pentru aceast problem.

AG
Subprogramul afiseaza() afieaz soluia problemei folosind informaiile din
vectorul s indicele fiecrei activiti selectate.
Strategia greedy este implementat astfel:
PAS1. Se iniializeaz vectorul s cu indicele primului element din vectorul a (se selec-

ED
teaz, ca prim activitate, activitatea care are ora de terminare cea mai mic).
PAS2. Pentru urmtoarele n-1 elemente ale vectorului a, execut
PAS3. Dac ora la care ncepe activitatea din elementul curent al vectorului a
este mai mare sau egal cu ora la care se termin ultima activitate adu-

P
gat la soluie (n vectorul s), atunci activitatea este adugat la soluie.
Mulimea activitilor
I
Activitatea 1 2 3 4 5 6 7 8
Ora de ncepere 9 12 8 10 16 14 20 19
Ora de terminare 11 13 10 12 18 16 22 21

Mulimea activitilor dup ce a fost sortat


IC

Activitatea 3 1 4 2 6 5 8 7
Ora de ncepere 8 9 10 12 14 16 19 20
Ora de terminare 10 11 12 13 16 18 21 22
CT

Soluia problemei
Activitatea 3 4 2 6 5 8
DA

Ora de ncepere 8 10 12 14 16 19
Ora de terminare 10 12 13 16 18 21
Programul este:
#include<fstream.h>
DI

struct activitate {int x,y,k;};


activitate a[20];
int n,m,s[20];
RA

fstream f("greedy1.txt",ios::in);
void citeste()
{int i; f>>n;
for(i=1;i<=n;i++) {f>>a[i].x>>a[i].y; a[i].k=i;} f.close();}
TU

void sort()
{int i,j; activitate aux;
for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
I

if (a[i].y>a[j].y) {aux=a[i]; a[i]=a[j]; a[j]=aux;}}


ED
Informatic 63

C
void greedy()
{int i,j; s[1]=1; j=1;
for (i=2;i<=n;i++)

I
if (a[i].x>=a[s[j]].y) {j++; s[j]=i;}

OG
m=j;}
void afiseaza()
{cout<<"Planificarea activitatilor: "<<endl;
for (int i=1;i<=m;i++)

AG
cout<<"Activitatea "<< a[s[i]].k<<" incepe la ora ";
cout<<a[s[i]].x <<" si se termina la ora "<<a[s[i]].y<<endl;}
void main()
{citeste(); sort(); greedy(); afiseaza();}

ED
ntr-o sal de spectacole trebuie planificate n spectacole care au loc n
Tem aceeai zi, fiecare spectacol avnd o or la care trebuie s nceap i o
durat de desfurare. Scriei un program care s planifice optim ocu-
parea slii de spectacole.

P
Exemplul 2. Problema ocuprii optime a mijlocului de transport (problema rucsacului).
Se folosesc urmtoarele date i structuri de date:
I
Pentru numrul de elemente ale celor Mulimea obiectelor G=20
dou mulimi se folosesc variabilele n
numrul de obiecte (numrul de elemente Obiectul 1 2 3 4 5
ale mulimii A) i m numrul de obiecte Greutatea 5 4 4 8 10

selectate pentru a forma soluia problemei Profitul 10 20 10 10 22


IC

(numrul de elemente ale mulimii S).


Eficiena 2 5 2,5 1,25 2,2
Pentru greutatea maxim care se poate
transporta, se folosete variabila G, iar Mulimea obiectelor dup ce a fost sortat
CT

pentru greutatea obiectelor care se mai pot Obiectul 2 3 5 1 4


selecta, se folosete variabila Gr (greuta-
tea rmas). Variabila Gr este iniializat Greutatea 4 4 10 5 8
cu valoarea G (iniial, greutatea obiectelor Profitul 20 10 22 10 10
DA

care se pot selecta este greutatea maxim Eficiena 5 2,5 2,2 2 1,25
de transport), iar dup ce s-a construit
soluia, variabila Gr are valoarea 0 (nu se Soluia problemei
mai pot selecta obiecte, deoarece a fost Obiectul 2 3 5 1 4
DI

ocupat toat capacitatea de transport). Greutatea 4 4 10 5 8


Pentru mulimea obiectelor (A) se folo-
sete vectorul a, ale crui elemente sunt Fraciunea 1 1 1 0,2 0
de tip nregistrare obiect, care conine Greutatea 4 4 10 2 0
RA

patru cmpuri: g greutatea obiectului, c


profitul obinut n urma transportului, e eficiena transportului i k numrul
obiectului (este folosit ca un identificator al obiectului).
Soluia (mulimea S) va fi memorat n vectorii s i x. n fiecare element al vectorului s se
TU

memoreaz indicele obiectului selectat din vectorul a, dup ce a fost sortat dup criteriul
candidatului optim, iar n elementul din vectorul x care are acelai indice cu cel din
vectorul s se memoreaz fraciunea de cantitate care se va lua din obiectul selectat.
Elementele vectorului x sunt iniializate cu valoarea 0 (vectorul este declarat global).
I
ED
64 Tehnici de programare

C
Se folosesc urmtoarele subprograme:
Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe primul
rnd este scris numrul de obiecte n i greutatea maxim a transportului G, iar pe

I
urmtoarele n rnduri perechi de numere reale, separate prin spaiu, care reprezint

OG
greutatea i profitul transportului unui obiect. Fiecrui obiect i se atribuie, ca identificator,
numrul de ordine de la citirea din fiier. Pentru fiecare obiect se calculeaz eficiena
transportului. n urma execuiei acestui subprogram se creeaz vectorul obiectelor, a.
Subprogramul sort() sorteaz vectorul a, cresctor dup eficiena transportului

AG
obiectelor (cmpul e).
Subprogramul greedy() implementeaz strategia greedy pentru aceast problem.
Subprogramul afiseaza() afieaz soluia problemei folosind informaiile din vectorii
s i x indicele fiecrui obiect selectat i fraciunea din greutate care se va transporta.

ED
Strategia greedy este implementat astfel:
PAS1. Se iniializeaz greutatea Gr cu valoarea G i selectarea obiectelor ncepe cu obi-
ectul cu cea mai mare eficien a transportului (primul obiect din vectorul a).
PAS2. Ct timp mai exist obiecte care nu au fost selectate i greutatea obiectelor

P
selectate nu este greutatea maxim, execut
PAS3. Dac greutatea obiectului din elementul curent al vectorului a este mai
mic sau egal cu greutatea rmas, Gr, atunci obiectul este adugat la
I
soluie, lundu-se ntreaga cantitate disponibil din obiect; altfel, se ia din
obiect fraciunea egal cu greutatea rmas Gr. Se actualizeaz greutatea
Gr diminund-o cu greutatea obiectului care a fost adugat n rucsac.

Programul este:
#include<fstream.h>
IC

struct obiect {int k;


float g,c,e;};
obiect a[20];
CT

int n,m,s[20];
float G,Gr,x[20];
fstream f("greedy2.txt",ios::in);
void citeste()
DA

{int i; f>>n>>G;
for(i=1;i<=n;i++)
{f>>a[i].g>>a[i].c; a[i].k=i; a[i].e=a[i].c/a[i].g;} f.close();}
void sort()
DI

{int i,j; obiect aux;


for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
RA

if (a[i].e<a[j].e) {aux=a[i]; a[i]=a[j]; a[j]=aux;}}


void greedy()
{int i,j=0; Gr=G;
for (i=1;i<=n && Gr!=0;i++)
TU

if (Gr>a[i].g) {j++; s[j]=i; x[j]=1; Gr-=a[i].g;}


else {j++; s[j]=i; x[j]=Gr/a[i].g; Gr=0;}
m=j;}
void afiseaza()
I

{for (int i=1;i<=m;i++)


ED
Informatic 65

C
{cout<<"Obiectul "<< a[s[i]].k<<" in cantitatea ";
cout<<x[i]* a[s[i]].g<<endl;}}
void main()

I
{citeste(); sort(); greedy(); afiseaza();}

OG
Observaie. n problema rucsacului exist dou situaii:
1. Obiectele pot fi fracionate problema continu a rucsacului;
2. Obiectele nu pot fi fracionate problema discret a rucsacului.
Algoritmul greedy furnizeaz soluia optim numai n cazul problemei continue a

AG
rucsacului. De exemplu, pentru patru obiecte: a (20 kg, 110 lei), b (9 kg, 45 lei), c (9 kg, 45
lei) i d (6 kg, 30 lei) i greutatea maxim de transport 25 kg:
Soluia greedy: obiectul a profitul transportului = 110;
Soluia optim: obiectele b, c i d profitul transportului = 120.

ED
ntr-un rucsac se pot transporta maximum G kg. Exist n obiecte, fieca-
Tem re obiect avnd greutatea gi i valoarea vi. Obiectele pot fi fracionate.
Scriei un program care s gseasc obiectele care trebuie transportate

P
n rucsac, astfel nct s se obin cea mai valoroas ncrctur.
Exemplul 3. Problema expresiei de valoare maxim.
I
Se folosesc urmtoarele date i structuri de date:
Pentru mulimea coeficienilor C se folosete vectorul c cu n elemente, iar pentru
mulimea numerelor A se folosete vectorul a cu m elemente. Elementele vectorilor sunt
de tip int.

Pentru calcularea valorii expresiei se folosete variabila exp, care este iniializat cu
valoarea 0 (este variabil global), iar pentru a numra elementele selectate din
IC

mulimea A se folosete variabila k, care este iniializat cu valoarea 0.


Se folosesc urmtoarele subprograme:
CT

Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd sunt scrise dou numere ntregi, n i m, care reprezint numrul de
elemente ale celor dou mulimi, pe rndul al doilea cei n coeficieni, iar pe rndul al
treilea cele m numere ntregi din mulimea A. Valorile numerice de pe un rnd sunt
DA

separate prin spaiu. n urma execuiei acestui subprogram se creeaz vectorii c i a.


Subprogramul sort() se folosete pentru a sorta cresctor cei doi vectori c i a.
Subprogramul greedy() implementeaz strategia greedy pentru aceast problem i
afieaz soluia n timp ce o construiete.
DI

Strategia greedy este implementat astfel:


PAS1. Se calculeaz termenii pentru care valorile coeficientului ci i ale numrului aj sunt
pozitive. Pentru ca expresia s fie maxim, parcurgerea celor doi vectori se face de la
ultimul element ctre primul element (de la cele mai mari numere pozitive, ctre cele
RA

mai mici numere pozitive). Se memoreaz, n variabila p, indicele elementului din


vectorul c care urma s fie selectat la terminarea parcurgerii, iar n variabila r indi-
cele elementului din vectorul a care urma s fie selectat la terminarea parcurgerii.
PAS2. Se calculeaz termenii pentru care valorile coeficientului ci i ale numrului aj
TU

sunt negative. Pentru ca expresia s fie maxim, parcurgerea celor doi vectori se
face de la primul element ctre ultimul element (de la cele mai mari numere nega-
tive, ctre cele mai mici numere negative).
I
ED
66 Tehnici de programare

C
PAS3. Coeficienii rmai pot fi numai pozitivi n=5 i m=7 Emax = 97
sau numai negativi. n cazul n care sunt
Indici 1 2 3 4 5 6 7
numai negativi, n mulimea A au rmas

I
numai numere pozitive. Termenii care se ci -2 -1 3 4 5

OG
calculeaz fiind negativi, pentru ca ai -5 -4 -1 2 5 7 8
expresia s fie maxim vor trebui s aib si -5 -4 5 7 8
valoarea ct mai mic i vectorii se vor
parcurge n continuare, ctre ultimul n=6 i m=7 Emax = 77

AG
element (coeficienii sunt numere negati- Indici 1 2 3 4 5 6 7
ve din ce n ce mai mici, iar numerele din ci -5 -4 -3 -1 4 5
vectorul a sunt numere pozitive din ce n
ai -5 -4 1 2 3 4 5
ce mai mari). n cazul n care coeficienii
rmai sunt numai pozitivi, n mulimea A si -5 -4 1 2 4 6

ED
au rmas numai numere negative. n=6 i m=7 Emax = 21
Termenii care se calculeaz fiind nega- Indici 1 2 3 4 5 6 7
tivi, pentru ca expresia s fie maxim vor
trebui s aib valoarea ct mai mic i ci -2 -1 3 4 5 5

P
vectorii se vor parcurge astfel: vectorul c ai -6 -5 -4 -3 -1 1 2
ncepnd de la elementul p ctre primul si -6 -5 -3 -1 1 2
I
element, iar vectorul a ncepnd de la
elementul r ctre primul element (coeficienii sunt numere pozitive din ce n ce mai
mici, iar numerele din vectorul a sunt numere negative din ce n ce mai mari).
Programul este:

#include<fstream.h>
IC

int n,m,p,r,c[20],a[20],exp;
fstream f("greedy3.txt",ios::in);
void citeste()
CT

{int i; f>>n>>m;
for(i=1;i<=n;i++) f>>c[i];
for(i=1;i<=m;i++) f>>a[i];
f.close();}
DA

void sort(int v[], int n)


{int i,j,aux;
for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
DI

if (v[i]>v[j]) {aux=v[i]; v[i]=v[j]; v[j]=aux;}}


void greedy()
{int i=n,j=m,k=0; //indici: ivector c, jvector a, kvector b
cout<<"E= ";
RA

while (c[i]>0 && a[j]>0 && k<n)


{k++; cout<<"("<<c[i]<<")*("<<a[j]<<")+";
exp+=c[i]*a[j]; i--; j--;}
p=j; i=1; j=1;
TU

while (c[i]<0 && a[j]<0 && k<n)


{k++; cout<<"("<<c[i]<<")*("<<a[j]<<")+";
exp+=c[i]*a[j]; i++; j++;}
I

if (c[i]<0)
ED

while (k<n)
Informatic 67

C
{k++; cout<<"("<<c[i]<<")*("<<a[j]<<")+";
exp+=c[i]*a[j]; i++; j++;}
else

I
{i=p;j=r;

OG
while (k<n)
{k++; cout<<"("<<c[i]<<")*("<<a[j]<<")+";
exp+=c[i]*a[j]; i--; j--;}}
cout<<'\b'<<" = "<<exp;}

AG
void main()
{citeste(); sort(c,n); sort(a,m); greedy();}
Justificarea criteriului candidatului optim. Considerm cazul n care coeficienii sunt
numere ntregi pozitive care au fost ordonate cresctor i exist cel puin n numere pozitive

ED
n mulimea A. Conform criteriului candidatului optim, mulimea A a fost ordonat cresctor.
Dac C={c1,c2, , cn} cu cicj, pentru i<j i A={a1,a2, , am} cu aiaj, pentru i<j, atunci
S={x1,x2, , xn} cu xixj, pentru i<j i xn=am, xn-1=am-1, , x1=am-n+1. Este evident c
pentru a obine valoarea maxim a expresiei trebuie s se aleag cele mai mari n numere

P
din mulimea A. Trebuie s demonstrm dac este corect modul n care s-a construit
mulimea S cu aceste numere. Pentru alegerea fcut, expresia are valoarea E1.
E1 = c1 x1 + c2 x2 + + ci xi + + cj xj + + cn xn
I
S presupunem c exist o expresie E2 a crei valoare este mai mare dect a expresiei E1
(E2 >E1). n cel mai bun caz, n expresie ordinea numerelor din mulimea S difer numai
prin valorile din poziiile i i j, cu i<j i ci<cj i xi<xj.

E2 = c1 x1 + c2 x2 + + ci xj + + cj xi + + cn xn
Conform presupunerii fcute, nseamn c E2 E1 > 0. Dar,
IC

E2 E1 = ci (xj - xi) + cj (xi - xj) = (cj - ci) (xi - xj) < 0 i E2 <E1
ceea ce contrazice ipoteza de la care s-a plecat. n mod analog se justific i alegerea
elementelor mulimii S atunci cnd cei n coeficieni sunt negativi i n mulimea A exist cel
CT

puin n numere negative.


1. Justificai criteriul prioritii de alegere pentru cazul n care coeficienii
Tem sunt pozitivi i n mulimea A nu exist dect numere negative.
DA

2. Justificai criteriul prioritii de alegere pentru cazul n care coeficienii


sunt negativi i n mulimea A nu exist dect numere pozitive.
3. Refacei programul astfel nct s se determine valoarea minim a expresiei.
4. Fiind dat o mulime A cu n numere reale, s se determine o submulime a sa care are
DI

proprietatea c suma elementelor submulimii este maxim. Indicaie. Submulimea va


fi format din toate numerele pozitive, iar dac nu exist numere pozitive, din cel mai
mare numr din mulime.
5. Fiind date mulimea de numere reale A = {a1,a2, , am} i n, gradul unui polinom, cu nm,
RA

s se selecteze, din mulimea A, o submulime de n+1 numere pentru coeficienii


polinomului, astfel nct valoarea polinomului P(x) ntr-un punct x precizat s fie maxim.
6. La un cabinet medical, n sala de ateptare, se gsesc n pacieni. Timpul necesar
pentru consultarea unui pacient i este ti. Cunoscnd numrul de pacieni n i timpul
TU

necesar pentru fiecare consultaie ti, scriei un program care s afieze ordinea de
tratare a pacienilor, astfel nct timpul total de ateptare al pacienilor s fie minim.
Indicaie. Deoarece timpul de ateptare al unui pacient este egal cu suma timpilor de
consultaie ai pacienilor tratai naintea sa, ordonarea pacienilor dup criteriul
I
ED
68 Tehnici de programare

C
candidatului optim nseamn ordonarea cresctoare dup timpul de consultaie.
Demonstrai c soluia obinut astfel este soluia optim.
Exemplul 4. Problema plii unei sume cu un numr minim de bancnote cu valori

I
OG
date.
Se folosesc urmtoarele date i structuri de date:
Pentru valorile bancnotelor se folosete vectorul a cu n elemente (n reprezint numrul
de tipuri de bancnote).
Pentru suma care trebuie pltit se folosete variabila S.

AG
Se folosesc urmtoarele subprograme: n=4 i S=147 Numr total bancnote=9
Subprogramul citeste() pentru
Valoare bancnot 50 10 5 1
citirea datelor din fiierul text. n fiierul
text, pe primul rnd sunt scrise dou nu- Numr de bancnote 2 4 1 2

ED
mere ntregi, n i S, iar pe rndul urmtor cele n valori ale bancnotelor. Valorile
numerice de pe fiecare rnd sunt separate prin spaiu.
Subprogramul sort() se folosete pentru a sorta descresctor vectorul a.
Subprogramul greedy() implementeaz strategia greedy pentru aceast problem i

P
afieaz soluia n timp ce o construiete.
Strategia greedy este implementat astfel:
I
PAS1. Selectarea bancnotelor ncepe cu bancnota cu valoarea cea mai mare (prima
valoare din vectorul a).
PAS2. Ct timp nu a fost pltit toat suma, execut
PAS3. Dac o parte din suma rmas poate fi pltit n bancnote care au valoa-

rea elementului curent din vectorul a, atunci se determin numrul maxim


IC

de bancnote cu care se face plata (ctul dintre suma rmas i valoarea


bancnotei) i se calculeaz restul din sum care mai rmne de pltit.
PAS4. Se trece la urmtoarea valoare a bancnotei i se revine la Pasul 2.
CT

#include<fstream.h>
int n,m,S,a[20];
fstream f("greedy4.txt",ios::in);
void citeste()
DA

{int i; f>>n>>S;
for(i=1;i<=n;i++) f>>a[i]; f.close();}
void sort()
{int i,j,aux;
DI

for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
if (a[i]<a[j]) {aux=a[i]; a[i]=a[j]; a[j]=aux;}}
void greedy()
RA

{int i=1;
while (S!=0)
{if (S/a[i]!=0)
{cout<<S/a[i]<<" bancnote cu valoarea "<<a[i]<<endl;
TU

S=S%a[i];}
i++;}}
void main()
I

{citeste(); sort(n); greedy();}


ED
Informatic 69

C
Observaie. n plata sumei S cu bancnote de valori date pot s apar dou cazuri
(presupunnd c n moneda respectiv exist bancnote cu valorile precizate mai jos):
1. Suma este 48 i bancnotele au valorile 15, 5 i 4 (n=3). Algoritmul greedy nu va gsi nici

I
o soluie, deoarece va alege 3 bancnote cu valoarea 15, rmnnd un rest de sum cu

OG
valoarea de 3, pentru care nu mai exist bancnote ca s se plteasc. n realitate,
problema are o soluie: 2 bancnote cu valoarea 15, 2 bancnote cu valoarea 5, i 2 banc-
note cu valoarea 8.
2. Suma este 22 i bancnotele au valorile 9, 7, 5 i 1 (n=4). Algoritmul greedy nu va gsi

AG
soluia optim, deoarece va alege 2 bancnote cu valoarea 9, i 4 bancnote cu valoarea
1, n total 6 bancnote. Soluia optim este de a plti cu 4 bancnote: 3 bancnote cu
valoarea 7 i o bancnot cu valoarea 1.
Metoda greedy care nu furnizeaz soluia optim a problemei se numete metoda

ED
euristic greedy.
Ce relaie trebuie s existe ntre valorile bancnotelor pentru ca soluia
Tem greedy s furnizeze soluia optim?

P
Complexitatea algoritmului greedy
Algoritmul greedy propriu-zis are complexitatea O(n), deoarece se parcurg cele n elemente
I
ale mulimii A pentru a alege fiecare dintre cele m elemente ale soluiei. Algoritmul de sortare
folosit pentru aranjarea elementelor mulimii A dup criteriul candidatului optim are complexi-
tatea O(nlog2n) dac se alege un algoritm de sortare eficient, cum este de exemplu

algoritmul QuickSort. Complexitatea metodei greedy este O(n)+ O(nlog2n)= O(nlog2n).


Metoda greedy se recomand n urmtoarele cazuri:
IC

se dorete numai obinerea soluiei optime i suntem siguri c aplicnd strategia greedy
se obine soluia optim;
se dorete obinerea unei soluii acceptabile, nu neaprat optime, i algoritmul greedy
CT

este mult mai eficient dect ali algoritmi care pot duce la obinerea mai multor soluii sau
a soluiei optime.
1. Un automobilist pornete dintr-un ora A i trebuie s ajung n
Tem oraul B. Rezervorul autoturismului, dac este plin, i permite s
DA

parcurg n kilometri. Pe hart sunt trecute m staii de alimentare i


distanele dintre ele. Automobilistul dorete s opreasc la ct mai puine staii pentru
alimentarea autoturismului. Scriei un program care s determine staiile de benzin la
care trebuie s se opreasc pentru alimentare.
DI

2. ntr-un camping exist k csue care pot fi nchiriate 365 de zile din an. Orice turist poate
nchiria o csu pentru exact m zile consecutive din an. Campingul a adunat solicitrile
a n turiti pe un an ntreg, cu un an nainte. Fiecare turist precizeaz prima zi cu care
RA

dorete s nchirieze o csu (1, 2, ). S se determine numrul maxim de turiti care


vor putea fi primii n camping (k100, m20, n1000).
(Concursul Nemes Tihamr, 1998)
3. Un turist trebuie s strbat un traseu de munte. Pe hart, zona prin Nord
TU

care trebuie s treac are o form dreptunghiular, care este 2 1 1 3


mprit, prin caroiaje, n subzone, care au fiecare o anumit 2 1 2 1
nlime. Zona prin care trece turistul poate fi reprezentat printr-o 0 0 4 2
matrice ale crei elemente memoreaz nlimea fiecrei subzone. 3 1 2 3
I

Turistul pornete din sud, din orice subzon de pe hart, i trebuie s


ED

Sud
70 Tehnici de programare

C
ajung n nord, n orice subzon de pe hart, astfel nct s urce ct mai puin pe ntreg
traseul. El poate trece dintr-o zon n alta, numai mergnd n direciile: Est, Nord-Est,
Nord, Nord-Vest i Vest. Datele de intrare sunt dimensiunile matricei i matricea nlimilor

I
i se vor citi din fiier.

OG
4. ntr-o fabric s-a automatizat procesul de producie i, la sfritul zilei de munc, piesele
sunt adunate de roboi industriali. Fiecare robot poate strnge un anumit numr de piese.
Harta halei a fost mprit printr-un caroiaj i poate fi reprezentat printr-o matrice (nm)
ale crei elemente pot avea valorile: 0 (pentru locurile n care nu exist maini) i 1 (pentru

AG
locurile n care exist maini). Roboii se deplaseaz n spaiul de deasupra mainilor,
corespunztor aceluiai caroiaj. Roboii pornesc din colul din stnga sus (1,1) i trebuie
s duc piesele n colul din dreapta jos (n,m). Roboii sunt programai astfel nct s se
deplaseze doar la dreapta sau n jos. S se scrie un program care s determine numrul

ED
minim de roboi care trebuie pornii pentru a strnge toate piesele fabricate ntr-o zi.
(Concursul Nemes Tihamr, 1998)
5. ntr-un depozit al monetriei statului sosesc n saci cu monede. eful depozitului
cunoate numrul de monede din fiecare sac i vrea s modifice coninutul sacilor, prin

P
mutarea de monede dintr-un sac n altul, astfel nct, la sfrit, s fie n fiecare sac
acelai numr de monede. S se scrie un program care s determine, dac este posibil,
numrul minim de mutri prin care fiecare sac s conin acelai numr de monede,
I
altfel s se afieze un mesaj. Fiecare mutare se afieaz sub forma: sac iniial, sac final,
numr de monede. (n2000, iar numrul total de monede 1.000.000.000)
(ONI Oradea, 1998)

1.6. Metoda programrii dinamice


IC

1.6.1. Descrierea metodei programrii dinamice


Metoda programrii dinamice se poate folosi pentru problemele n care trebuie s fie
CT

gsit soluia optim i care au urmtoarele caracteristici:


1. Soluia optim se alege dintr-o mulime de soluii, fiecrei soluii putnd s i se asocieze
o valoare. Alegerea soluiei optime nseamn alegerea soluiei care are valoarea
DA

optim (minim sau maxim).


2. Problema poate fi descompus n subprobleme similare cu problema iniial ce
respect principiul optimalitii: soluia problemei este optim dac ea conine soluiile
optime ale subproblemelor.
DI

3. Subproblemele n care se descompune problema nu sunt independente.


4. Soluia problemei este dat de un vector S = {x1, x2, , xm} i:
exist o mulime finit A din care se poate alege un element xi al soluiei;
fiecare etap de determinare a unui element xi al soluiei se bazeaz pe rezultatele
RA

etapelor n care s-au determinat elementele anterioare ale soluiei;


numrul de posibiliti de a alege un element xi al soluiei se reduce din cauza cerin-
elor de optimizare i a restriciilor impuse soluiei.
TU

Metoda clasic de rezolvare a acestor probleme este de a cuta toate soluiile problemei
i de a alege, dintre soluiile gsite, soluia optim. Algoritmul de generare a tuturor
soluiilor nseamn generarea tuturor submulimilor de indici ai mulimii A cu n elemente
n
i are ordinul de complexitate O(2 ). Acest ordin de complexitate este inacceptabil
I

pentru o dimensiune mare a datelor de intrare n.


ED
Informatic 71

I C
Scop: identificarea problemelor care pot fi descompuse n subprobleme similare care

OG
nu sunt independente i care respect principiul optimalitii, soluiilor putnd s li se
asocieze o valoare, iar soluia optim determinndu-se prin calcularea valorii optime.
Enunul problemei 1: Se consider un triunghi de numere naturale
a11
aij cu n linii. Pornind de la numrul din linia 1, mergnd n jos pn la
linia n, s se determine o selecie de elemente astfel nct suma a21 a22

AG
elementelor s fie maxim. Trecerea la linia urmtoare se poate .
face numai mergnd n jos, direct sau pe diagonal, la dreapta. an1 an2 ann
Metoda clasic de rezolvare a acestei probleme este de a calcula toate sumele care se pot

ED
forma respectnd restricia de deplasare n triunghi i de a alege, dintre sumele gsite, suma
care are valoarea cea mai mare.
Mulimea datelor de intrare o reprezint mulimea A format din elementele aij ale triunghiului.
Valoarea asociat unei soluii este suma elementelor. Valoarea soluiei optime este valoa-

P
rea maxim (suma elementelor trebuie s fie maxim). Soluia problemei este dat de un
vector S = {x1, x2, , xn}, unde xiA. Pentru construirea soluiei se pornete de la elementul
a11 i se merge n jos, pn la linia n. Trecerea la linia urmtoare nu se poate face dect
I
direct, n jos sau pe diagonal, la dreapta, astfel nct succesorul elementului aij nu poate fi
dect elementul ai+1,j sau elementul ai+1,j+1. Problema poate fi descompus n subprobleme:
subproblema i este alegerea elementului xi al soluiei de pe linia i a triunghiului. Restricia

impus pentru soluie este ca elementul xi al soluiei s se obin, prin deplasarea n triunghi,
numai pe dou direcii, de la elementul anterior, limitnd mulimea elementelor din care se
IC

alege elementul xi al soluiei numai la elementele din triunghi care se gsesc ntr-o anumit
poziie fa de elementul anterior al soluiei. Pentru a respecta principiul optimalitii, suma
elementelor alese anterior trebuie s fie maxim. Subproblemele nu sunt independente
CT

deoarece n subproblema i alegerea elementului xi al soluiei se bazeaz pe alegerile fcute


n subproblemele anterioare.
Enunul problemei 2: Dndu-se un ir de numere s se determine subirul cresctor
de lungime maxim.
DA

Fiind dat un ir de numere a1, a2, , an, se definete ca subir cresctor, irul ai1, ai2, , aik,
cu ai1 ai2 aik i 1 i1 i2 ik. De exemplu, n irul de numere 1, -2, 3, 2, 4, 4,
un subir cresctor este 1, 3, 4, 4.
DI

Metoda clasic de rezolvare a acestei probleme este de a genera fiecare subir al mulimii A
i de a verifica dac este subir cresctor. Dintre subirurile cresctoare gsite se alege apoi
subirul care are lungimea cea mai mare.
Mulimea datelor de intrare o reprezint mulimea format din elementele irului: A={a1, a2,
RA

, an}. Valoarea asociat unei soluii este lungimea subirului cresctor. Valoarea
soluiei optime este valoarea maxim (lungimea subirului trebuie s fie maxim).
Soluia problemei este dat de un vector S = {x1, x2, , xm}, unde xiA. Problema poate
fi descompus n subprobleme: subproblema i este de a gsi subirul cresctor de lungime
TU

maxim care ncepe cu elementul ai. Restricia impus pentru soluie este ca elementul ai
cu care ncepe subirul s aib valoarea mai mic sau cel mult egal cu cea a succe-
sorului su n subir (aj), iar n mulimea A numrul lui ordine (i) trebuie s fie mai mic dect
numrul de ordine al succesorului (j), limitnd mulimea elementelor din care se alege
I
ED

succesorul aj. Metoda cea mai simpl de a gsi subirul de lungime maxim care ncepe cu
72 Tehnici de programare

C
elementul ai este de a cuta printre subirurile de lungime maxim descoperite n
subproblemele rezolvate anterior, cel mai lung subir care ncepe cu un element aj ce
poate fi succesor n subir al elementului ai, obinndu-se un nou subir, de lungime mai

I
mare, care ncepe cu elementul ai. Pentru a respecta principiul optimalitii, lungimea

OG
subirurilor descoperite anterior trebuie s fie maxim. Subproblemele nu sunt indepen-
dente deoarece n subproblema i alegerea subirului care ncepe cu elementul ai al
soluiei se bazeaz pe alegerile fcute n subproblemele anterioare.
Enunul problemei 3: O eav cu lungimea L trebuie s se confecioneze din n buci de

AG
eav, fiecare bucat avnd lungimea ai. O bucat de eav nu poate fi tiat. S se
gseasc, dac exist, soluia de a obine eava de lungime L prin sudarea unor buci de
eav cu lungimea ai.
Metoda clasic de rezolvare a acestei probleme este de a genera toate evile care se pot

ED
forma cu cele n buci de eav cu lungimile date i de a verifica dac lungimea evii obinute
este egal cu L.
Mulimea datelor de intrare o reprezint mulimea A format din lungimile bucilor de eav
ai. Valoarea asociat unei soluii este lungimea evii. Valoarea soluiei optime este L

P
(lungimea evii construite trebuie s fie L). Soluia problemei este dat de un vector S
= {x1, x2, , xm}, unde xiA. Problema poate fi descompus n subprobleme: subpro-
blema i este de a gsi toate evile care se pot confeciona adugnd bucata de eav cu
I
lungimea ai la evile care au fost construite n subproblema anterioar. Restricia impus
pentru evile care se construiesc este ca ele s nu depeasc lungimea L. Aceast
restricie limiteaz mulimea evilor construite anterior. Pentru a respecta principiul opti-

malitii, construcia evilor cu ajutorul bucii de eav cu lungimea ai se bazeaz numai


pe evile construite n subproblema anterioar, iar subproblemele nu sunt independente.
IC

Enunul problemei 4: ntr-un rucsac se poate transporta o greutate maxim G i exist n


obiecte, fiecare obiect avnd greutatea gi i un profit obinut n urma transportului ci, iar
CT

obiectele nu pot fi fracionate. S se selecteze obiectele care vor fi transportate n rucsac,


astfel nct s se obin profitul maxim (problema discret a rucsacului).
Metoda clasic de rezolvare a acestei probleme este de a genera toate posibilitile de a
ncrca rucsacul alegnd obiecte din cele n obiecte i de a verifica dac greutatea obiectelor
DA

nu depete greutatea de ncrcare a rucsacului G. Dintre variantele de ncrcare a rucsa-


cului se alege cea care are profitul cel mai mare.
Mulimea datelor de intrare o reprezint mulimea A format din cele n obiecte ai care pot fi
transportate n rucsac. Valoarea asociat unei soluii este profitul transportului. Valoarea
DI

soluiei optime este valoarea maxim (profitul trebuie s fie maxim). Soluia problemei
reprezint ncrctura optim a rucsacului i este dat de un vector S = {x1, x2, , xm},
unde xkA i 1km. Problema poate fi descompus n subprobleme: subproblema i este
RA

de a verifica dac obiectul ai poate fi element al soluiei. Restricia impus pentru soluia
care se construiete este ca obiectul ai s nu aib o greutate mai mare dect greutatea
disponibil a rucsacului i profitul lui s fie mai mare sau egal cu profitul utimului obiect
adugat n rucsac ai-1. Aceast restricie limiteaz mulimea elementelor din care se alege
TU

elementul xk al soluiei. Pentru a respecta principiul optimalitii, elementul xk al soluiei


se determin prin alegerea dintre dou obiecte a celui care are profitul mai mare.
Subproblemele nu sunt independente deoarece rezolvarea subproblemei i se
bazeaz pe rezolvarea subproblemei i-1 (elementul xi al soluiei este determinat n
I

funcie de elementul xi-1 al soluiei).


ED
Informatic 73

C
Metoda programrii dinamice se bazeaz pe descompunerea unei probleme n
subprobleme similare problemei iniiale, care nu sunt independente, i
construiete soluia rezolvnd fiecare subproblem, prin selectarea, dintr-o

I
mulime de elemente, a elementelor care ndeplinesc o anumit condiie. .Pentru

OG
ca elementele care se selecteaz s aparin soluiei optime, la pasul k alegerea
se face n funcie de valoarea optim a unei funcii asociate soluiei i se bazeaz
pe alegerile care s-au fcut pn atunci (pe elementele soluiei care au fost
descoperite anterior).

AG
Etapele de rezolvare a unei probleme prin metoda programrii dinamice sunt:
PAS1. Se demonstreaz c problema are o substructur optim (prin reducere la absurd).
PAS2. Se caracterizeaz structura unei soluii optime (descompunerea problemei n sub-
probleme).

ED
PAS3. Se definete recursiv valoarea soluiei optime.
PAS4. Se calculeaz valoarea soluiei optime ntr-o manier de jos n sus (bottomup).
PAS5. Se construiete soluia optim din informaiile obinute prin calcularea valorii solu-
iei optime.

P
Observaie. Valoarea soluiei optime este definit recursiv n funcie de valorile optime ale
subproblemelor. Dac pentru calcularea funciei recursive s-ar folosi un algoritm recursiv,
n
I
ordinul de complexitate ar fi O(2 ), la fel ca i n cazul metodei clasice de rezolvare. Din
aceast cauz, calcularea funciei recursive se face de jos n sus obinndu-se un
algoritm iterativ:
PAS1. Se rezolv subproblema obinut din descompunerea problemei iniiale care are

cea mai mic dimensiune i se memoreaz soluia ei.


PAS2. Ct timp nu s-a ajuns la rezolvarea problemei cu dimensiunea n, execut: se
IC

rezolv o subproblem de dimensiunea i folosind soluiile obinute n subproble-


mele cu dimensiune mai mic dect i.
CT

1.6.2. Implementarea metodei programrii dinamice


Pentru implementarea metodei programrii dinamice se vor folosi subprogramele:
subprogramul init() care iniializeaz variabilele de memorie i structurile de date
DA

folosite pentru construirea soluiei;


subprogramul p_dinamica() care calculeaz valoarea soluiei optime;
subprogramul afiseaza() care afieaz soluia problemei folosind informaiile
obinute prin calcularea valorii soluiei optime.
DI

n exemplele urmtoare datele de intrare vor fi citite dintr-un fiier text.


Exemplul 1. Problema sumei maxime n triunghi.
Cerina problemei este ca pentru calculul sumei s se porneasc de la elementul a11 i s
RA

se mearg n jos, pn la linia n. Trecerea la linia urmtoare nu se poate face dect direct,
n jos, sau pe diagonal, la dreapta, astfel nct succesorul elementului aij nu poate fi dect
elementul ai+1,j sau elementul ai+1,j+1.
PAS1. Problema are substructur optim. Fie un ir de n numere din triunghi, care res-
TU

pect condiiile de deplasare n triunghi ale problemei, i care formeaz suma maxim. n
subproblema i a fost ales numrul de pe linia i pe baza sumelor maxime calculate n
subproblemele anterioare, altfel se contrazice ipoteza c irul formeaz suma maxim.
I
ED
74 Tehnici de programare

C
PAS2. Descompunerea problemei n subprobleme. Se determin pe rnd sumele maxi-
me ale numerelor care apar pe traseele care pornesc de pe ultima linie n ctre vrf i ajung
pe linia i (1in-1). Pe linia i, suma maxim pentru fiecare element se va calcula pe baza

I
sumelor maxime care s-au calculat n subproblemele anterioare (sumele de la linia n pn

OG
la linia i+1). Aceste sume sunt sumele maxime pentru fiecare linie i principiul optimalitii
este respectat.
PAS3. Valoarea soluiei fiind suma ele- aij dac i=n, 1ji
mentelor selectate, funcia recursiv S(i,j) =

AG
care definete suma maxim pornind aij + max(S(i+1,j), S(i+1,j+1)) dac 1in-1
de la elementul aij al triunghiului este
prezentat alturat.
PAS5. Pentru a calcula valoarea soluiei optime ntr-o manier de de jos n sus, se va

ED
forma un triunghi al sumelor maxime, pornind de la baz (linia n) ctre vrf (linia 1).
Sumele maxime de pe linia n sunt egale fiecare cu elementul corespunztor de pe linia n a
triunghiului. Valoarea maxim a sumei elementelor este S11.
PAS5. Pentru reconstituirea elementelor soluiei,

P
1 dac S(i+1,j) S(i+1,j+1)
se folosete o matrice p, n care se memoreaz p(i,j) =
direcia de deplasare (valoarea 1 pentru depla- 2 dac S(i+1,j) S(i+1,j+1)
sarea n jos i valoarea 2 pentru deplasarea pe
I
diagonal). Matricea p este definit alturat.
Se folosesc urmtoarele date i structuri de date:
Pentru numrul de linii ale triunghiului se folosete variabila n.

Pentru memorarea triunghiului se folosete matricea a, pentru a 0 ... 0


11
memorarea sumelor maxime matricea S, iar pentru memo-
IC

a a 22 ... 0
rarea direciei de deplasare matricea p. Toate aceste matri- 21
ce sunt ptrate, cu dimensiunea n. ... ... ... 0

a n1 an2 ... a nn
CT

Se folosesc urmtoarele subprograme:


Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd este scris numrul de linii, n, iar pe urmtoaree n rnduri numerele de pe
fiecare linie a triunghiului. Numerele sunt separate prin spaiu. n urma execuiei acestui
DA

subprogram se creeaz matricea triunghiului a.


Subprogramul init() iniializeaz linia n a matricei S cu elementele de pe linia n a
triunghiului.
Subprogramul p_dinamica calculeaz valoarea soluiei optime (elementul S11 al ma-
DI

tricei sumelor).
Subprogramul afiseaza() afieaz suma maxim i soluia problemei folosind infor-
maiile din matricea p.
Strategia programrii dinamice este implementat astfel:
RA

PAS1. Se iniializeaz linia n a matricei sumelor maxime S cu elementele de pe linia n a


matricei triunghiului a.
PAS2. Pentru urmtoarele linii ale matricei sumelor maxime ncepnd cu linia n-1 pn la
linia 1, execut:
TU

PAS3. Se calculeaz suma maxim astfel: dac suma maxim S(i+1,j) de sub
elementul curent din triunghi este mai mare dect suma maxim
S(i+1,j+1) de pe diagonala elementului curent, atunci la elementul
I
ED
Informatic 75

C
curent se adun suma S(i+1,j) i direcia de deplasare este 1; altfel, la
elementul curent se adun suma S(i+1,j+1) i direcia de deplasare este 2.

I
Matricea triunghiului a Matricea sumelor Matricea direciei de

OG
Suma maxim = 20 maxime S deplasare p
1 2 3 4 1 2 3 4 1 2 3 4
1 5 0 0 0 1 20 0 0 0 1 1 0 0 0
2 4 2 0 0 2 15 1 0 0 2 1 1 0 0

AG
3 5 4 3 0 3 11 10 8 0 3 2 1 2 0
4 4 6 2 5 4 4 6 2 5 4 0 0 0 0
Programul este:

ED
#include<fstream.h>
int n,a[20][20],p[20][20],S[20][20];
fstream f("pd1.txt",ios::in);
void citeste()

P
{int i,j; f>>n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++) f>>a[i][j]; f.close();}
I
void init()
{for (int i=1;i<=n;i++) S[n][i]=a[n][i];}
void p_dinamica()
{int i,j;

for (i=n-1;i>=1;i--)
IC

for (j=1;j<=i;j++)
if (S[i+1][j]>S[i+1][j+1])
{S[i][j]=a[i][j]+S[i+1][j]; p[i][j]=1;}
CT

else {S[i][j]=a[i][j]+S[i+1][j+1]; p[i][j]=2;} }


void afiseaza()
{int i,j ,q=1,r=1;
cout<<"Suma maxima= "<<S[1][1]<<"= "<<a[1][1]<<"+";
DA

for (i=1,j=1;i<n;i++)
{if (p[i][j]==2) {r=r+1; j++;}
q=q+1; cout<<a[q][r]<<"+";}
cout<<'\b'<<" "<<endl;}
DI

void main()
{citeste(); init(); p_dinamica(); afiseaza();}
Exemplul 2. Problema irului de lungime maxim.
RA

Pentru a determina irul de lungimea maxim, trebuie calculat, pentru fiecare element ai al
irului, lungimea celui mai mare subir cresctor care se poate forma ncepnd cu el, dup
care se alege subirul cu lungimea maxim.
PAS1. Problema are substructur optim. Fie un ir cresctor de m numere din irul
TU

iniial A care ncepe cu numrul ai i respect condiia c este subir al irului A, i care are
lungimea maxim dintre toate subirurile cresctoare care ncep cu numrul ai. n subpro-
blema i se alege subirul cresctor de lungime maxim care ncepe cu numrul ai astfel: se
adaug la numrul ai subirul cu lungime maxim dintre subirurile din subproblemele ante-
I
ED
76 Tehnici de programare

C
rioare care ncep cu numrul aj, cu ai aj i ij, altfel se contrazice ipoteza c subirul are
lungimea maxim.
PAS2. Descompunerea problemei n subprobleme. Se determin pe rnd lungimea

I
maxim a unui subir cresctor care ncepe cu elementul ai din ir, pornind de la subirurile

OG
cresctoare de lungime maxim care ncep cu elementul an, pn la subirurile care ncep
cu elementul ai+1. Pentru elementul ai din ir, lungimea maxim a subirurilor cresctoare
care se pot forma, ncepnd cu el, se va calcula pe baza lungimilor maxime care s-au calculat
n subproblemele anterioare. Aceste lungimi sunt lungimile maxime pentru fiecare subir care

AG
se poate forma ncepnd cu acel element i principiul optimalitii este respectat.
PAS3. Valoarea soluiei fiind lungimea 1 dac i=n
subirului cresctor, funcia recursiv L(i) =
care definete lungimea maxim a sub- 1 + max(L(j)) dac ai aj , in i i jn

ED
irului care se poate forma pornind de la
elementul ai al irului este prezentat alturat.
PAS4. Pentru a calcula valoarea soluiei optime ntr-o manier de jos n sus, se va forma
un vector al lungimilor maxime, pornind de la ultimul element din ir (elementul n) ctre

P
primul element din ir. n acest vector se va memora n poziia i lungimea maxim a unui
subir cresctor care se poate forma ncepnd cu elementul ai al irului. Cum lungimea
maxim a unui subir cresctor care se poate forma cu un singur element este 1, lungimea
I
maxim corespunztoare elementului an se iniializeaz cu valoarea 1.
PAS5. Pentru reconstituirea elementelor soluiei, se folosete vectorul p n care, n poziia i, se
memoreaz indicele elementului urmtor din subirul de lungime maxim care ncepe cu ai.

Se folosesc urmtoarele date i structuri de date:


IC

Pentru numrul de elemente ale irului se folosete variabila n.


Pentru memorarea irului de numere se folosete vectorul a, pentru memorarea lungi-
milor maxime vectorul L, iar pentru memorarea indicelui elementului urmtor din
CT

subir vectorul p. Toi aceti vectori au dimensiunea n.


Se folosesc urmtoarele subprograme:
Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd este scris lungimea irului n, iar pe urmtorul rnd cele n numere din ir.
DA

n urma execuiei acestui subprogram se creeaz vectorul pentru irul de numere a.


Subprogramul init() iniializeaz elementul n al vectorilor L i p.
Subprogramul p_dinamica calculeaz valoarea soluiei optime (lungimea maxim a
subirurilor care ncep cu fiecare element ai din ir).
DI

Subprogramul cauta_soluia() caut cea mai mare lungime maxim a unui subir
pentru a gsi elementul cu care ncepe subirul.
Subprogramul afiseaza() afieaz lungimea irului gsit i soluia problemei
folosind informaiile din vectorul p.
RA

Strategia programrii dinamice este implementat astfel:


PAS1. Se iniializeaz elementul n al vectorului lun-
Indici 1 2 3 4 5 6
gimilor maxime cu 1 i al vectorului p cu n.
TU

PAS2. Pentru urmtoarele elemente i ale vecto- a 1 -2 3 2 4 4


rului, lungimilor maxime ncepnd cu ele- L 4 4 3 3 2 1
mentul n-1 pn la elementul 1, execut:
p 3 3 5 5 6 6
PAS3. Se iniializeaz lungimea maxim
I

a subirului care ncepe cu acest Subirul 1 3 4 4


ED
Informatic 77

C
element cu valoarea 1 i poziia cu care ncepe subirul cu poziia elemen-
tului n ir.
PAS4. Se calculeaz lungimea maxim a subirului care ncepe cu elementul

I
curent din ir, astfel: pentru toate elementele j din ir care urmeaz dup

OG
elementul i, execut
PAS5. Dac ai este mai mic dect aj i lungimea subirului care ncepe
cu aj este mai mare dect lungimea subirului care ncepe cu ai,
atunci L(i) este egal cu 1+L(j) i indicele elementului care urmea-

AG
z n subir dup elementul ai este j.
PAS6. Se determin cea mai mare lungime maxim L(k). Subirul de lungime maxim va
ncepe cu elementul ak.
Programul este:

ED
#include<fstream.h>
int n,k,a[20],p[20],L[20];
fstream f("pd2.txt",ios::in);
void citeste()

P
{int i; f>>n;
for(i=1;i<=n;i++) f>>a[i]; f.close();}
void init()
I
{L[n]=1; p[n]=n;}
void p_dinamica()
{int i,j;

for (i=n-1;i>=1;i--)
{L[i]=1; p[i]=i;
IC

for (j=i+1;j<=n;j++)
if (a[i]<=a[j] && L[i]<=L[j])
{L[i]=L[j]+1; p[i]=j;}}}
CT

void cauta_solutia()
{int i,max=-1;
for (i=1;i<=n;i++)
if (max<L[i]) {max=L[i]; k=i;}}
DA

void afiseaza()
{int i,j;
cout<<"Lungime subsir= "<<L[k]<<endl;
for (i=1,j=k;i<=L[k];i++,j=p[j]) cout<<a[j]<<" ";}
DI

void main()
{citeste();p_dinamica(); cauta_solutie(); afiseaza(); }
Exemplul 3. Problema evii.
RA

Dac se poate construi o eav de lungimea D folosind buci de eav cu lungimea a1, a2,
, ai, atunci se poate construi i o eav cu lungimea D+ai+1 folosind buci de eav cu
lungimea a1, a2, , ai, ai+1.
PAS1. Problema are substructur optim. Fie o eav care s-a obinut prin sudarea bu-
TU

cii de eav cu lungimea ai, la o eav care a fost obinut anterior din buci de eav cu
lungimea aj, i care are lungimea mai mic dect L. n subproblema i se aleg dintre evile
obinute anterior numai acelea care au lungimea mai mic dect L-ai, altfel se contrazice
ipoteza c se poate construi noua eav.
I
ED
78 Tehnici de programare

C
PAS2. Descompunerea problemei n subprobleme. Se determin pe rnd lungimile
evilor care se pot forma cu bucata de eav cu lungimea ai, pornind de la eava format
numai cu bucata de eav cu lungimea a1, pn la evile formate cu primele i-1 buci de

I
eav. evile formate nu depesc lungimea L i principiul optimalitii este respectat.

OG
PAS3. Valoarea soluiei fiind lungimea -1 dac j=0
unei evi, funcia recursiv care define- T(i,j) =
te lungimea evilor care se pot forma ai dac T(i,j- ai) 0 pentru 1in i 1jL
cu bucata de eav cu lungimea ai este

AG
prezentat alturat.
PAS4. Pentru a calcula valoarea soluiei optime ntr-o manier de jos n sus, se vor
forma toate evile cu lungimea mai mic sau egal cu L, pornind de la eava care se poate
construi cu bucata de eav cu lungimea a1, i adugnd la evile obinute, pe rnd, urm-

ED
toarele n-1 buci de eav cu lungimea ai. Pentru a ine evidena evilor care s-au construit
n subproblema i se folosete un vector al lungimilor evilor care se construiesc T, care
are lungimea logic L. n acest vector se va memora n poziia j lungimea ultimei buci de
eav care se adaug la una dintre evile construite anterior pentru a obine o eav cu

P
lungimea j. Principiul optimalitii este respectat prin modul n care se construiete o eav
cu lungimea j: prin adugarea unei buci de eav la una dintre evile confecionate n
subproblema anterioar.
I
PAS5. Pentru reconstituirea elementelor soluiei, se folosete vectorul T. Pornind de la
elementul din poziia L care corespunde evii cu lungimea L, se scade bucata de eav cu
lungimea T(L), obinndu-se lungimea evii la care a fost adugat aceast bucat de eav

(indicele din vectorul T). Procesul continu pn se obine eava cu lungimea 0.


Se folosesc urmtoarele date i structuri de date:
IC

Pentru numrul de buci de eav se folosete variabila n, pentru lungimea evii care
trebuie confecionat, variabila L, iar pentru lungimea maxim a unei evi care se poate
forma adugnd o nou bucat de eav la evile construite anterior variabila max.
CT

Variabila max are iniial valoarea 0 (nu s-a construit nici o eav), iar la sfrit, dac
problema are soluie, are valoarea L (lungimea evii care trebuie confecionat).
Pentru memorarea lungimii fiecrei buci de eav se folosete vectorul a, de lungime
DA

n, iar pentru memorarea evilor care se pot confeciona, vectorul T, de lungime L.


Se folosesc urmtoarele subprograme:
Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd sunt scrise numrul de buci de eav n i lungimea evii L, iar pe
DI

urmtorul rnd, lungimile celor n buci de eav. n urma execuiei acestui subprogram
se creeaz vectorul cu lungimile bucilor de eav a.
Subprogramul init() iniializeaz elementul 0 al vectorului T i variabila max.
Subprogramul p_dinamica calculeaz valoarea soluiei optime (lungimile evilor ce se
RA

pot obine adugnd fiecare bucat de eav ai).


Subprogramul soluie() verific dac s-a gsit soluia problemei.
Subprogramul afiseaza() dac este posibil s se confecioneze eava, afieaz
lungimile bucilor de eav din care se confecioneaz.
TU

Strategia programrii dinamice este implementat astfel:


PAS1. Se iniializeaz elementul 0 al vectorului T cu -1 i variabila max cu valoarea 0.
PAS2. Pentru fiecare bucat de eav cu lungimea ai ncepnd cu bucata de eava cu
I

lungimea a1 pn la bucata de eav cu lungimea an, execut:


ED
Informatic 79

C
PAS3. Pentru evile cu lungimea j ncepnd cu eava cu lungimea max pn la
eava cu lungimea 1, execut:
PAS4. Dac adugnd la eava cu lungimea j bucata de eav cu lungi-

I
mea ai se obine o eav care va putea fi folosit la confecionarea

OG
evii cu lungimea L, atunci construirea evii cu lungimea j+ai
ncepe cu bucata de eav cu lungimea ai. Se revine la Pasul 3.
PAS5. Se determin lungimea maxim a unei evi care se poate construi din evile
construite anterior, astfel: dac adugnd la eava cu lungimea maxim

AG
bucata de eav cu lungimea ai, se obine o eav cu lungimea mai mic
dect L, atunci lungimea maxim a unei evi care se poate construi va fi
mrit cu lungimea bucii de eav ai; altfel, ea va fi L. Se revine la Pasul 2.
PAS6. Dac nu exist soluie (nu exist o bucat de eav cu care se poate ncepe
construirea evii de lungime L), atunci se afieaz un mesaj de informare; altfel, se

ED
trece la Pasul 7 pentru a afia soluia.
PAS7. Pentru fiecare eav cu lungimea i din care s-a obinut eava final, ncepnd de la
eava cu lungimea L, pn la eava cu lungimea 0, execut:
PAS8. Se afieaz lungimea bucii de eav cu care ncepe construirea evii i: T(i).

P
PAS9. Se calculeaz lungimea evii rmase, scznd lungimea bucii de eav
din lungimea i.
I
L=10 indici 1 2 3 4 5
n=5 a 2 2 3 5 6
indici vectorul T = lungime eav

max a(i) 0 1 2 3 4 5 6 7 8 9 10
IC

iniial -1 0 0 0 0 0 0 0 0 0 0
0 a(1) -1 0 2 0 0 0 0 0 0 0 0
CT

2 a(2) -1 0 2 0 2 0 0 0 0 0 0
4 a(3) -1 0 2 3 2 3 0 3 0 0 0
7 a(4) -1 0 2 3 2 5 0 5 5 5 5
DA

10 a(5) -1 0 2 3 2 5 6 5 6 6 6
De exemplu, dup ce s-a luat n consideraie i bucata de eav de lungime a(2) se pot
construi evi cu lungimea 2 (din bucata de eav a(1)=2) i cu lungimea 4 (din bucile de
eav a(1)=2 i a(2)=2), lungimea maxim a unei evi fiind 4. Lundu-se n consideraie i
DI

bucata de eav de lungime a(3)=3 se pot construi evi cu lungimea 2 (din bucata de eav
a(1)=2), cu lungimea 3 (din bucata de eav a(3)=3), cu lungimea 4 (din bucile de eav
a(1)=2 i a(2)=2) i cu lungimea 5 (din bucile de eav a(1)=2 i a(3)=3).
RA

Programul este:
#include<fstream.h>
int L,n,max,T[20],a[20];
fstream f("pd3.txt",ios::in);
TU

void citeste()
{int i; f>>L>>n;
for(i=1;i<=n;i++) f>>a[i]; f.close();}
void init()
I

{T[0]=-1; max=0;}
ED
80 Tehnici de programare

C
void p_dinamica()
{int i,j,k;
for (i=1;i<=n;i++)

I
{for (j=max;j>=0;j--)

OG
if (T[j]!=0 && j+a[i]<=L) T[j+a[i]]=a[i];
if (max+a[i]<L) max=max+a[i]; else max=L;}}
int solutie()
{return T[L]!=0;}

AG
void afiseaza()
{if (!solutie()) cout<<"Teava nu se poate confectiona";
else for (int i=L;i!=0;)
{cout<<"Bucata de "<<T[i]<<" metri "<<endl;
i-=T[i];}}

ED
void main()
{citeste(); init(); p_dinamica(); afiseaza();}

Exemplul 4. Problema discret a rucsacului.

P
PAS1. Fie un ir de m obiecte a cror greutate nu depete greutatea de ncrcare a
rucsacului G i care asigur profitul maxim al transportului. n subproblema i a fost ales
I
obiectul i numai dac greutatea sa nu depete greutatea de ncrcare disponibil i
profitul adus de el este mai mare dect al obiectului adugat anterior n rucsac, altfel se
contrazice ipoteza c ncrcarea rucsacului asigur profitul maxim.

PAS2. Descompunerea problemei n subprobleme. Se determin pe rnd profitul maxim


adus de fiecare obiect ai pentru fiecare greutate de ncrcare disponibil (de la 1 la G) por-
IC

nind de la obiectul a1, pn la obiectul an, pe baza profiturilor maxime aduse de primele
i-1 obiecte.
PAS3. Valoarea soluiei fiind profitul, funcia recursiv care definete profitul maxim C(i,j)
CT

obinut prin ncrcarea optim a rucsacului cu primele i obiecte, avnd disponibil greutatea
de ncrcare a rucsacului j, este prezentat alturat. C(i,0) reprezint profitul maxim al unui
rucsac cu greutatea disponibil 0 (care
nu permite adugarea niciunui obiect i). 0 dac j=0 i 1in
DA

C(0,j) reprezint profitul maxim al unui 0 dac i=0 i 1jG


rucsac gol cu greutatea disponibil j C(i,j) =
(care nu conine niciun obiect). max(C(i-1,j-g(i))+c(i), C(i-1,j)) dac g(i) j
C(i-1,j) n rest
DI

PAS3. Pentru a calcula valoarea soluiei


optime ntr-o manier de jos n sus, se va forma o matrice a profiturilor maxime C,
pornind de la primul obiect (linia 1), pn la ultimul obiect (linia n). Matricea C are
dimensiunea nG. Elementul C(i,j) memoreaz profitul maxim obinut n subproblema i
RA

pentru o greutate disponibil j. Pe linia i, profitul maxim pentru fiecare greutate de ncr-
care j se determin pe baza profiturilor maxime ce s-au calculat n subproblemele anteri-
oare (profiturile maxime de la linia 1 pn la linia i-1). Aceste profituri sunt maxime pentru
fiecare linie i principiul optimalitii este respectat. Valoarea maxim a profitului este CnG
TU

(profitul maxim obinut pentru un rucsac cu greutatea disponibil G ocupat prin alegerea din
cele n obiecte a obiectelor care aduc profitul maxim).
PAS4. Pentru reconstituirea elementelor soluiei, se folosete matricea p cu dimensiunea
nG. Elementul p(i,j) memoreaz obiectul ales n subproblema i pentru o greutate disponi-
I
ED

bil j.
Informatic 81

C
Se folosesc urmtoarele date i structuri de date globale:
Pentru numrul de obiecte se folosete variabila n, iar pentru greutatea rucsacului,
variabila G.

I
Pentru mulimea obiectelor (A) se folosete vectorul a ale crui elemente sunt de tip

OG
nregistrare obiect care conine dou cmpuri: g greutatea obiectului i c profitul
obinut n urma transportului.
Pentru memorarea profiturilor se folosete matricea C, iar pentru memorarea obiectelor
alese ntr-o subproblem se folosete matricea p. Ambele matrice au dimensiunea nG.

AG
Se folosesc urmtoarele subprograme:
Subprogramul citeste() pentru citirea datelor din fiierul text. n fiierul text, pe
primul rnd este scris numrul de obiecte n i greutatea maxim a transportului G, iar pe
urmtoarele n rnduri perechi de numere ntregi, separate prin spaiu, care reprezint

ED
greutatea i profitul transportului unui obiect. n urma execuiei acestui subprogram se
creeaz vectorul obiectelor a.
Subprogramul p_dinamica calculeaz valoarea soluiei optime (profitul maxim obinut
pentru un rucsac cu greutatea disponibil G ocupat prin alegerea din cele n obiecte, a

P
obiectelor care aduc profitul maxim).
Subprogramul afiseaza() afieaz profitul maxim i soluia problemei folosind infor-
maiile din matricea p.
I
Matricea C
n=4 G=10 Greutatea disponibil
Obiectul Greutatea Profitul Obiect 1 2 3 4 5 6 7 8 9 10

1 2 20 1 0 20 20 20 20 20 20 20 20 20
IC

2 3 40 2 0 20 40 40 60 60 60 60 60 60
3 6 50 3 0 20 40 60 60 60 60 70 90 90
4 0 20 40 45 60 65 85 85 105 105
CT

4 4 45
Matricea p
Greutatea disponibil Soluia
Obiect 1 2 3 4 5 6 7 8 9 10 Obiectul Greutatea Profitul
DA

1 0 1 1 1 1 1 1 1 1 1 4 4 45
2 0 1 2 2 2 2 2 2 2 2 2 3 40
3 0 1 2 2 2 2 2 3 3 3 1 2 20
DI

4 0 2 4 2 4 4 4 4 4 4 Total 9 115
Strategia programrii dinamice este implementat astfel:
PAS1. Pentru fiecare obiect i ncepnd cu primul obiect pn la ultimul obiect (n), execut:
RA

PAS2. Pentru greutatea disponibil j ncepnd de la 1 pn la G, execut:


PAS3. Se calculeaz profitul maxim pentru greutatea disponibil j lund n
consideraie profitul care s-ar putea obine prin adugarea obiectului
i: dac greutatea obiectului i este mai mic sau egal cu greutatea
TU

disponibil i profitul adus la greutatea j este mai mare dect profitul


adus de obiectul i-1, atunci profitul pentru obiectul i i greutatea j
este egal cu profitul obiectului i adunat la profitul calculat pentru
I

obiectul i-1 i greutatea j diminuat cu greutatea obiectului i i n


ED
82 Tehnici de programare

C
matricea p se memoreaz obiectul i; altfel, profitul pentru obiectul i
i greutatea j este egal cu profitul obiectului i-1 i greutatea j i n
matricea p se memoreaz obiectul i-1 ales pentru greutatea j.

I
Programul este:

OG
#include<fstream.h>
struct obiect {int g,c;};
obiect a[20];
int n,G,p[20][20],C[20][20];

AG
fstream f("pd4.txt",ios::in);
void citeste()
{int i; f>>n>>G;
for(i=1;i<=n;i++) f>>a[i].g>>a[i].c; f.close();}

ED
void p_dinamica()
{for (int i=1;i<=n;i++)
for (int j=1;j<=G;j++)
if ((a[i].g<=j) && (a[i].c+C[i-1][j-a[i].g]>C[i-1][j]))

P
{C[i][j]=a[i].c+C[i-1][j-a[i].g]; p[i][j]=i;}
else {C[i][j]=C[i-1][j]; p[i][j]=p[i-1][j];}}
void afiseaza()
I
{int i=n,j=G,k; cout<<"Profit total= "<<C[n][G]<<endl;
while (p[i][j]!=0)
{k=p[i][j];

cout<<"Obiectul "<<k<<" cu greutatea "<<a[k].g;


cout<<" si profitul "<<a[k].c<<endl;
IC

j-=a[p[i][j]].g;
while (p[i][j]==k) i--;}}
void main()
CT

{citeste(); p_dinamica(); afiseaza();}


Complexitatea algoritmului programrii dinamice
Algoritmul programrii dinamice are complexitatea O(nm) deoarece se rezolv cele n
DA

subprobleme, iar pentru fiecare subproblem se calculeaz cele m elemente ale valorii
asociate soluiei.
1. Se dau n numere naturale i un numr natural S. S se gseasc,
Tem dac exist, soluia de a obine numrul S ca sum de numere
DI

naturale dintre cele n numere date.


2. S se afieze cel mai mic numr cu exact n divizori.
3. Se citesc de la tastatur dou iruri de caractere S1 i S2. S se insereze spaii n irul
S1 astfel nct dac se suprapun cele dou iruri, numrul de caractere care coincid s
RA

fie maxim.
4. Se dau dou iruri de caractere A i B de lungime n, respectiv m. ntr-un ir de carac-
tere se pot executa numai urmtoarele trei operaii prin care se poate transforma un ir:
S(i) terge caracterul din poziia i, I(i,c) insereaz caracterul c n poziia i i M(i,c)
TU

nlocuiete caracterul din poziia i cu caracterul c. S se transforme irul A n irul B


folosind un numr minim de operaii. Problema se va rezolva n dou variante: a)
transformrile se vor aplica de la stnga la dreapta; b) transformrile se vor aplica de la
I

dreapta la stnga.
ED
Informatic 83

C
5. Se dau dou iruri de numere X={x1, x2, , xm} i Y={y1, y2, , ym}. S se determine
cel mai lung subir comun al celor dou iruri. irul Z={z1, z2, , zk} este subir
comun al irurior X i Y dac el este subir al irului X i subir al irului Y. De

I
exemplu, dac X={1,2,3,2,2,1,4} i Y={2,1,3,1,2,4}, irul Z={2,3,1,4} este un subir

OG
comun al celor dou iruri. Indicaie. Valoarea asociat soluiei este lungimea unui
subir comun, iar funcia recursiv definete valoarea lungimii maxime a unui subir
comun L(i,j) unde i este indicele 0 dac i=0 sau j=0
elementului cu care ncepe subi- L(i,j) = 1+L(i-1,j-1) dac i0, j0 i xi = yj

AG
rul X, iar j este indicele elementului max(L(i,j-1), L(i-1,j) ) dac i0, j0 i xiyj
cu care ncepe subirul Y.
6. Se d un ir de n matrice A1, A2, , An i trebuie s se calculeze produsul lor: A1A2
An. Fiecare matrice Ai, cu 2in, are pi-1 linii i pi coloane (dou matrice A i B se

ED
pot nmuli numai dac numrul de coloane din matricea A este egal cu numrul de
linii din matricea B). S se pun n acest produs parantezele potrivite astfel nct
numrul de nmuliri s fie minim (deoarece nmulirea matricelor este asociativ,
inserarea parantezelor nu modific rezultatul).

P
Indicaie. Fiind date dou matrice Ap,q i Bq,r, matricea produs Cp,r conine elementele:
q
I
c ij a ik b kj
k 1

Timpul necesar pentru calculul matricei produs este determinat de numrul de nmuliri
scalare: aikbkj. De exemplu, pentru produsul A1A2A3, n care matricele au dimen-

siunile 1020, 205 i, respectiv, 540, numrul de nmuliri scalare pentru paranterizarea
IC

((A1A2)A3) este 10205+10540=1200, iar pentru paranterizarea (A1(A2A3)) este


102040+20540=12000 (de 10 ori mai mare dect n exemplul anterior). Valoarea
asociat soluiei este numrul de nmuliri scalare, iar funcia recursiv m(i,j) definete
CT

numrul minim de nmuliri scalare pentru calculul matricei produs AiAj.


0 dac i= j
m(i,j) =
min{ m(i,k) + m(k+1,j) + pi-1pkpj | ikj } dac ij
DA

Numrul minim de nmuliri scalare pentru calculul produsului A1An este m(1,n).
Pentru a memora poziiile parantezelor optime se va folosi matricea s, n care elementul sij
are valoarea k ce reprezint poziia parantezei optime n produsul AiAj. Altfel spus, sij
DI

este egal cu k pentru care m(i,j) = m(i,k) + m(k+1,j) + pi-1pkpj.

1.7. Compararea metodelor de construire a algoritmilor


RA

Metodele backtracking, greedy i programarea dinamic se recomand n cazul proble-


melor care au urmtoarele caracteristici:
soluia poate fi dat de un vector sau o matrice cu elemente de tip ntreg;
elementele soluiei aparin unui subdomeniu limitat.
TU

Algoritmul backtracking are cea mai mare complexitate (complexitatea exponenial), iar
algoritmul greedy, cea mai mic. Alegerea uneia dintre aceste metode se face n funcie de
cerinele problemei:
I

Dac se cere determinarea tuturor soluiilor, se va alege metoda backtracking.


ED
84 Tehnici de programare

C
Dac se cere determinarea soluiei optime, se va alege metoda greedy, dac se
poate demonstra c ea furnizeaz un rezultat corect; altfel, se va alege metoda
programrii dinamice.

I
OG
Metodele greedy i programarea dinamic se folosesc n problemele n care trebuie gsit
soluia optim. n ambele metode alegerea elementului xk al soluiei este irevocabil i
poate duce la obinerea soluiei optime n cazul problemelor care au proprietatea de optim
local, adic soluia optim a problemei cu dimensiunea n a datelor de intrare conine solu-
iile optime ale subproblemelor similare cu problema iniial, dar de dimensiune mai

AG
mic. Deosebirea dintre cele dou metode const n modul n care este construit soluia:
1. n cazul metodei programrii dinamice, se pornete de la structura problemei iniiale
care corespunde soluiei optime globale i se descompune aceast problem n sub-
probleme n care se determin soluiile optime ale subproblemelor (optimul local). Ea se

ED
poate aplica n problemele n care optimul global implic optimul local. Din aceast
cauz, etapa cea mai dificil la aceast metod este cea de determinare a structurii
soluiei optime. Dac se cunoate structura soluiei optime, metoda garanteaz
obinerea soluiei optime a problemei prin determinarea optimului local.

P
2. n cazul metodei greedy, se pornete de la soluiile optime locale i pe baza lor se
construiete soluia optim global. Problema este descompus n subprobleme i
I
soluia este construit treptat: se pornete de la mulimea vid i se alege pe rnd
pentru fiecare element al soluiei candidatul optim pentru acea subproblem. Alegerea
soluiilor optime locale nu garanteaz ns c soluia global obinut este i soluia
optim, deorece optimul local nu implic ntotdeauna optimul global. Din aceast

cauz, pentru a fi siguri c soluia aleas este soluia optim, pentru fiecare problem
trebuie s se demonstreze c modul de alegere a candidatului optim (optimul local)
IC

implic optimul global. Metoda greedy este mai simpl dect metoda programrii
dinamice deoarece la fiecare pas se trateaz numai subproblema curent, iar ordinul de
complexitate este mai mic dect n cazul programrii dinamice.
CT

Metodele greedy i backtracking construiesc treptat soluia problemei. Deosebirea dintre


cele dou metode const n modul n care se construiete soluia. n cazul metodei greedy,
cnd se alege elementul xk al soluiei, dac elementul ai care este candidatul optim al soluiei
DA

nu este element al soluiei, el este ndeprtat din mulimea elementelor candidate la soluie
(A). n acest mod el nu va mai fi verificat atunci cnd se alege un alt element al soluiei,
micornd foarte mult ordinul de complexitate al algoritmului.
Pentru a obine soluia dorit folosind un algoritm ct mai eficient se pot combina
DI

metodele nvate.
Exemplu. Problema plii unei sume cu un numr minim de bancnote cu valori date.
Problema a fost rezolvat cu ajutorul metodei greedy. Folosind aceast metod este posibil
RA

s nu obinei nicio soluie, sau soluia obinut s nu fie soluia optim. Problema poate fi
rezolvat combinnd metoda greedy (prin ordonarea vectorului cu valorile bancnotelor
dup criteriul candidatului optim) cu metoda backtracking. Soluia optim va fi printre
primele soluii generate. Apelul subprogramului bt() se va opri imediat ce se depete
TU

numrul minim de bancnote Prin combinarea celor dou metode se obine un algoritm mai
eficient dect algoritmul backtracking, care va permite gsirea soluiei optime.
I
ED
Informatic 85

C
Metodele divide et impera i programarea dinamic se bazeaz pe descompunerea pro-
blemei n subprobleme similare cu problema iniial. Deosebirile dintre cele dou meto-
de sunt:

I
Divide et impera Programarea dinamic

OG
1. Subproblemele
Subproblemele sunt independente i nu se Subproblemele nu sunt independente i n des-
cunosc de la nceput subproblemele care apar compunerea iniial exist subprobleme comune
n urma descompunerii. De multe ori descompu- unor subprobleme de dimensiuni mai mari. Pen-

AG
nerea n subprobleme depinde de distribuia da- tru a se putea rezolva problema trebuie s se cu-
telor de intrare i este posibil ca n aceeai pro- noasc, de la nceput, subproblemele n care se
blem, pentru date de intrare diferite, s se obi- descompune problema iniial. Aceasta presupu-
n descompuneri diferite (de exemplu, algoritmul ne cunoaterea structurii problemei iniiale i a
cutrii binare sau algoritmul sortrii rapide). relaiei de recuren care determin soluia.

ED
2. Asigurarea eficienei metodei
Este eficient numai dac este respectat regula Este eficient numai dac o subproblem este
de descompunere a problemei n subprobleme rezolvat o singur dat, soluia sa este

P
independente. Dac nu este asigurat indepen- memorat i folosit pentru a obine soluiile
dena problemelor, metoda devine ineficient celorlalte subprobleme.
deoarece, n apelurile recursive, aceeai subpro-
I
blem este rezolvat de mai multe ori.
3. Modul de descompunerea n subprobleme
Descompunerea se face ntr-o manier de sus n Descompunerea se face ntr-o manier de jos n

jos (topdown): problema iniial este descom- sus (bottomup): se rezolv problemele de dimen-
pus n subprobleme din ce n ce mai mici pn se siunile cele mai mici care apar n problema iniial,
IC

obin subprobleme cu rezolvare imediat, se rezolv se memoreaz soluiile lor i se rezolv subprobe-
aceste subprobleme, dup care se combin soluiile mele de dimensiuni din ce n ce mai mari prin com-
subproblemelor de dimensiuni din ce n ce mai mari. binarea soluiilor problemelor mai mici i memorarea
CT

noilor soluii.
4. Algoritmul
Algoritmul este recursiv. Algoritmul este iterativ.
DA

Din cauza acestor deosebiri aceste metode se folosesc pentru clase diferite de probleme. De
exemplu, problema determinrii termenului n al irului lui Fibonacci. Rezolvarea acestei
probleme prin metoda divide et impera este ineficient deoarece pentru a calcula termenul fn
trebuie s se calculeze termenii fn-1 i fn-2. Dar, n calculul termenului fn-1, reapare calculul
DI

termenului fn-2, iar n calculul ambilor termeni apare calculul termenului fn-3 .a.m.d. n acest
caz, se recomand metoda programrii dinamice, calculnd pe rnd termenii f3, f4, , fn,
pornind de la termenii f1=f2=1. Formula de recuren este: fi = fi-1+fi-2, pentru 3in. Deoa-
rece termenul fi nu depinde dect de doi termeni fi-1 i fi-2, nu este necesar s se memoreze
RA

ntregul ir de termeni, ci pentru fiecare subproblem i, numai termenii obinui n subpro-


blemele i-1 i i-2.
TU

Adevrat sau Fals:


1. n algoritmul metodei backtracking iniializarea elementului k al soluiei se face cnd
I

se revine de pe nivelul k+1 la nivelul k.


ED
86 Tehnici de programare

C
2. Algoritmul metodei backtracking se ncheie dac s-au testat toate valorile posibile
pentru primul element al soluiei.
3. n algoritmul backtracking, dup gsirea unei soluii, se revine la nivelul anterior al soluiei.

I
4. n algoritmul backtracking, trecerea de la nivelul k la nivelul k-1 al soluiei se face

OG
dup ce s-au gsit toate valorile posibile pentru nivelul k.
5. n algoritmul backtracking iniializarea nivelului k al soluiei se face cu valoarea de pe
nivelul anterior al soluiei.
6. n algoritmul backtracking, dac s-a trecut la nivelul k al soluiei, nseamn c s-au

AG
gsit primele k-1 elemente ale soluiei.
7. n algoritmul backtracking, trecerea la nivelul k+1 al soluiei se face dup ce au fost
testate toate valorile posibile pentru nivelul k al soluiei.
8. n implementarea recursiv a metodei backtracking revenirea din autoapel este echi-
valent cu revenirea la nivelul anterior al soluiei din varianta iterativ.

ED
9. n implementarea recursiv a metodei backtracking autoapelul este echivalent cu
trecerea la nivelul urmtor al soluiei din varianta iterativ.
10. Divide et impera este metoda prin care problema iniial se descompune n subpro-
bleme care nu sunt independente.

P
11. Prin metoda divide et impera se gsete soluia optim a problemei.
12. Metoda programrii dinamice pornete de la soluiile optime locale i, pe baza lor,
I
construiete soluia optim global.
13. n metoda programrii dinamice descompunerea n subprobleme se face de sus n jos.
14. Metoda greedy se bazeaz pe teorema c optimul local implic ntotdeauna optimul global.

Alegei:
1. Algoritmul care implementeaz metoda backtracking este:
IC

a. polinomial b. logaritmic c. exponenial d. liniar logaritmic


2. Algoritmul care implementeaz metoda sortrii rapide este:
CT

a. liniar b. logaritmic c. ptratic d. liniar logaritmic


3. Algoritmul care implementeaz metoda cutrii binare este:
a. liniar b. logaritmic c. ptratic d. liniar logaritmic
4. Se utilizeaz metoda backtracking pentru generarea anagramelor cuvntului masca.
DA

S se precizeze cuvntul precedent i cuvntul urmtor secvenei camas, camsa,


caams:
a. csaam i casma b. csama i casma c. csaam i casma d. csaam i caasm
5. Se utilizeaz metoda backtracking pentru generarea tuturor numerelor cu 4 cifre dis-
DI

tincte care se pot forma cu cifrele 0, 2, 4 i 8. S se precizeze numrul precedent i


numrul urmtor secvenei 2840 4028 4082:
a. 2480 i 4280 b. 2804 i 4280 c. 2804 i 4208 d. 2480 i 4280
RA

6. Se utilizeaz metoda backtracking pentru generarea irului de opt paranteze rotunde


astfel nct ele s formeze o succesiune corect. S se precizeze irul de paranteze
precedent i irul de paranteze urmtor secvenei (()(())) (()()()) (()())():
a. ((()())) i ()((())) b. ((()))() i ()((())) c. ((()))() i (())(()) d. ((()())) i (())(())
TU

7. Se utilizeaz metoda backtracking pentru generarea submulimilor mulimii {1,2,3}.


S se precizeze submulimea precedent i submulimea urmtoare secvenei de
submulimi {1} {1,3} {1,2} :
a. {} i {2,3} b. {} i {2} c. {2,3} i {1,2,3} d. {} i {3}
I
ED
Informatic 87

C
8. Dac se utilizeaz metoda backtracking pentru a genera toate permutrile de 5
obiecte i primele 4 permutri generate sunt: 5 4 3 2 1, 5 4 3 1 2, 5 4 2 3 1, 5 4 2 1 3,
atunci a cincea permutare este:

I
a. 5 4 3 2 1 b. 5 3 4 2 1 c. 5 4 1 2 3 d. 5 4 1 3 2

OG
(Bacalaureat Sesiunea special 2003)
9. Se cere determinarea tuturor modalitilor de planificare n zile diferite a 4 probe
(rezisten, aruncarea suliei, srituri, tir) n oricare dintre cele 7 zile din sptmn.
Problema este echivalent cu:

AG
a. generarea combinrilor de 4 obiecte luate cte 7
b. generarea aranjamentelor de 4 obiecte luate cte 7
c. generarea combinrilor de 7 obiecte luate cte 4
d. generarea aranjamentelor de 7 obiecte luate cte 4
(Bacalaureat Sesiunea special 2003)

ED
10. Generarea tuturor irurilor de 3 elemente, fiecare element putnd fi oricare numr din
mulimea {1,2,3,4,5,6}, se realizeaz cu ajutorul unui algoritm echivalent cu algoritmul
de generare a:
a. aranjamentelor b. permutrilor c. combinrilor d. produsului cartezian

P
(Bacalaureat Sesiunea special 2003)
11. Se cere determinarea tuturor modalitilor distincte de aezare n linie a tuturor celor
n sportivi aflai la o festivitate de premiere. Problema este echivalent cu generarea:
I
a. partiiilor unei mulimi de n obiecte b. aranjamentelor de n obiecte luate cte 1
c. permutrilor de n obiecte d. submulimilor unei mulimi cu n obiecte
(Bacalaureat Sesiunea iunie-iulie 2003)

12. Condiia ca dou dame Q i D (de tip structur) s se afle pe aceeai diagonal a
tablei de ah este:
IC

a. (Q.linie==D.linie)|| (Q.coloana==D.coloana)
b. abs(Q.linie-D.linie)==abs(Q.coloana-D.coloana)
c. Q.linie-D.linie == Q.coloana-D.coloana
CT

d. abs(Q.linie-D.coloan)==abs(D.linia-D.coloana)
(Bacalaureat Sesiunea iunie-iulie 2003)
13. Se cere determinarea tuturor numerelor formate cu cifre aflate n ordine strict cresc-
toare, cifre alese dintr-o mulime cu k cifre distincte date. De exemplu, pentru cifrele
DA

alese din mulimea {1,5,2} se obin numerele 1, 2, 12, 5, 15, 25, 125 (nu neaprat n
aceast ordine). Problema este echivalent cu generarea:
a. partiiilor unei mulimi b. aranjamentelor de 10 obiecte luate cte k
c. permutrilor de k obiecte d. submulimilor nevide ale unei mulimi
DI

(Bacalaureat Sesiunea august 2003)


14. Cineva dorete s obin i s prelucreze toate numerele formate din trei cifre din
irul 2, 9, 4 i le genereaz exact n ordinea 222, 229, 224, 292, 299, 294, 242, 249,
244, 922, 929, 924, 992, 999, 994, 942, 949, 944, 422, 429, 424, 492, 499, 494, 442,
RA

449, 444. Dac dorete s obin prin acelai procedeu numerele formate din 4 cifre,
atunci dup numrul 4944 va urma:
a. 4949 b. 9222 c. 4422 d. 4924
(Bacalaureat Simulare 2004)
TU

15. Un elev folosete metoda backtracking pentru a genera submulimile mulimii


{1,2,5,6,9}. Cte soluii (submulimi) care obligatoriu conin elementul 2 i nu conin
elementul 6 a generat?
a. 7 b. 16 c. 6 d. 8
I
ED

(Bacalaureat Sesiunea special 2004)


88 Tehnici de programare

C
16. Pentru a determina toate modalitile de a scrie pe 9 ca sum de numere naturale
nenule distincte (abstracie fcnd de ordinea termenilor), un elev folosete metoda
backtracking genernd, n aceast ordine, toate soluiile: 1+2+6, 1+3+5, 1+8, 2+3+4,

I
2+7, 3+6 i 4+5. Aplicnd exact aceeai metod, el determin soluiile pentru

OG
scrierea lui 12. Cte soluii de forma 3+ exist?
a. 7 b. 1 c. 2 d. 4
(Bacalaureat Sesiunea iunie-iulie 2004)
17. Pentru problema anterioar, care este a opta soluie determinat?

AG
a. 2+3+7 b. 3+4+5 c. 1+5+6 d. 1+11
(Bacalaureat Sesiunea iunie-iulie 2004)
18. Pentru problema anterioar stabilii care este soluia cu proprietatea c imediat dup
ea este generat soluia 3+4+5?

ED
a. 3+4+6 b. 2+3+7 c. 2+10 d. 4+8
(Bacalaureat Sesiunea iunie-iulie 2004)
19. Se genereaz toate permutrile distincte de 4 obiecte numerotate de la 1 la 4, avnd
proprietatea c 1 nu este vecin cu 3 (1 nu se afl imediat dup 3, i nici 3 imediat

P
dup 1) i 2 nu este vecin cu 4. Cte astfel de permutri se genereaz?
a. 12 b. 24 c. 6 d. 8
(Bacalaureat Sesiunea august 2004)
I
20. Se cere s se determine toate modalitile distincte de a programa n spectacole n z
zile (de exemplu, dou spectacole Micul Prin i Pcal se pot programa n trei
zile, mari, miercuri i joi, astfel: Micul Prin mari i Pcal miercuri sau; Micul

Prin miercuri i Pcal mari; Micul Prin miercuri i Pcal joi; Micul
Prin mari i Pcal joi; Micul Prin joi i Pcal miercuri etc.).
IC

Rezolvarea se bazeaz pe algoritmul de generare a:


a. combinrilor de n obiecte luate cte z b. aranjamentelor de n obiecte luate cte z
c. combinrilor de z obiecte luate cte n d. aranjamentelor de z obiecte luate cte n
CT

(Bacalaureat Simulare 2005)


21. Se consider algoritmul care determin toate permutrile distincte de n obiecte
(numerotate de la 1 la n) n care nu exist poziii fixe. O permutare (p1, p2, , pn) are
puncte fixe dac exist cel puin o component pi=i. De exemplu, pentru n=5,
DA

permutarea (2,3,5,4,1) are puncte fixe deoarece p4=4. Pentru n=4, stabillii cte
permutri fr puncte fixe exist.
a. 8 b. 9 c. 10 d. 12
(Bacalaureat Sesiunea special 2005)
DI

22. Se consider algoritmul care determin toate permutrile distincte de n obiecte (nume-
rotate de la 1 la n) n care pe orice poziie de rang par se afl o valoare par. De
exemplu, pentru n=5, primele trei permutri generate n ordine lexicografic sunt
(1,2,3,4,5), (1,2,5,4,3), (1,4,3,2,5). Pentru n=4, numrul total de astfel de permutri este:
RA

a. 2 b. 4 c. 8 d. 12
(Bacalaureat Sesiunea iunie-iulie 2005)
23. Se consider algoritmul care genereaz, n ordine strict cresctoare, toate numerele
formate din n cifre distincte (cifrele de la 1 la n), numere n care pe fiecare poziie par
TU

se af o cifr impar. Poziia se numr de la stnga ctre dreapta, pornind de la


poziia 1. De exemplu, pentru n=4, primele trei numere generate sunt: 2143, 2341,
4123. Pentru n=5, primul numr generat este:
a. 21345 b. 21435 c. 12345 d. 13254
I
ED

(Bacalaureat Sesiunea august 2005)


Informatic 89

C
24. Se genereaz toate submulimile formate din dou elemente ale mulimii {5,6,7,8} n
ordinea: 5 6, 5 7, 5 8, 6 7, 6 8, i 7 8. Dac se utilizeaz exact aceeai metod pentru
a genera submulimile de trei elemente ale mulimii {2,3,4,5,6}, atunci penultima mul-

I
ime generat este:

OG
a. 3 4 5 b. 3 5 6 c. 4 5 6 d. 2 5 6
(Bacalaureat Simulare 2006)
Miniproiecte:
Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:

AG
a. dou metode pentru construirea algoritmului (care sunt precizate n cazul pri-
melor 8 miniproiecte);
b. justificarea folosirii metodelor care au fost alese pentru rezolvarea problemei;
c. explicarea metodelor folosite pentru construirea agoritmului;

ED
d. compararea celor dou metode din punct de vedere al corectitudinii soluiei;
e. compararea celor doi algoritmi din punct de vedere al complexitii.
1. Rezolvai problema acoperirii tablei de ah de dimensiunea nn cu un cal care pornete

P
din ptratul de coordonate (x,y) folosind metoda backtracking i metoda greedy.
2. Rezolvai problema costruirii evii de lungime L din buci de eav de lungimi ai folosind
metoda backtracking i metoda programrii dinamice.
I
3. Rezolvai problema gsirii unui traseu pentru a iei din labirintul de dimensiunea nm,
tiind c se pornete din ptratul de coordonate (x,y), folosind metoda greedy i metoda
backtracking.

4. Rezolvai problema plii unei sume cu bancnote cu valori date, pentru fiecare valoare
de bancnot avnd la dispoziie un anumit numr de bancnote, folosind metoda
IC

programrii dinamice i metoda backtracking.


5. Rezolvai problema turistului care trebuie s gseasc un traseu de munte n care s
urce ct mai puin, folosind metoda programrii dinamice i metoda greedy.
CT

6. Rezolvai problema determinrii sumei maxime ntr-un triunghi folosind metoda greedy
i metoda programrii dinamice.
7. Rezolvai problema determinrii unui subir cresctor de lungime maxim folosind
metoda greedy i metoda programrii dinamice.
DA

8. Se dau n paralelipipede avnd fiecare dimensiunile ai, bi i ci. S se construiasc un


turn de nlime maxim prin suprapunerea acestor paralelipipede. Un paralelipiped
poate fi aezat pe orice fa. Un paralelipiped poate fi aranjat peste un alt paralelipiped
numai dac faa lui nu depete faa paralelipipedului pe care este pus. Rezolvai
DI

problema folosind metoda backtracking i metoda programrii dinamice.


9. Pe o tabl de ah de dimensiunea nn un cal pornete din ptratul de coordonate
(x1,y1) i trebuie s ajung n ptratul de coordonate (x2,y2). S se gseasc traseul de
RA

lungime minim.
10. Se dau n piese de domino, fiecare pies i fiind descris prin perechi de dou numere
(xi,yi). S se gseasc o secven de lungime maxim de piese n care oricare dou
piese alturate au nscrise la capetele cu care se nvecineaz acelai numr.
TUI
ED
C
2. Implementarea

I
structurilor de date

OG
2.1. Tipuri de date specifice pentru adresarea memoriei

AG
Memoria intern a calculatorului este organizat sub forma unor locaii de dimensiunea unui
octet, numerotate consecutiv, pornind de la 0. Aceste numere, exprimate n hexazecimal, se
numesc adrese de memorie. Locaiile de memorie pot fi manipulate individual sau n grupuri

ED
contigue. Spaiul de memorie este gestionat de sistemul de operare. Fiecrui program
aflat n execuie, sistemul de operare i rezerv (aloc) propriul spaiu de memorie. Dac pro-
gramul apeleaz subprograme, acestea pot fi privite ca blocuri care conin instruciuni i date
(variabile de memorie i structuri de date), crora sistemul de operare trebuie s le aloce

P
spaiu de memorare n interiorul zonei de memorie rezervat programului principal (care
corespunde fiierului surs). Spaiul de memorare este mprit n patru segmente, iar proce-
sorul are acces la toate cele patru segmente, ale cror adrese le gestioneaz prin intermediul
I
unor regitri:
segmentul de cod n care se ncarc instruciunile programului care se execut;
adresa de nceput se pstreaz n registrul CS;
segmentul de date n care se ncarc anumite date ale programului care se execut

(de exemplu, variabilele globale); adresa de nceput se pstreaz n registrul DS;


segmentul de stiv a sistemului n care se ncarc adresele de revenire din subpro-
IC

grame i variabilele locale cu care lucreaz subprogramele; pentru gestionarea sa se


folosesc doi regitri: SS (n care se pstreaz adresa de la baza stivei) i SP (n care se
CT

pstreaz adresa de la vrful stivei);


extrasegmentul de date n care se ncarc alte date ale programului; adresa de
nceput se pstreaz n registrul ES.
Sistemul de operare aloc spaiu datelor n mai multe zone de memorie, n funcie de
DA

modul n care au fost declarate n program.


variabile locale
zona de adrese libere (heap) (alocarea implicit)
DI

stiva sistemului (stack)


variabile globale variabile locale statice
segmentul de date
(alocarea implicit) (alocare cu static)
regitrii procesorului
RA

variabile locale
(alocare cu register)

O dat manipulat de program prin intermediul unei variabile de memorie este caracterizat
TU

de mai multe atribute pe care le primete n momentul n care este declarat n program:
Numele. Este identificatorul folosit pentru referirea datei n cadrul programului (n
exemplu a).
Adresa. Este adresa de memorie intern la care se aloc spaiu datei respective, pentru
I

a stoca valoarea datei (n exemplu, datei i se aloc adresa adr n stiva sistemului).
ED
Informatic 91

C
2 octei valoarea datei

a = nume dat 0000000001100100

I
void sb()

OG
{int a=100; ...} adr = adresa zonei de memorie adr+2

Memoria intern

AG
Valoarea. Este coninutul, la un moment dat, al zonei de memorie rezervate datei (n
exemplu 100(10) = 1100100(2)).
Tipul. Determin: domeniul de definiie intern al datei (mulimea n care poate lua
valori data), operatorii care pot fi aplicai pe acea dat i modul n care data este

ED
reprezentat n memoria intern metoda de codificare n binar a valorii datei (n
exemplu, tipul este unsigned int: domeniul de definiie intern al datei este intervalul
[0, 65535]), operatorii care pot fi aplicai pe aceast dat sunt operatorii permii de tipul
numeric aritmetici, relaionali, logici, logici pe bii etc. i reprezentarea datei n

P
memoria intern se face prin conversia numrului din zecimal n binar).
Lungimea. Este dimensiunea zonei de memorie alocate datei i se msoar n octei.
Ea depinde de modul de reprezentare intern a tipului de dat (n exemplu, datei i se
I
aloc un grup contiguu de 2 octei). Pentru a afla dimensiunea zonei de memorie alo-
cate unei variabile de memorie se poate folosi operatorul sizeof().
Durata de via. Este perioada de timp n care variabilei i se aloc spaiu de memo-
rare (n exemplu, data a este o variabil cu durat local creia i se aloc spaiu de

memorare numai pe durata de execuie a blocului n care a fost declarat, adic pe


IC

durata de execuie a subprogramului sb).


Pentru a putea manipula o dat, programul trebuie s identifice zona de memorie n care
este stocat. Identificarea acestei zone se poate face att prin numele datei (a), ct i prin
CT

adresa la care este memorat (adr). Pentru a putea manipula datele cu ajutorul adreselor
de memorie, n limbajul C++ sunt implementate urmtoarele tipuri de date:
tipul pointer sau adres;
tipul referin.
DA

Se poate folosi un nou criteriu pentru clasificarea datelor:


criteriul semnificaiei coninutului
DI

Operanzii sau datele care fac obiectul Adresele sau datele care permit
operaiilor de prelucrare. adresarea operanzilor.
Sunt date ale cror valori sunt folosite ca Sunt date ale cror valori sunt folosite pentru
RA

operanzi n cadrul expresiilor utilizate pentru localizarea pe suportul de memorare a datelor


calcularea rezultatelor cerute de problem. care sunt prelucrate (operanzii).

2.2. Tipul de dat pointer


TU

Pointerul este o variabil de memorie n care se memoreaz o adres de memorie.


Observaie. Un pointer se asociaz ntotdeauna unui tip de dat (de exemplu: int, char,
I
ED

float etc.) numit tip de baz. Se spune c un pointer indic o zon de memorie care
92 Implementarea structurilor de date

C
conine o dat care are tipul de baz. Este necesar s se asocieze pointerului un tip de
dat deoarece el memoreaz numai o adres i, pentru a manipula coninutul unei zone de
memorie, compilatorul trebuie s cunoasc dimensiunea zonei de memorie care ncepe de

I
la acea adres i semnificaia coninutului, adic ce algoritm de decodificare trebuie s

OG
foloseasc pentru a transforma secvena de bii (din acea zon de memorie) ntr-o dat.

2.2.1. Declararea variabilelor de tip pointer


Declararea unei variabile de tip pointer se poate face prin instruciunea declarativ:

AG
tip_dat *nume_variabil;
tipul datei stocate la adresa memorat numele variabilei de tip pointer n care se
n pointer (tipul de baz) memoreaz adresa unei variabile de

ED
memorie care are tipul de baz
operatorul de referin
Exemplu:
char *p;

P
int *q;
float *r;
S-au definit trei variabile de tip adres (pointeri): p ctre tipul char, q ctre tipul int i r ctre
I
tipul float. Numele acestor variabile de memorie sunt p, q i r, iar tipul de baz al fiecrei
variabile de tip pointer este char, int, respectiv float. Aadar, p este o variabil de tip
adres a unei locaii ce conine un caracter care ocup 1 octet, q este o variabil de tip

adres a unei locaii ce conine o dat numeric ntreag care ocup 2 octei, iar r este o
variabil de tip adres a unei locaii ce conine o dat numeric real care ocup 4 octei.
IC

Se poate declara un pointer ctre tipul de dat nregistrare (adresa unei nregistrri).
Exemplu:
CT

struct punct {int x,y;};


punct *p;
S-a definit variabila p de tip adres ctre tipul nregistrare punct, adic o adres a unei
locaii care conine dou date numerice ntregi de tip int ce ocup 4 octei.
DA

Pointerul zero are valoarea 0 i indic zona de memorie de la adresa 0.


Pentru limbajul C++ adresa 0 nseamn o adres care nu este valid pentru date, adic o
adres inexistent. Altfel spus, pointerul zero nu indic nimic. Acest tip de pointer este
DI

folosit ca terminator n structurile de date care sunt prelucrate cu ajutorul pointerilor.

2.2.2. Constante de tip adres


RA

O constant de tip adres este un pointer al crui


coninut nu poate fi modificat.
Exemplu. Constanta 0 care semnific adres nul (adres inexistent sau adres
nealocat) este util, n unele cazuri, pentru iniializarea valorii unui pointer. n locul
TU

constantei numerice literale 0, se poate folosi constanta simbolic predefinit NULL.


Observaie. La declararea unui tablou de memorie, acestuia i se aloc o zon de memorie
de dimensiune fix, ncepnd de la o anumit adres de memorie. Adresa de la care se
I

aloc zona de memorie este o constant (nu poate fi modificat) i ea este asociat cu
ED
Informatic 93

C
numele tabloului de memorie. Numele tabloului de memorie este folosit de compilatorul
C++ ca o constant simbolic de tip adres (pointer ctre tipul de baz dat de tipul
elementelor tabloului).

I
Tabloul de memorie este o structur de date omogen, adic o colecie de elemente de

OG
acelai tip, i fiecare element ocup acelai numr de octei. Acest mod de memorare
permite determinarea adresei fiecrui element pornind de la adresa simbolic a tabloului,
care va reprezenta i adresa primului element. Identificarea unui element de tablou de
memorie se face folosind pentru fiecare element un grup de indici (numrul de indici fiind

AG
egal cu dimensiunea tabloului), adresa elementului calculndu-se fa de un element de
referin care este adresa tabloului. Deoarece adresa tabloului este i adresa primului
element, n limbajul C++ numerotarea indicilor se face pornind de la 0, indicele repre-
zentnd deplasarea elementului fa de adresa tabloului.

ED
Exemplul 1: int v[5];
Zona de memorie alocat unui vector are dimensiunea n sizeof(tip_baz). De exemplu,
vectorului v i se va aloca o zon de memorie de 5sizeof(int)=52=10 octei. Identificarea unui
element de tablou de memorie se face folosind un singur indice (i). Dac adresa tabloului v

P
este adr, ea este i adresa elementului v[0], iar adresa elementului v[i] este:
adr + isizeof(tip_baz).
I
2 octei

v[0] v[1] v[2] v[3] v[4]


adr adr+2 adr+4 adr+6 adr+8


IC

adr este o adres de memorie care are valoarea


constantei simbolice v
CT

Pentru exemplul de mai sus, adresa elementului v[2] este:


adr + 2sizeof(int) = adr + 22 = adr + 4.
Exemplul 2: int a[4][2];
DA

4 octei

linia 0 linia 1 linia 2 linia 3


DI

a[0][0] a[0][1] 2 octei a[3][0] a[3][1]

a[1][0] a[1][1] a[2][0] a[2][1]


adr adr+2 adr+12 adr+14
RA

adr+4 adr+6 coloana 0 coloana 1

adr este o adres de memorie care are valoarea constantei simbolice a

Alocarea memoriei unei matrice se face n mod contiguu, memorarea elementelor fcn-
TU

du-se linie cu linie, astfel nct matricea apare ca un vector de linii. Dac matricea are m linii
i n coloane, ea va avea mn elemente. De exemplu, matricea a are 42=8 elemente i este
memorat ca un vector cu m elemente de tip vector cu n elemente, care au tipul de baz al
I

matricei (n exemplu, un vector cu 4 elemente de tip vector cu 2 de elemente de tip int). Zona
ED
94 Implementarea structurilor de date

C
de memorie alocat unei matrice are dimensiunea m n sizeof(tip_baz). n exemplu,
matricei a i se aloc o zon de memorie de 42sizeof(int) =422=16 octei. Identificarea unui
element al matricei se face folosind doi indici (i i j). Adresa tabloului este i adresa primului

I
element, a[0][0]. Dac adresa tabloului este adr, adresa elementului a[i][j] este:

OG
adr + insizeof(tip_baza) + jsizeof(tip_baza)= adr + (in+j)sizeof(tip_baza).
Pentru exemplul de mai sus, adresa elementului a[3] [1] este:
adr + 32sizeof(int) + 1sizeof(int) = adr + 322 + 12 = adr + 14.

2.2.3. Operatori pentru variabile de tip pointer

AG
Pe variabilele de tip pointer se pot aplica urmtoarele tipuri de operatori:
operatori specifici,
operatorul de atribuire,

ED
operatori aritmetici,
operatori relaionali.
2.2.3.1. Operatorii specifici

P
Operatorii specifici variabilelor de tip pointer sunt:
Operatorul & operatorul de adresare. Se aplic pe o variabil de memorie sau un
I
element de tablou de memorie i furnizeaz adresa variabilei de memorie, respectiv a
elementului de tablou. Rezultatul obinut prin aplicarea acestui operator este de tip
pointer. Operaia se numete referenierea unei variabile de memorie.
Operatorul * operatorul de redirectare. Se aplic pe o variabil de tip pointer i

furnizeaz valoarea variabilei de memorie care se gsete la adresa memorat n


IC

pointer. Rezultatul obinut prin aplicarea acestui operator este de tipul datei asociate
pointerului. Operaia se numete dereferenierea unui pointer.
& - operatorul de adresare
CT

referenierea
nume variabil de variabilei de memorie adres variabil de
memorie memorie
(coninut) (pointer)
DA

* - operatorul de redirectare
dereferenierea pointerului
Observaii:
DI

1. Pointerii reprezint adrese ale unei zone de memorie (coninutul unei variabile de me-
morie p de tip pointer este o adres de memorie).
2. Accesul la o zon de memorie se poate face fie folosind identificatorul asociat zonei
RA

de memorie (numele variabilei de memorie), fie aplicnd operatorul de redirectare * pe


adresa zonei de memorie (coninutul adresei de memorie indicate de un pointer p se
refer cu *p).
3. Dimensiunea i semnificaia coninutului unei zone de memorie indicate de un pointer
TU

depind de tipul pointerului.


Exemplul 1
int a=10, *p=&a;
cout<<*p<<endl<<a<<endl;
I

cout<<p<<endl<<&a<<endl;
ED
Informatic 95

C
S-a definit o variabil de memorie de tip int (a) i o variabil de tip pointer ctre tipul
int (*p) creia i s-a atribuit ca valoare adresa variabilei a. n memoria intern se vor aloca
dou zone de memorie: una de 2 octei, pentru variabila de memorie identificat prin numele

I
a, n care se pstreaz o valoare numeric ntreag, i una de 2 octei pentru variabila pointer

OG
identificat prin numele p, n care se pstreaz o adres de memorie (n exemplu, adresa
variabilei de memorie a). Coninutul acestor zone de memorie este prezentat n figur.
2 octei 2 octei

AG
adr 10

p a adr

ED
Memoria intern

Prin instruciunea cout<<*p; se afieaz coninutul variabilei de memorie a. Referirea la


aceast variabil de memorie se face nu prin numele variabilei, ci prin operatorul de redirec-
tare * aplicat pe variabila pointer p n care este memorat adresa variabilei a. Aceast instruc-

P
iune are acelai efect ca i instruciunea cout<<a;. Prin instruciunea cout<<p; se afiea-
z o constant hexazecimal care reprezint o adres de memorie (adresa adr la care este
I
memorat variabila a). Aceast instruciune are acelai efect ca i instruciunea cout<<&a;.
Exemplul 2
int a=10,b=20,*p=&a;
b=*p; /*variabilei b i se atribuie valoarea de la adresa

memorat n variabila p, adic valoarea variabilei a */


IC

cout<<a<<" "<<b; //afieaz 10 10


*p=100; /*variabilei a crei adres este memorat n
pointerul p (adic, variabilei a) i se atribuie valoarea 100 */
CT

cout<<a<<" "<<b; //afieaz 100 10


Observaie. Dac tipul de dat indicat de pointer este tipul nregistrare, data conine mai
multe cmpuri. Operatorul de redirectare prin care se furnizeaz coninutul unui cmp
este operatorul > i se numete operatorul de selecie indirect a membrului unei
DA

structuri.
<nume variabil pointer> > <nume cmp>
El conine dou referine: una la coninutul adresei indicate de pointer i alta ctre un
DI

membru al nregistrrii (cmpul). Rezultatul furnizat de expresie este valoarea membrului


selectat (a cmpului). Este un operator binar care are prioritate maxim i asociativi-
tatea de la stnga la dreapta.
Exemplu
RA

struct punct {int x,y;};


punct a={3,4},*p=&a;
cout<<a.x<<" "<<a.y<<endl; //afieaz 3 4
cout<<p->x<<" "<<p->y; //afieaz 3 4
TU

Observaii:
1. Operatorul * se poate folosi n ambii membri ai unei operaii de atribuire:
int a=10,b=20,*p=&a,*q=&b; // (1)
I
ED

*q=*p; // (2)
96 Implementarea structurilor de date

C
/* variabilei de la adresa memorat n variabila q, adic variabi-
lei b, i se atribuie valoarea de la adresa memorat n
variabila p, adic valoarea variabilei a

I
cout<<a<<" "<<b; //afieaz 10 10

OG
adr_a 10 adr_a 10

p a p a
adr_a *p adr_a *q=*p

AG
*p
adr_b 20 adr_b 10

q b adr_b q *q b adr_b
*q

ED
Memoria intern (1) Memoria intern (2)

2. Construcia *p (p fiind un pointer ctre un tip de dat) poate aprea n orice expresie n

P
locul unei variabile de memorie care are acelai tip ca i cel asociat pointerului:
int a=10,*p=&a;
I
*p=*p+5; /* incrementeaz cu 5 valoarea variabilei de la adresa
memorat n variabila p, adic valoarea variabilei a*/
cout<<a<<" "<<*p; //afieaz 15 15

3. Operatorii * i & sunt operatori unari i au prioritate mai mare dect operatorii
aritmetici, relaionali, logici i de atribuire.
IC

int a=10,*p=&a;
*p+=1; /* incrementeaz cu 1 valoarea variabilei de la adresa memo-
rat n p, adic valoarea variabilei a */
CT

cout<<a; //afieaz 11
4. Asociativitatea operatorilor unari este de la dreapta la stnga. Din aceast cauz,
trebuie folosii cu grij operatorii unari * i ++ (respectiv - -). Astfel, *p++ incrementeaz
DA

cu 1 adresa memorat n variabila p, i nu valoarea de la adresa memorat n p:


int a=10,*p=&a;
++*p; /* incrementeaz cu 1 valoarea variabilei de la adresa
memorat n p, adic valoarea variabilei a */
DI

cout<<a; //afieaz 11
(*p)++; /* incrementeaz cu 1 valoarea variabilei de la adresa
memorat n p, adic incrementeaz cu 1 valoarea variabilei a */
cout<<a; //afieaz 12
RA

5. Datorit tehnicii de suprancrcare a operatorilor permis de limbajul C++, caracterul *


(asterisc) este folosit i ca operator de redirectare (operator unar) i ca operator de
multiplicare (operator aritmetic). Pentru a nmuli valorile memorate la dou adrese de
memorie indicate de doi pointeri p i q este obligatoriu s se foloseasc parantezele:
TU

int a,b=10,c=20,*p=&b,*q=&c;
a=(*p)*(*q); /*variabilei a i se atribuie produsul dintre valoarea de
la adresa memorat n p, adic valoarea variabilei b, i valoarea
I

de la adresa memorat n q, adic valoarea variabilei c */


ED

cout<<a; //afieaz 200


Informatic 97

C
Considernd declaraia: int a,b,*p=&a; instruciu- b=a+10; b=*p+10;
nile de atribuire din tabelul alturat sunt echivalente: a=b; *p=b;
Aadar, localizarea unei date memorate ntr-o varia- a++; (*p)++;

I
a=a+5; *p=*p+5;

OG
bil de memorie se poate face prin:
adresare direct folosind numele variabilei de b=a*a; b=(*p)*(*p);
memorie (n exemplu a); a*=5; *p*=5;
adresare indirect folosind o variabil de tip pointer n care este memorat adresa
zonei de memorie n care este stocat data (n exemplu, p).

AG
1. Scriei un program n care declarai o variabil de memorie de tip
Tem float i un pointer ctre tipul float, citii de la tastatur valoarea
variabilei i i afiai valoarea folosind cele dou metode de adresare:
adresarea direct i adresarea indirect.

ED
2. Scriei un program n care declarai o variabil de memorie de tip nregistrare care va
conine dou cmpuri, corespunztoare numitorului i numrtorului unei fracii, i o
variabil de tip pointer ctre tipul nregistrare , citii de la tastatur valorile cmpurilor

P
din nregistrare i afiai valorile acestor cmpuri folosind cele dou metode de adre-
sare: adresarea direct i adresarea indirect.
I
2.2.3.2. Operatorul de atribuire
Unei variabile de tip pointer i se poate atribui numai o valoare care reprezint o adres de
memorie. Ea poate fi exprimat prin:

O adres de memorie obinut prin aplicarea operatorului de adresare pe o variabil


de memorie definit anterior, de acelai tip cu tipul de baz al pointerului. Dup operaia
IC

de atribuire, variabila de tip pointer va adresa zona de memorie n care este stocat
variabila de memorie.
O alt variabil de tip pointer care se refer la acelai tip de baz. Dup operaia de
CT

atribuire, cele dou variabile de tip pointer vor adresa aceeai zon de memorie.
O constant de tip adres de acelai tip cu tipul de baz al pointerului.
Numele unui tablou de memorie este o constant de tip adres. Dup operaia de
atribuire, variabila de tip pointer va adresa zona de memorie n care este stocat pri-
DA

mul element al tabloului n cazul vectorului, elementul cu indicele 0.


Constanta 0 sau constanta simbolic predefinit NULL care corespunde pointe-
rului zero poate fi atribuit oricrui tip de pointer.
Rezultatul unei expresii construite cu operanzi de tip adres a unor date definite
DI

anterior i care aparin tipului de baz al pointerului.


Observaie. Unui pointer i se poate atribui un pointer de alt tip dect tipul de baz
numai dac se aplic operatorul de conversie explicit de tip. Acest operator trebuie
RA

aplicat ns cu foarte mare precauie, deoarece de multe ori rezultatul obinut nu este cel
dorit.
int a=10, *p=&a; float *q;
q=(float*)p; //Memoria intern (1)
TU

/*tipul expresiei (float*)p este float*, adic pointer ctre tipul


float, i n acest mod pointerului q i s-a putut atribui adresa
memorat n pointerul p*/
cout<<*q<<endl; // Afieaz 1.401298e-44, un numr real.
I
ED
98 Implementarea structurilor de date

C
/* Pointerul q indic o zon de memorie de tip float de 4 octei, din
care primii 2 octei conin reprezentarea n complement fa de 2 a nu-
mrului ntreg 10, iar urmtorii 2 octei o valoare rezidual. Instruc-

I
iunea de afiare face conversia valorii memorate, din reprezentarea n

OG
format intern n reprezentarea n format extern, interpretnd-o ca pe un
numr real reprezentat n virgul mobil simpl precizie */
*q=10; cout<<*q<<endl; // Afieaz 10
p=(int*)q; // Memoria intern (2)

AG
//pointerului p i s-a atribuit adresa memorat n pointerul q
cout<<*p; // Afieaz 0, un numr ntreg.
/*Pointerul p indic o zon de memorie de tip int de 2 octei, care re-
prezint primii 2 octei din grupul de 4 octei n care a fost reprezen-
tat n virgul mobil simpl precizie numrul real 10. Instruciunea de

ED
afiare face conversia valorii memorate din reprezentarea n format
intern n reprezentarea n format extern, interpretnd-o ca pe un numr
ntreg reprezentat n complement fa de 2 */

P
2 octei 2 octei
valoare rezidual
adr
I
10

p 2 octei a
adr
adr

q
Memoria intern (1)
IC

2 octei reprezentat n virgul


2 octei mobil simpl precizie
CT

adr 10

p 2 octei a
adr 4 octei
adr
DA

q
Memoria intern (2)

Exemplul 1:
DI

char c='A',*p;
p=&c; /*variabilei p de tip pointer ctre caracter i se atribuie
adresa variabilei de memorie c */
cout<<c<<" "<<*p; //afieaz A A
RA

Exemplul 2:
int a=10,*p=&a,*q;
q=p; /* pointerului q i se atribuie valoarea pointerului p, adic
TU

adresa variabilei a */
cout<<*p<<" "<<*q; //afieaz 10 10
Exemplul 3: Numele unui vector este numele unei variabile de memorie, dar i o con-
stant de tip adres cu tipul de baz al elementelor vectorului, care indic primul element
I

al vectorului. Pointerului p i se poate atribui adresa vectorului a exprimat prin:


ED
Informatic 99

C
constanta simbolic a;
operatorul de adresare & aplicat pe numele variabilei a;
operatorul de adresare & aplicat pe identificatorul primului element al vectorului a[0],

I
iar urmtoarele operaii de atribuire sunt echivalente:

OG
p=a p=&a p=&a[0] i *p a[0]
int a[10],i,k=1,*p;
for (i=0;i<10;i++) a[i]=k++;
p=a; /*variabilei p i se atribuie numele vectorului a, care

AG
este o constant simbolic de tip adres */
cout<<*p<<" "<<a[0]<<endl; //afieaz 1 1 - valoarea elementului a[0]
Exemplul 4: Numele unei matrice este numele unei variabile de memorie, dar i o con-
stant de tip adres cu tipul de baz al elementelor matricei, care indic primul element

ED
al matricei. Pentru un pointer p cu tipul de baz al elementelor matricei a, care trebuie s
indice primul element al matricei, urmtoarele operaii de atribuire sunt echivalente:
p=a p=&a p=a[0] p=&a[0][0] i *p a[0][0]
int a[10][10],i,j,k=1,*p;

P
for (i=0;i<10;i++)
for (j=0;j<10;j++) a[i][j]=k++;
I
p=a; /*variabilei p i se atribuie numele matricei a, care
este o constant simbolic de tip adres */
cout<<*p<<" "<<a[0][0]<<endl; //afieaz 1 1 - valoarea elementului a[0][0]
Exemplul 5:

int a[4][5],i,j,k=1,*p;
IC

for (i=0;i<4;i++)
for (j=0;j<5;j++) a[i][j]=k++;
p=a[0]; /*variabilei p i se atribuie adresa vectorului format
CT

din prima linie a matricei a, care este o constant */


cout<<*p<<" "<<a[0][0]<<endl;
//afieaz 1 1 - valoarea elementului a[0][0]
DA

Exemplul 6:
int *q;
q=0; // pointerului q i se atribuie constanta 0
cout<<*q<<endl; /*nu afieaz nimic, deoarece pointerul q are
DI

valoarea 0 i el nu indic nici o adres de memorie */


q=NULL; // pointerului q i se atribuie constanta simbolic NULL
cout<<*q; /*nu afieaz nimic deoarece pointerul q are
valoarea NULL i el nu indic nici o adres de memorie */
RA

Unui pointer nu i se poate atribui valoarea unei constante ntregi,


Atenie chiar dac este o constant hexazecimal, deoarece programatorul
nu are acces direct la adresele de memorie pentru a le gestiona.
TU

Unei date nu poate s i atribuie o adres de memorie dect sistemul de operare.


Deoarece numele tabloului de memorie este folosit de compila-
Atenie torul C++ ca o constant simbolic de tip adres, unei variabile
de tip tablou nu i se poate atribui o alt variabil de tip tablou sau un
I
ED

pointer, ca n exemplul urmtor:


100 Implementarea structurilor de date

C
int a[10],b[10],*p=&b;
a=b; a=p; // Eroare! Unei constante nu i se poate modifica valoarea
Scriei un program n care declarai o variabil de memorie de tip nre-

I
Tem

OG
gistrare, care conine dou cmpuri corespunztoare numitorului i nu-
mrtorului unei fracii i o variabil de tip pointer ctre tipul nregistrare
i care s realizeze urmtoarele:
a. atribuie pointerului adresa variabilei nregistrare;
b. citete de la tastatur valorile pentru numrtor i numitor;

AG
c. afieaz fracia simplificat rezultatele se obin n dou variante, folosind cte una
dintre cele dou metode de adresare (adresarea direct i apoi adresarea indirect)
i se compar rezultatele obinute.

ED
2.2.3.3. Operatorii aritmetici
Operaiile aritmetice permise asupra pointerilor sunt:
Adunarea i scderea unei constante operatorii + i -.
Incrementarea i decrementarea unui pointer operatorii ++ i --.

P
Scderea a doi pointeri de acelai tip operatorul -.
Toate operaiile aritmetice cu pointeri ctre un tip de baz se execu-
I
Atenie t considernd unitatea egal cu sizeof(tip_baz), adic egal cu
numrul de octei necesari pentru a memora o dat care are tipul
tip_baz. De exemplu, incrementarea unui pointer ctre tipul int va considera unitatea
egal cu 2 (numrul de octei necesari pentru reprezentarea tipului int) i noua adres se

va obine prin adunarea constantei 2 la adresa iniial memorat de pointer.


IC

Operatorul pentru adunarea sau scderea unei constante este:


p + k sau p - k
CT

unde p este un pointer ctre tipul tip_baza care memoreaz o adres adr, iar k o constan-
t. Rezultatul este o adres care se calculeaz astfel: adr+ksizeof(tip_baza), respectiv
adr-ksizeof(tip_baza).
Observaie: Operaia de adunare este comutativ: p+k = k+p.
DA

Operatorul pentru incrementarea i decrementarea unui pointer este:


p++ sau p- -
unde p este un pointer ctre tipul tip_baza care memoreaz o adres adr. Rezultatul este
DI

o adres care se calculeaz astfel: adr+sizeof(tip_baza), respectiv adr-sizeof(tip_baza).


Operatorul pentru scderea a doi pointeri este:
p-q
RA

unde p i q sunt doi pointeri ctre acelai tip de baz, care indic elementele aceluiai
tablou de memorie, adresa memorat de p fiind mai mare dect cea memorat de q (p
indic un element de tablou situat n memorie dup elementul indicat de pointerul q).
Rezultatul este un numr ntreg care reprezint numrul de elemente aflate ntre p i q.
TU

Operaiile aritmetice cu pointeri au sens numai dac adresele indi-


Atenie cate de pointerii operanzi i de pointerul rezultatului expresiei se
pstreaz n spaiul de adrese ale unui tablou de memorie. Sin-
I
ED
Informatic 101

C
gura excepie acceptat este cea a pointerului care indic adresa unui element situat
imediat dup ultimul element al tabloului.
Exemplul 1 n cazul n care operatorii aritmetici se aplic pe pointeri care nu-i pstreaz

I
valorile n spaiul unui tablou de memorie, rezultatele obinute nu au nici un fel de relevan.

OG
int a=10,*p=&a,*q=p; cout<<p<<" "<<*p<<endl;
p++; cout<<p<<" "<<*p<<endl; p++; cout<<p<<" "<<*p<<endl;
/*Zona de memorie indicat de pointer dup fiecare operaie de
incrementare conine o valoare rezidual care nu are nici un fel de

AG
relevan n cadrul programului*/
cout<<p-q; // afieaz 2
Exemplul 2 Se inverseaz un vector n el nsui. Se folosesc doi pointeri p i q ctre ele-
mentele vectorului care se interschimb.

ED
int a[20],n,*p,*q,aux;
cout<<"n= ";cin>>n;
for (p=a;p<a+n;p++) {cout<<"elementul "<<p-a+1<<"= "; cin>>*p;}
for(p=a,q=a+n-1;p<q;p++,q--) {aux=*p; *p=*q; *q=aux;}

P
for(p=a;p<a+n;p++) cout<<*p<<" ";
Observaie. Prin definiie, operatorul indice al tabloului ([ ]):
I
se aplic pe doi operanzi x i y (x[y] sau y[x]), x fiind un pointer i y un ntreg;
realizeaz adunarea dintre pointerul x i constanta y, obinnd adresa elementului
y al vectorului de la adresa x;

rezultatul furnizat este valoarea indicat de pointerul obinut, adic valoarea ele-
mentului y al vectorului de la adresa x: x[y]=y[x] =*(x+y).
IC

Este un operator binar i are prioritate maxim i asociativitatea de la stnga la dreapta.


Elementul i al vectorului a poate fi identificat prin a[i], deoarece operatorul indice al ta-
bloului ([ ]) execut suma dintre pointerul a (o adres) i constanta numeric i. Prin apli-
CT

carea acestui operator se obine valoarea de la adresa elementului i. Deoarece operaia


de adunare dintre un pointer i o constant este comutativ, urmtoarele expresii sunt
echivalente i se pot folosi pentru identificarea elementului i al vectorului:
a[i] *(a+i) *(i+a) i[a]
DA

Un element al matricei a poate fi identificat, folosind cei doi indici i i j, prin a[i][j].
Asociativitatea operatorului indice al tabloului fiind de la stnga la dreapta i prioritatea
sa fiind cea mai mare, calcularea adresei elementului se va face astfel: mai nti se
DI

execut suma dintre pointerul a i constanta i i apoi suma dintre rezultatul obinut
anterior i constanta j. Prin aplicarea operatorilor indice al tabloului se obine adresa
elementului din linia i i coloana j, urmtoarele expresii fiind echivalente:
a[i][j] *(a[i]+j) (*(a+i))[j] *(*(a+i)+j)
RA

*(&a[0][0]+n*i+j)

2.2.3.4. Operatorii relaionali


Operatorii relaionali care pot fi aplicai asupra pointerilor sunt:
TU

Operatorii de inegalitate: <, >, <= i >=.


Operatorii de egalitate: == i !=.
Evaluarea unui operator relaional aplicat pe doi pointeri p i q se face prin analiza dife-
I

renei p-q.
ED
102 Implementarea structurilor de date

C
Exemplu Se afieaz ordinea n care apar dou valori x i y ntr-un vector cu numere
ntregi. Se folosesc doi pointeri p i q ctre elementele vectorului. Se parcurge vectorul
folosind pointerul p pentru localizarea valorii x i pointerul q pentru localizarea valorii y.

I
Stabilirea ordinii de apariie n vector se face prin compararea celor doi pointeri (a adreselor

OG
memorate n pointeri).
int x,y,a[100],*p=a,*q=a;
cout<<"n= ";cin>>n;
for (;p<a+n;p++) {cout<<"elementul "<<p-a+1<<"= "; cin>>*p;}

AG
cout<<"prima valoare= "; cin>>x;
cout<<"a doua valoare= "; cin>>y;
p=a;
while (*p!=x) p++;

ED
while (*q!=y) q++;
if (p>q) cout<<"valoarea "<<y<<" apare inaintea valorii "<<x;
else cout<<"valoarea "<<x<<" apare inaintea valorii "<<y;
Scriei urmtoarele programe, n care prelucrarea vectorilor se va face cu

P
Tem ajutorul pointerilor. Elementele vectorilor se citesc de la tastatur.
1. Se terge elementul cu valoarea k dintr-un vector cu numere ntregi.
Valoarea numrului k se citete de la tastatur.
I
2. Se insereaz elementul cu valoarea x naintea elementului cu valoarea y. Valorile
numerice x i y se citesc de la tastatur.
3. Se insereaz elementul cu valoarea x dup elementul cu valoarea y. Valorile

numerice x i y se citesc de la tastatur.


4. Se ordoneaz cresctor elementele vectorului.
IC

5. Se afieaz elementele comune din doi vectori a i b o singur dat.

2.3. Tipul de dat referin


CT

Acest tip de dat permite folosirea mai multor identificatori pentru aceeai variabil de me-
morie. Declararea unei variabile de tip referin se poate face prin instruciunea declarativ:
DA

tip_dat &nume_variabil = nume_variabil_referit;


tipul datei la care se
numele variabilei de memorie la care se refer
refer variabila de
variabila de memorie definit
DI

memorie definit
numele variabilei de memorie care se definete
operatorul de refereniere prin referina la o alt variabil de memorie
Exemplu: int a=10;
RA

int &b=a;
sau
int a=10,&b=a;
Variabila de memorie b este o referin ctre variabila de memorie a. Aceasta nseamn
TU

c, prin referin, variabilei de memorie (a) i s-a mai dat un nume (b). Cele dou variabile
de memorie (a i b) au aceleai atribute (adres de memorie, lungime, valoare, tip etc.), cu
excepia numelui. Chiar dac n program s-au declarat dou variabile de memorie (a i b),
se lucreaz cu o singur zon de memorie, care poate fi identificat cu dou nume diferite,
I
ED

iar urmtoarele dou instruciuni vor afia aceleai valori:


Informatic 103

C
cout<<"a = "<<a<<"adresa lui a= "<<&a<<endl;
cout<<"b = "<<b<<"adresa lui b= "<<&b;
Orice operaie de modificare a valorii variabilei referite prin numele b, va modifica valoarea

I
OG
variabilei identificate prin numele a, deoarece ambele nume de variabile se refer la coni-
nutul aceleiai zone de memorie. Urmtoarele dou instruciuni vor afia aceleai valori:
b=15;
cout<<"a = "<<a<<"adresa lui a= "<<&a<<endl;
cout<<"b = "<<b<<"adresa lui b= "<<&b;

AG
Observaii:
1. Tipul de dat referin, la fel ca i tipul de dat pointer, conine o adres. Pentru a
avea acces prin referin la o variabil de memorie nu este ns nevoie s se

ED
foloseasc adresa de memorie, ci numele variabilei referin.
Exemplu:
int a=10,b=200; //s-au declarat dou variabile ntregi

P
int &x=a; //s-a declarat o referin la variabila a
int *p=&a; //s-a declarat un pointer care indic variabila a
int *q=&x; //s-a declarat un pointer care indic variabila x
I
cout<<a<<" "<<x<<" "<<*p<<" "<<*q<<" "<<endl;
//afieaz 10 10 10 10
*p=20; cout<<a<<" "<<x<<" "<<*p<<" "<<*q<<" "<<endl;

//afieaz 20 20 20 20
x=30; cout<<a<<" "<<x<<" "<<*p<<" "<<*q<<" "<<endl;
IC

//afieaz 30 30 30 30
p=&b; //p indic variabila b
cout<<b<<" "<<*p<<endl; //afieaz 200 200
CT

p=&x; //p indic variabila x care se refer la variabila a


cout<<b<<" "<<*p<<endl; //afieaz 200 30
2. Operatorii aritmetici aplicai pe variabile referin nu modific valoarea adresei refe-
rite, ci valoarea memorat la adresa variabilei referite. Operatorii relaionali aplicai pe
DA

variabile referin nu compar valorile adreselor referite, ci valorile memorate la


adresele variabilelor referite.
Exemplu:
DI

int a=10,b=20,&x=a,&y=b;
x=30; cout<<a<<" "<<x<<endl; //afieaz 30 30
x++; cout<<a<<" "<<x<<endl; //afieaz 31 31
x=--x; x+=x*2; cout<<a<<" "<<x<<endl; //afieaz 90 90
RA

if (x!=y) cout<<"adevarat" <<endl; //afieaz adevarat


x=++y; cout<<a<<" "<<x<<endl; //afieaz 21 21
cout<<b<<" "<<y<<endl; //afieaz 21 21
if (x==y) cout<<"adevarat" <<endl; //afieaz adevarat
TU

Atenie 1. Referina trebuie iniializat chiar n momentul declarrii ei.


Exemplu:
I
ED

int a,&b; // Eroare: variabila referin nu a fost iniializat


104 Implementarea structurilor de date

C
2. Dup ce a fost iniializat, referina nu mai poate fi modificat (nu se mai poate
schimba adresa de memorie la care se refer).
Exemplu:

I
OG
int a=10,b=100,&x=a;
cout<<a<<" "<<x<<endl; //afieaz 10 10
x=&b; /* Eroare: variabilei referin x nu i se poate atribui
adresa variabilei de memorie b, deoarece variabila x, prin definiie,
se refer la variabila de memorie a i memoreaz adresa ei */

AG
x=b; /* Corect: variabilei referin x i se poate atribui
valoarea variabilei de memorie b, aceasta nsemnnd c variabilei
referite de x (variabila a) i se atribuie valoarea variabilei b */
cout<<a<<" "<<x<<endl; //afieaz 100 100

ED
3. Nu se poate crea un pointer la o referin.
Exemplu:
int a=10,&x=a;

P
int *p=x; /* Eroare: pointerului p nu i se poate atribui adresa
memorat n variabila x, deoarece numele variabilei x nu identific o
adres, ci o valoare ntreag memorat la adresa variabilei a */
I
int *p=&x; /* Corect: pointerului p i se poate atribui adresa
variabilei referin x, aceasta fiind de fapt adresa variabilei a */
4. Nu este permis declararea unei referine la o adres exprimat printr-o referin

sau printr-un pointer.


Exemplu:
IC

int a=10,b=100,*p=&a,*q=&b,&x=a;
int &y=&x; /* Eroare: s-a declarat variabila y care trebuie s se re-
fere la o variabil de tip int, ca o referin la adresa variabilei x */
CT

int &y=x; /* Corect: s-a declarat variabila y ca o referin la


variabila x, care este o referin la variabila a; variabila y se refer
la variabila a */
DA

int &z=q; /* Eroare: s-a declarat variabila z, care trebuie s


se refere la o variabil de tip int, ca o referin la variabila
pointer q care memoreaz o adres */
int &z=*q; /* Corect: s-a declarat variabila z, care trebuie s
DI

se refere la o variabil de tip int, ca o referin la o variabil


a crei adres este indicat de pointerul q (adic variabila b)*/
cout<<a<<" "<<*p<<" "<<x<<" "<<y<<endl; //afieaz 10 10 10 10
cout<<b<<" "<<*q<<" "<<z<<endl; //afieaz 100 100 100
RA

*p=20; cout<<a<<" "<<*p<<" "<<x<<" "<<y<<endl;


//afieaz 20 20 20 20
x=30; cout<<a<<" "<<*p<<" "<<x<<" "<<y<<endl;
//afieaz 30 30 30 30
TU

p=&z; b=200;
cout<<a<<" "<<*p<<" "<<x<<" "<<y<<" "<<*q<<" "<<z<<endl;
//afieaz 30 200 30 30 200 200
5. Tipul referinei i tipul variabilei la care se refer trebuie s fie acelai i referina
I
ED

i obiectul la care face referirea trebuie s fie de acelai tip. Astfel, dac referina
Informatic 105

C
este o variabil de memorie, referirea trebuie s se fac tot la o variabil de memorie,
i nu, de exemplu, la o constant, chiar dac aceasta este de acelai tip cu referina. n
cazul n care nu se respect aceste reguli, compilatorul v va ateniona. Aceasta

I
nseamn c programul va putea fi executat, dar rezultatul obinut nu va fi cel ateptat,

OG
deoarece se creeaz o variabil de memorie temporar, cu tipul referinei, creia i se
atribuie valoarea variabilei referite, respectiv a constantei, iar variabila referin va
adresa aceast variabil temporar, i nu variabila referit, respectiv constanta:
Exemplu:

AG
char c='A'; float &a=c;
//echivalent cu: char c='A'; float temp=c; float &a=temp;
//temp fiind variabila de memorie temporar
cout<<a<<" "<<c<<endl; //afieaz 65 A

ED
a=a/5; cout<<a<<" "<<c<<endl; //afieaz 13 A
c++; cout<<a<<" "<<c<<endl; //afieaz 13 B
int &a=10; //echivalent cu: int temp=10; int &a=temp;
//temp fiind variabila de memorie temporar

P
cout<<a<<endl; //afieaz 10
a=20; cout<<a; //afieaz 20
I
Scriei un program n care declarai o variabil de memorie de tip float i
Tem o referin ctre aceast variabil de memorie, citii de la tastatur i
afiai valoarea variabilei de tip float folosind cele dou nume ale vari-
abilei de memorie.

Utilitatea tipului de dat referin


IC

Tipul de dat referin este util n transmiterea datelor ntre modulul apelant i subprogam prin
intermediul parametrilor de comunicaie. n timpul execuiei subprogramului, datele cu care
el lucreaz (variabilele locale i parametrii cu care a fost apelat) sunt pstrate n stiv.
CT

Instruciunile subprogramului pot modifica aceste date. Modificrile se execut asupra


valorilor memorate n stiv. Cnd se termin execuia subprogramului, spaiul ocupat n
stiv de parametri i de variabilele locale este eliberat i n cazul parametrilor de ieire
DA

sau de intrare-ieire se pierd valorile calculate n subprogram.


void sb(int a) {a=a+2; cout<<a<<endl;;} //afieaz 4
void main() {int a=2; sb(a); cout<<a; } //afieaz 2
Folosind transferul parametrului prin referin, n momentul apelrii subprogramului, n
DI

stiv este ncrcat adresa de memorie la care se gsete valoarea parametrului. Subprogra-
mul va lucra direct n zona de memorie n care se gsete data. Aadar, att modulul apelant
ct i subprogramul lucreaz asupra aceleiai date, i orice modificare a valorii acestui
parametru fcut n subprogram se va reflecta i n modulul apelant. La terminarea execuiei
RA

subprogramului, este eliberat din stiv zona n care este memorat adresa parametrului.
void sb(int &a) {a=a+2; cout<<a<<endl;;} //afieaz 4
void main() {int a=2; sb(a); cout<<a; } //afieaz 4
TU

ntre modulul apelant i subprogram se pot transmite i parametri de tip adres. Dac
adresa este transmis prin valoare i ea este modificat n subprogram, noua valoare se
pierde la terminarea execuiei subprogramului.
void sb(int *p) {int x=4; p=&x cout<<*p<<endl;} //afieaz 4
I
ED

void main() {int a=2,*p=&a; sb(p); cout<<*p;} //afieaz 2


106 Implementarea structurilor de date

C
Folosind transferul parametrului prin referin pentru pointer, n momentul apelrii subpro-
gramului, n stiv este ncrcat adresa de memorie a pointerului i subprogramul va lucra
direct n zona de memorie n care se gsete pointerul. Aadar, att modulul apelant ct i

I
subprogramul lucreaz asupra aceleiai date, i orice modificare a adresei memorate n

OG
pointer fcut n subprogram se va reflecta i n modulul apelant. La terminarea execuiei
subprogramului, este eliberat din stiv zona n care este memorat adresa pointerului.
void sb(int *&p) {int x=4; p=&x; cout<<*p<<endl;} //afieaz 4
void main() {int a=2,*p=&a; sb(p); cout<<*p;} //afieaz 4

AG
2.4. Alocarea dinamic a memoriei
Declarrile de date n cadrul programului folosesc alocarea static a memoriei.

ED
Alocarea static a memoriei se face n timpul compilrii, n funcie de modul
n care a fost declarat variabila de memorie sau structura de date,
iar n timpul execuiei programului nu mai poate fi modificat.
Variabilele care folosesc alocarea static a memoriei se numesc variabile statice.

P
Sistemul de operare le aloc spaiu n segmentul de date sau n stiva sistemului, n
funcie de modul n care au fost declarate n program (globale sau locale).
I
Structurile de date statice au un mare dezavantaj, deoarece n timpul execuiei progra-
mului pot s apar urmtoarele cazuri:
spaiul alocat structurii este insuficient i este posibil ca s se depeasc acest
spaiu i s se intre n spaiul de memorie alocat altor date;

spaiul alocat structurii este mult mai mare dect este necesar i memoria intern
nu este utilizat eficient.
IC

Acest dezavantaj poate fi eliminat prin folosirea alocrii dinamice a memoriei.


Alocarea dinamic este metoda prin care unei variabile de memorie sau unei
CT

structuri de date i se atribuie spaiu de memorie sau se elibereaz spaiul de


memorie ocupat de ea n timpul execuiei programului, n funcie de necesiti.
Variabilele care folosesc alocarea dinamic a memoriei se numesc variabile dinamice.
DA

Spaiul de memorie alocat va fi n zona de adrese libere (Heap). Sistemul de operare alo-
c unei date zon de memorie n Heap sau elibereaz spaiul de memorie alocat datei, n
urma unor cereri de alocare de memorie i de eliberare de memorie din program. Meca-
nismul prin care programatorul folosete alocarea dinamic a memoriei este urmtorul:
DI

1. Se declar o variabil de memorie de tip pointer ctre tipul de dat al variabilei


dinamice.
<tip de baza> *<nume pointer>;
RA

La compilarea programului, variabilei pointer i se va aloca spaiu n segmentul de date


sau n stiva sistemului, n funcie de modul n care a fost declarat n program (global
sau local). n variabila pointer se va memora adresa variabilei dinamice.
2. n momentul n care n program trebuie folosit variabila dinamic se cere sistemului
TU

de operare s i aloce spaiu n Heap. Pentru cererea de alocare de memorie se


folosete operatorul new:
<nume pointer> = new <tip de baza>;
Sistemul de operare caut n Heap o zon de memorie liber, de dimensiunea tipului
I
ED

variabilei dinamice, i atribuie pointerului adresa acestei zone.


Informatic 107

C
3. n momentul n care n program nu mai este folosit variabila dinamic se cere
sistemului de operare s elibereze spaiul de memorie pe care i l-a alocat n Heap.
Pentru cererea de eliberare a memoriei se folosete operatorul delete:

I
delete <nume pointer>;

OG
Sistemul de operare declar liber zona de memorie care a fost alocat variabilei
dinamice, i consider c variabila pointer nu mai este iniializat cu o adres de
memorie, iar valoarea care a fost memorat n variabila dinamic se pierde.
Observaie. Operatorii new i delete sunt operatori unari i au prioritatea i

AG
asociativitatea acestui tip de operatori.

ED
Scop: exemplificarea modului n care putei folosi alocarea dinamic a memoriei.
Enunul problemei 1: Se citesc de la tastatur trei numere ntregi a, b i c care
reprezint mrimile laturilor unui triunghi. S se afieze aria triunghiului.
Se folosete alocarea dinamic a variabilelor elementare. Pentru referirea mrimilor

P
laturilor se folosesc pointerii a, b i c ctre tipul int, iar pentru referirea ariei i a semi-
perimetrului se folosesc pointerii aria i sp ctre tipul float.
I
#include<iostream.h>
#include<math.h>
void main()
{int *a,*b,*c; float *aria, *sp; //se declar pointerii (1)

a = new int; b = new int; c = new int; //se aloc memorie pentru
aria = new float; sp = new float; //variabilele dinamice (2)
IC

//se citesc de la tastatur valorile variabilelor dinamice


//folosite pentru laturile triunghiului
CT

cout<<"a= "; cin>>*a; cout<<"b= "; cin>>*b; cout<<"c= "; cin>>*c;


//se calculeaz valorile variabilelor dinamice folosite pentru
//semiperimetru i arie
*sp=(*a+*b+*c)/2.; *aria=sqrt(*sp*(*sp-*a)*(*sp-*b)*(*sp-*c));
DA

//se afieaz valoarea variabilei dinamice folosite pentru arie


cout<<"aria= "<<*aria;
//se elibereaz zona de memorie alocat variabilelor dinamice (3)
delete a; delete b; delete c; delete aria; delete sp;}
DI

Enunul problemei 2: Se citesc de la tastatur coordonatele a dou puncte din plan a


i b. S se afieze distana dintre cele dou puncte.
Se folosete alocarea dinamic a structurii de date de tip nregistrare. Pentru referi-
RA

rea coordonatelor celor dou puncte se folosesc pointerii a i b ctre tipul nregistrare
punct, iar pentru referirea distanei se folosete pointerul d ctre tipul float.
#include<iostream.h>
#include<math.h>
TU

struct punct {int x,y;};


punct *a,*b; float *d; //se declar pointerii (1)
void main()
{//se aloc memorie pentru variabilele dinamice (2)
I

a = new punct; b = new punct; d = new float;


ED
108 Implementarea structurilor de date

C
//se citesc de la tastatur valorile variabilelor dinamice
//folosite pentru coordonatele punctelor a i b
cout<<"coordonatele punctului a - x: "; cin>>a->x;

I
cout<<" - y: "; cin>>a->y;

OG
cout<<"coordonatele punctului b - x: "; cin>>b->x;
cout<<" - y: "; cin>>b->y;
//se calculeaz valoarea variabilei dinamice folosite pentru distan
*d=sqrt(pow(a->x-b->x,2)+pow(a->y-b->y,2));

AG
//se afieaz valoarea variabilei dinamice folosite pentru distan
cout<<"distanta dintre punctele a si b este "<<*d;
//se elibereaz zona de memorie alocat variabilelor dinamice (3)
delete a; delete b; delete d;}

ED
Enunul problemei 3: Se citesc de la tastatur n numere ntregi care se memoreaz ntr-un
vector. S se inverseze vectorul n el nsui i s se afieze vectorul dup inversare.
Se folosete alocarea dinamic a structurii de date de tip vector. Pentru referirea num-
rului de elemente ale vectorului se folosete pointerul n ctre tipul int, iar pentru referirea

P
variabilei prin intermediul creia se interschimb dou elemente ale vectorului se folosete
pointerul aux ctre tipul int. Pentru referirea vectorului se folosete pointerul p ctre tipul
int[*n]. Acest pointer indic o zon continu de nsizeof(int) octei, n reprezentnd
I
valoarea citit de la tastatur pentru numrul de elemente ale vectorului i care este referit
de pointerul n. Pointerii q i r ctre tipul int se folosesc pentru a parcurge zona de
memorie alocat vectorului n vederea prelucrrii elementelor lui.

#include<iostream.h>
#include<math.h>
IC

void main()
{int *p,*q,*r,*n,*aux; //se declar pointerii (1)
//se aloc memorie pentru variabilele dinamice (2)
CT

n=new int; aux=new int; cout<<"n= "; cin>>*n;


p = new int[*n];
//se citesc de la tastatur valorile pentru elementele vectorului
DA

for (q=p;q<p+*n;q++)
{cout<<"elementul= "<<q-p+1<<"= "; cin>>*q;}
//se interschimb elementele vectorului
for (q=p,r=p+*n-1;q<r;q++,r--) {*aux=*q; *q=*r; *r=*aux;}
DI

//se afieaz elementele vectorului


for (q=p;q<p+*n;q++) cout<<*q<<" ";
//se elibereaz zona de memorie alocat variabilelor dinamice (3)
delete []p; delete n; delete aux;}
RA

Scriei urmtoarele programe n care folosii alocare dinamic a memoriei:


Tem a. Citii de la tastatur temperatura, presiunea i numrul de moli ai unui
gaz i calculai volumul lui.
b. Citii de la tastatur numrtorul i numitorul a dou fracii, calculai suma i produsul
TU

celor dou fracii, simplificai rezultatele obinute i apoi afiai suma i produsul.
c. Citii de la tastatur coordonatele a dou coluri ale unui dreptunghi (colul din stnga
sus i colul din dreapta jos) i afiai dimensiunea diagonalei dreptunghiului.
I
ED
Informatic 109

C
d. Citii de la tastatur temperaturile medii zilnice din luna precedent i afiai tempe-
ratura medie a lunii, i zilele n care temperaturile au fost mai mari dect media.

I
2.5. Clasificarea structurilor de date

OG
Organizarea n structuri de date a datelor prelucrate de algoritmi simplific multe dintre
operaiile de prelucrare. Atunci cnd organizai datele ntr-o structur de date, trebuie s
identificai modul n care putei avea acces la ele i operaiile pe care le putei executa cu

AG
datele din colecie. Procesul de organizare a datelor n colecii este un proces care se
desfoar pe trei niveluri care interacioneaz ntre ele, pornind de la nivelul conceptual:
nivel conceptual
(nivelul la care se dezvolt imaginea mental a structurii de date: modul

ED
n care trebuie organizate datele i relaiile care exist ntre ele)

nivel logic
(nivelul la care se alege un model de implementare a structurii

P
conceptuale)
I
nivel fizic
(nivelul la care sunt stocate datele n memoria calculatorului i care implic
anumite caracteristici ale operaiilor de accesare i de prelucrare a datelor din

colecie, n funcie de modul n care sunt memorate datele i de algoritmii


implementai n limbaj pentru accesarea, citirea i scrierea datelor n memorie)
IC

Ai studiat structurile de date implementate la nivel fizic n limbajul C++:


tabloul de memorie structur de date omogen, liniar, intern i temporar;
CT

fiierul structur de date omogen, liniar, extern i permanent;


irul de caractere structur de date omogen, liniar, intern i temporar;
nregistrarea structur de date neomogen, intern i temporar.
Ai mai studiat i o structur de date logic lista structur de date omogen, liniar, intern
DA

i temporar i o metod de implementare la nivel logic a listei folosind vectorul.

Scop: exemplificarea modului n care identificai structura de date pe care o folosii


DI

pentru a rezolva problema.


Enunul problemei 1. O firm de transport are un parc de 10 maini cu capaciti de
transport diferite. Trebuie s se determine cte dintre aceste maini au cea mai mare
RA

capacitate de transport.
Pentru rezolvarea problemei trebuie stabilit structura de date care se va folosi:
La nivel conceptual capacitile de transport ale mainilor reprezint un ir de
numere ntregi, aranjate ntr-o ordine aleatorie, n care trebuie cutat numrul cel mai
TU

mare i de cte ori apare n ir.


20 40 50 30 20 40 50 40 30 40
La nivel logic implementarea permis de limbajul C++ a unei colecii de date omogene
I

este vectorul, fiecare numr ntreg fiind un element al structurii. Pentru rezolvarea proble-
ED
110 Implementarea structurilor de date

C
mei se vor folosi urmtorii algoritmi: algoritmul pentru parcurgerea vectorului la memo-
rarea numerelor, algoritmul pentru determinarea valorii maxime dintr-un ir de numere i
algoritmul de cutare n vector a elementelor cu o valoare precizat (valoarea maxim).

I
int a10;

OG
La nivel fizic numerele vor fi memorate ntr-o zon continu de memorie intern, fiecrui
numr alocndu-i-se acelai spaiu pentru memorare. Identificarea unui element al
structurii se face prin numrul su de ordine (indicele).
20 40 50 30 20 40 50 40 30 40

AG
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9
Dac se dorete pstrarea datelor memorate (capacitile de transport ale mainilor din
parcul auto) pentru prelucrarea lor ulterior, se vor salva ntr-un fiier text, de unde vor fi
restaurate n memoria intern ntr-un vector, la fiecare prelucrare (execuie a programului).

ED
Observaie. n structura de date folosit (vectorul), ntre elementele structurii exist o
relaie de ordine n care fiecare element are un succesor i un predecesor. Acest tip de
structur este o structur liniar.

P
a1 a2 ... ai-1 ai
I ai+1 ... an

a1 = primul element ai = element an = ultimul element


(nu are predecesor) succesorul su este ai+1 (nu are succesor)
predecesorul su este ai-1

Enunul problemei 2. Un profesor trebuie s calculeze media semestrial a fiecrui elev din
clas i s obin o list cu numele, prenumele i mediile elevilor, n ordinea descresctoare
IC

a mediilor.
Pentru rezolvarea problemei, trebuie stabilit structura de date care se va folosi:
La nivel conceptual elevii din clas reprezint un ir de entiti care sunt caracte-
CT

rizate de o list de proprieti (atribute): nume i prenume (care identific unic elevul),
cinci note i media semestrial.
Nume Prenume Nota 1 Nota 2 Nota 3 Nota 4 Nota 5 Media
DA

1 Anghel Maria 10 9 10 9 9,5



30 Vlad Mihai 7 6 8 7
La nivel logic implementarea permis de limbajul C++ a unei colecii de date omogene
DI

este vectorul, fiecare list de atribute ale unui elev fiind un element al structurii. Pentru
implementarea listei de atribute (care este format din date neomogene: numele i
prenumele sunt iruri de caractere, notele sunt numere ntregi, iar media este un numr
real) se va folosi structura de date de tip nregistrare, fiecare atribut fiind memorat ntr-un
RA

cmp. Pentru rezolvarea problemei se vor folosi urmtorii algoritmi: algoritmul pentru
parcurgerea vectorului la memorarea listei de atribute a fiecrui elev i la afiarea mediilor,
algoritmul pentru calcularea mediei aritmetice i algoritmul de sortare a elementelor
vectorului n funcie de valoarea unui atribut din lista de atribute.
TU

struct elev
{char nume[20], pren[20];
unsigned nota[5];
float media;};
I

elev clasa30;
ED
Informatic 111

C
La nivel fizic listele de atribute ale fiecrui elev vor fi memorate ntr-o zon continu de
memorie intern, fiecrei liste de atribute alocndu-i-se acelai spaiu pentru memorare.
Identificarea unei liste de atribute n cadrul structurii se face prin numrul su de ordine

I
(indicele), iar identificarea unui atribut din list se face prin numele cmpului.

OG
i n cazul acestui exemplu, dac se dorete pstrarea datelor memorate (lista de atribute
a fiecrui elev din clas), pentru prelucrarea lor ulterior, se vor salva ntr-un fiier text, de
unde vor fi restaurate n memoria intern ntr-un vector de nregistrri, la fiecare prelucrare
(execuie a programului).

AG
Clasa

clasa[0] clasa[1] ... clasa[i] ... clasa[29]

ED
nume pren nota media

P
nota[0] nota[1] nota[2] nota[3] nota[4]
I
clasa[i].nume
clasa[i].nota[2]
Observaie. n structura de date folosit pentru lista de atribute, ntre elementele structurii
exist o relaie de ordine n care fiecare element are un singur predecesor i nici unul, unul

sau mai muli succesori. Entitatea elev (corespunde unui element din vectorul clasa) are ca
predecesor entitatea clasa i ca succesori entitile: nume, pren, nota i media. Entitatea
IC

nume are un singur predecesor (entitatea elev) i nici un succesor. Entitatea nota are un
singur predecesor (entitatea elev) i cinci succesori (nota[0], nota[1], nota[2], nota[3] i
CT

nota[4]). Structurile de date de tip nregistrare pot fi ierarhizate pe unul sau mai multe
niveluri. Acest model de reprezentare a datelor se numete arbore cu rdcin, iar acest
tip de structur de date este o structur ierarhizat.
DA

a1 Nivelul 1

a11 a12 a13 Nivelul 2


DI

a111 a112 a121 a122 a123 a131 Nivelul 3

Nivelul 4
a1221 a1222
RA

ntr-o structur de date ierarhizat, datele pot fi grupate pe mai multe niveluri. Elementul
a1 se gsete pe nivelul 1. El nu are predecesor, dar are trei succesori: a11, a12 i a13.
care se gsesc pe nivelul 2. Elementul a12 are un singur predecesor (a1) i trei succesori:
TU

a121, a122 i a123. Elementele a111, a112, a121, a123 i a131 de pe nivelul 3 i elementele
a1221 i a1222 de pe nivelul 4 nu au succesori.
O matrice cu n linii i m coloane este i ea o structur de date ierarhizat pe trei niveluri:
I

pe primul nivel este matricea care are n succesori: liniile, care sunt pe nivelul 1. Fiecare
ED
112 Implementarea structurilor de date

C
linie are ca predecesor matricea i ca succesori cele m elemente de pe o linie, care se
gsesc pe nivelul 3.
Nivelul 1

I
Matricea

OG
linia 0 linia 1 linia 2 linia 3 Nivelul 2

a[0][0] a[0][1] a[3][0] a[3][1]

AG
a[1][0] a[1][1] a[2][0] a[2][1] Nivelul 3

Enunul problemei 3. O persoan dorete s viziteze apte obiective turistice care se


gsesc n apte localiti, pe care le notm cu A, B, C, E, F, G i I. ntre cele apte obiective

ED
turistice exist mai multe ci de acces. Trebuie s se gseasc un traseu, astfel nct
turistul s plece din localitatea A i s revin n localitatea A, vizitnd toate cele apte
obiective fr s treac de dou ori prin aceeai localitate. Dac exist mai multe trasee,

P
s se caute traseul cu drumul cel mai scurt.
Pentru rezolvarea problemei, trebu-
ie stabilit structura de date care se
I
va folosi. Localitile reprezint
entiti care pot fi legate sau nu prin
ci de acces. Fiecare cale de acces

este caracterizat de distana dintre


cele dou localiti. Pentru a repre-
IC

zenta la nivel conceptual aceast


structur de date vom reprezenta
n plan harta zonei turistice prin
CT

intermediul unor elemente geome-


trice, astfel: localitile se reprezint prin cercuri n interiorul crora vom scrie identificatorul
localitii, iar cile de acces prin linii drepte care unesc anumite puncte. Acest model de
reprezentare a datelor se numete graf.
DA

Observaie. n structura de date folosit pentru a reprezenta la nivel conceptual entitile


(localitile), ntre elementele structurii exist o relaie de ordine n care fiecare
element are mai muli predecesori i mai muli succesori. Acest tip de structur de
date este o reea.
DI

Din studiul de caz anterior putem folosi un nou criteriu pentru clasificarea structurilor
de date:
criteriul relaiei de ordine
RA

Liniare Ierarhizate (arborescente) Reea


Fiecare element are un ntre elemente exist o relaie de subordo- ntre elemente exist o
TU

succesor i un nare, n care fiecare element are un pre- relaie de subordonare,


predecesor, exceptnd decesor unic i poate avea unul sau mai n care fiecare element
primul element, care nu muli succesori, cu excepia primului element poate avea mai muli
are dect succesor, i (numit rdcin), care nu are predecesor, i predecesori i mai muli
ultimul element, care nu a ultimelor elemente (numite terminale), succesori.
I

are dect predecesor. care nu au succesor.


ED
Informatic 113

C
2.6. Lista liniar

I
Pe lng criteriile studiate pentru clasificarea structurilor de date, mai exist i urm-

OG
toarele criterii:
Implementarea n limbajul de programare

Structuri implicite Structuri explicite

AG
Structura creat la nivel conceptual este Structura creat la nivel conceptual nu este
implementat la nivelul limbajului de implementat la nivelul limbajului de
programare. Reprezentarea sa este programare. Reprezentarea sa se face folosind
implicit i nu mai necesit informaii structurile implicite implementate n limbaj, fiind

ED
suplimentare pentru localizarea necesare informaii suplimentare pentru
componentelor. localizarea componentelor.

Dispunerea elementelor n memorie

Structuri contigue
P Structuri dispersate
I
Elementele sunt dispuse n zone contigue Elementele sunt dispuse n zone dispersate de
de memorie, care permit localizarea uneia memorie; pentru a putea localiza elementele n
dintre ele folosind o adres de referin i structur, trebuie s se memoreze pentru fiecare
deplasarea fa de adresa de referin. element i adresa la care se gsete.

Alocarea memoriei interne


IC

Structuri statice Structuri dinamice


CT

Dimensiunea zonei alocate este fix. Dimensiunea zonei alocate nu este fix.
Alocarea ei se face n timpul compilrii, n Alocarea sau eliberarea zonelor de memorie
funcie de modul n care a fost declarat folosite de structur se face n timpul
structura, iar n timpul execuiei programului execuiei programului, n funcie de numrul
DA

nu mai poate fi modificat. de componente ale structurii.

Lista liniar este o structur de date logic, cu date omogene, n care fiecare
element are un succesor i un predecesor, exceptnd primul element, care nu
DI

are dect succesor, i ultimul element, care nu are dect predecesor.


Lista liniar, la fel ca i vectorul, din punct de vedere conceptual este o structur de
date omogen liniar. ntre cele dou structuri exist urmtoarele deosebiri:
RA

Criteriul Vectori Liste


Implementarea Sunt structuri implicite. Fiind o Sunt structuri explicite. Fiind o structur
n limbaj structur fizic, este implementat logic, trebuie aleas o metod de
TU

n limbajul de programare. Nu nece- implementare folosind structurile fizice


sit informaii suplimentare pentru lo- existente. Necesit informaii suplimentare
calizarea elementelor structurii n me- pentru localizarea elementelor structurii n
moria intern, deoarece mecanismul memoria intern, deoarece mecanismul
prin care este implementat fizic prin care este implementat fizic nu asigu-
I
ED

asigur identificarea elementelor. r identificarea elementelor.


114 Implementarea structurilor de date

C
Criteriul Vectori Liste
Dispunerea Sunt structuri contigue. Pot fi structuri dispersate. Predecesorul,
elementelor Predecesorul, elementul i elementul i succesorul nu sunt n locaii de

I
n memorie succesorul se gsesc n locaii memorie contigue. Programatorul trebuie s

OG
contigue prin mecanismul de defineasc mecanismul prin care elementele
implementare a structurii de date la structurii vor fi legate unele de altele pentru
nivel fizic. a putea fi regsite n memorie.
Alocarea Sunt structuri statice. Sunt structuri statice sau dinamice, n

AG
memoriei funcie de implementarea aleas.

Se definete lungimea listei (n) ca fiind numrul de elemente ale listei. Lista vid este lis-
ta care are lungimea 0 (nu are nici un element). Elementele listei se mai numesc i noduri.

ED
Scop: exemplificarea modului n care identificai o aplicaie n care folosii ca structur de
date lista liniar.

P
Enunurile problemelor pentru care trebuie aleas structura de date i conceput algo-
ritmul pentru prelucrarea lor:
1. ntr-o bibliotec exist o colecie de cri organizate n ordinea alfabetic a autorilor. Un
I
cititor poate mprumuta o carte (se extrage o carte din colecie) sau poate napoia o carte
(se insereaz o carte n colecie). Toate aceste operaii trebuie executate astfel nct s se
pstreze organizarea n ordine alfabetic a autorilor.

2. La o benzinrie s-a format o coad de ateptare. Mainile sunt servite n ordinea


venirii: prima main sosit este servit, iar ultima main venit se aaz la sfritul
IC

cozii. Toate aceste operaii trebuie executate astfel nct s se pstreze ordinea n
care au sosit mainile i s-au aezat la coad.
3. ntr-o stiv de cri, volumele sunt aezate n ordinea alfabetic a titlurilor. Trebuie
CT

extras o carte din stiv fr a deranja modul n care sunt ordonate crile n stiv.
Toate aceste probleme au n comun urmtoarele caracteristici:
Elementele coleciei sunt omogene (nregistrri cu aceeai structur).
Conceptual sunt structuri liniare n care fiecare element are un succesor i un pre-
DA

decesor, cu excepia primului i a ultimului element, care au numai succesor, respec-


tiv numai predecesor.
Structurile de date se modific folosind aceiai algoritmi de prelucrare: se insereaz
i se extrag elemente, pstrndu-se o anumit ordine de aranjare a elementelor.
DI

Dac s-ar alege soluia de a grupa aceste elemente ntr-o structur de date de tip vector,
algoritmii de prelucrare (de actualizare a vectorilor) vor necesita multe deplasri de elemente
care consum timp de prelucrare. Caracteristicile operaiilor de prelucrare a vectorilor sunt:
RA

Vectorul este o structur de date care are lungimea fizic fix, iar implementarea lui
la nivel fizic este un proces prin care se face conversia locaiei conceptuale a unui
element, n locaia real, din memoria intern.
Orice operaie de adugare sau extragere a unui element din colecie modific lungi-
TU

mea logic a vectorului.


Pentru a insera un element n colecie, trebuie deplasate toate elementele spre
dreapta, ncepnd cu poziia inserrii.
Pentru a extrage un element din colecie, trebuie deplasate toate elementele spre
I

stnga, de la sfrit, pn n poziia din care se extrage.


ED
Informatic 115

C
n cazul structurilor liniare care trebuie s-i pstreze n timpul exploatrii ordonarea
dup un anumit criteriu, mecanismul vectorilor este greoi. n aceste cazuri, se poate
alege ca soluie de implementare a structurii de date lista liniar ce degreveaz programa-

I
torul de ordonarea dup indice a structurii, impus de vectori.

OG
Implementarea structurilor de date cu ajutorul listelor are urmtoarele avantaje:
alocarea dinamic a memoriei care gestioneaz memoria mult mai eficient;
algoritmii de prelucrare care sunt mult mai eficieni (se execut mult mai
puine operaii pentru inserarea i tergerea unui element).

AG
n funcie de modul n care se aloc memoria intern, se pot folosi metodele:
Metode de implementare a listelor

ED
static dinamic

folosind vectori folosind pointeri

P
n funcie de modul n care sunt aranjate elementele n list, se pot folosi metodele:
Metode de implementare a listelor
I
secvenial nlnuit

numai static static dinamic


IC

Metoda de implementare Avantajul alocrii dinamice a Avantajul algoritmilor


memoriei de prelucrare
CT

static secvenial nu nu
static nlnuit nu da
dinamic nlnuit da da
DA

Implementarea static secvenial nu aduce niciunul dintre avantajele listelor, fiind o


implementare n care lista este prelucrat la fel ca un vector. n implementarea nlnuit
nodurile listei nu mai sunt stocate succesiv n memorie. Aceast implementare se poate
face att static, ct i dinamic, ntre cele dou implementri existnd urmtoarele diferene:
DI

n implementarea static, nodurile listei ocup un bloc contiguu de locaii de me-


morie (zona de memorie alocat vectorului);
n implementarea dinamic, nodurile listei ocup locaii dispersate din memorie
(a cror adres poate fi pstrat cu ajutorul pointerilor).
RA

n clasa a X-a ai nvat modul n care putei implementa static listele liniare. Algoritmii
pentru prelucrarea unei liste nlnuite sunt aceiai, att n cazul implementrii statice,
ct i n cazul implementrii dinamice.
TU

2.6.1. Implementarea dinamic a listelor n limbajul C++


Exemplu O list este format din 5 cuvinte (noduri), fiecare cuvnt avnd maxim 4
caractere. Nodurile listei se exploateaz n ordine alfabetic:
I
ED

Lista = {"alfa", "beta", "gama", "teta", "zeta"}


116 Implementarea structurilor de date

C
Memoria intern
5 locaii de memorie dispersate
identificate prin adresele adr1, adr2, adr3, adr4, adr5

I
OG
"beta" "gama" "alfa"
nodul 2 nodul 3 nodul 1 (prim)
la adresa adr2 "zeta" la adresa adr3 "teta" la adresa adr1
nodul 5 nodul 4

AG
(ultim) la adresa adr4

Deoarece nodurile listei nu sunt aranjate succesiv, ci aleatoriu, n memorie, trebuie imple-
mentat un mecanism prin care s se precizeze ordinea real a acestor noduri (ordinea n
care se nlnuie n list). Aceasta nseamn c:

ED
trebuie cunoscut locul din care ncepe lista (lanul de noduri), adic poziia primului
nod din list (nodul prim) n exemplu, nodul "alfa";
trebuie cunoscut locul n care se termin lista, adic poziia ultimului nod din list
(nodul ultim) n exemplu, nodul "zeta";

P
pentru fiecare nod din list, cu excepia ultimului nod, trebuie cunoscut nodul care
este succesorul lui de exemplu, pentru nodul "gama" trebuie cunoscut c succe-
I
sorul su este nodul "teta".
Metoda folosit pentru implementare este ca
un nod al listei s conin dou tipuri de infor- Informaia Informaia pentru
maii: informaia propriu-zis i informaia propriu-zis legtur

de legtur adresa prin care se identific nodul care urmeaz n structur. Informaia
IC

de legtur memorat n ultimul nod (n cmpul de adres) este constanta NULL (care
semnific faptul c ultimul nod nu se leag de nimic).
Memoria intern
CT

adresele nodurilor adr1, adr2, adr3, adr4, adr5


"beta" adr3 "gama" adr4 "alfa" adr2
adr2 adr3 adr1
DA

"zeta" NULL "teta" adr5


DI

adr5 adr4

nlnuirea nodurilor listei n implementarea dinamic


RA

Lista liniar nlnuit este o structur logic de date, parcurs liniar, care are dou
extremiti (nceput i sfrit), n care fiecrui element i se asociaz o informaie
suplimentar referitoare la locul elementului urmtor, din punct de vedere logic.
Un nod al listei va fi de tipul nregistrare ce conine un cmp cu informaia pentru leg-
TU

tur care este adresa succesorului exprimat printr-un pointer.


struct nod
{<tip 1> <info 11>, <info 12>, ..., <info 1n>;
<tip 2> <info 21>, <info 22>, ..., <info 2n>;
I

.............................................
ED
Informatic 117

C
<tip m> <info m1>, <info m2>, ..., <info mn>;
nod *urm;};
nod *prim, *ultim, *p;

I
Cmpurile <info ij> sunt cmpurile cu informaii, iar cmpul urm este un cmp de tip

OG
pointer ctre tipul de baz nod i conine informaia de legtur (adresa urmtorului nod
din list). Acest tip de nregistrare se numete nregistrarea autoreferit. S-au declarat
variabilele de tip adres a unei nregistrri de tip nod:
*prim i *ultim pentru a memora adresa primului nod, respectiv a ultimului nod;

AG
ele v ajut s identificai extremitile listei;
*p pentru a memora adresa unui nod curent din list (este folosit pentru parcurgerea
listei).
n liste, algoritmii de inserare i eliminare a unor noduri din structur se simplific foarte mult:

ED
Inserarea unui nod const n alocarea zonei de memorie n care se scrie nodul i
legarea lui la structur (stabilirea legturii cu predecesorul i cu succesorul lui).
Eliminarea unui nod const n ruperea nodului din structur, prin legarea predece-
sorului su cu succesorul lui, i eliberarea zonei de memorie pe care a ocupat-o.

2.6.2. Clasificarea listelor


Liste liniare P
I
Liste generale Liste restrictive

Nu exist restricii pentru operaiile de Exist restricii pentru operaiile de


inserare i tergere a elementelor din list inserare i tergere a elementelor din list
IC

(se pot face n orice poziie a listei). (se pot face numai la extremiti).
CT

Stiva Coada
Operaiile de introducere i extragere Operaia de introducere a elementelor se
a elementelor se pot face numai face pe la o extremitate, iar extragerea
printr-una dintre extremiti. elementelor prin cealalt extremitate.
DA

Lista simplu nlnuit Lista dublu nlnuit Lista circular


DI

Fiecare element pstreaz Fiecare element pstreaz Este o list nlnuit n


legtura cu un singur vecin legtura cu ambii vecini care elementul ultim se
(de obicei, succesorul). (succesorul i predecesorul). leag de elementul prim.
RA

Algoritmii ce se pot folosi pentru prelucrarea listelor:


iniializarea listei se creeaz lista vid;
crearea listei se adaug repetat elemente la list, pornind de la lista vid;
inserarea unui element n list la nceput, la sfrit, n interior;
TU

tergerea unui element din list la nceput, la sfrit, n interior;


parcurgerea listei se viziteaz elementele listei pentru a obine informaii;
cutarea n list a unui element care ndeplinete anumite condiii;
sortarea unei liste;
concatenarea a dou liste;
I
ED

divizarea n dou liste.


118 Implementarea structurilor de date

C
2.6.3. Agoritmi pentru prelucrarea listelor simplu nlnuite
Lista simplu nlnuit

I
prim

OG
ultim
info urm info urm info urm info NULL

n implementarea algoritmilor urmtori se consider c informaia propiu-zis este

AG
format numai dintr-un cmp n care se memoreaz un numr ntreg:
struct nod
{int info; //informaia propriu-zis
nod *urm;}; //informaia pentru legtur

ED
nod *prim, *ultim, *p; //pointeri pentru exploatarea listei
int x; //pentru valoarea ce se atribuie cmpului cu informaii
n lista vid: att nodul prim ct i nodul ultim nu exist, i adresa lor are valoarea NULL:
prim = ultim = NULL; Starea de list vid trebuie cunoscut atunci cnd se

P
elimin noduri din list, deoarece n lista vid nu mai exist noduri care s fie eliminate.
Aceast stare se testeaz prin condiia: prim == NULL. Pentru testarea unei liste dac
I
este vid se poate implementa funcia operand este_vida() care va furniza valoarea 1
(adevrat), dac lista este vid, i valoarea 0 (fals) dac lista nu este vid.
int este vida(nod *prim)
{return prim==NULL;}

2.6.3.1. Iniializarea listei


IC

Prin acest algoritm se creeaz lista vid. n acest caz, att nodul prim ct i nodul ultim
nu exist, i li se atribuie adresa NULL.
Implementarea algoritmului. Se folosete funcia procedural init() ai crei parametri
CT

prim i ultim de tip nod se transmit prin referin, deoarece sunt parametri de ieire.
void init(nod *&prim, nod *&ultim)
{prim = ultim=NULL;}
DA

2.6.3.2. Crearea listei


Deoarece n algoritmii de prelucrare trebuie s se cunoasc adresa primului nod, este impor-
tant adugarea primului nod la lista vid. Paii algoritmului de creare a unei liste sunt:
PAS1. Se adaug primul nod la list (nodul prim).
DI

PAS2. Ct timp mai exist informaie, execut: se adaug un nod la list.


2.6.3.3. Adugarea primului nod la list
n lista cu un singur nod, adresa de legtur a nodului prim are valoarea NULL i att
RA

nodul prim ct i nodul ultim au aceeai adres. Paii executai n acest algoritm sunt:
PAS1. Se cere alocarea de memorie pentru nodul prim.
PAS2. Se scrie informaia n nodul prim.
PAS3. Adresei de legtur a nodului prim i se atribuie valoarea NULL.
TU

PAS4. Nodului ultim i se atribuie adresa nodului prim.


Implementarea algoritmului. Se folosete funcia procedural adauga_nod() ai crei para-
metri prim i ultim de tip nod se transmit prin referin, deoarece sunt parametri de ieire.
I

void adaug nod (nod *&prim, nod *&ultim)


ED

{prim = new nod; prim->info=x; prim->urm=NULL; ultim=prim;}


Informatic 119

C
2.6.3.4. Adugarea unui nod la list
Pentru adugarea unui nod p la list, n funcie de cerinele problemei, se poate folosi

I
unul dintre algoritmii urmtori:

OG
1. adugarea n faa primului nod;
2. adugarea dup ultimul nod;
3. adugarea ntr-o poziie n interiorul listei.
Adugare n faa primului nod

AG
Paii executai n acest algoritm sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
PAS3. Nodul p se leag de nodul prim.

ED
PAS4. Nodul p inserat devine nodul prim.
Adugare n faa primului nod
prim ultim

P
info urm info urm I info urm info NULL

p info urm p devine nodul prim


Implementarea algoritmului. Se folosete funcia procedural adauga_prim() al crei para-


metru prim de tip nod se transmite prin referin, deoarece este parametru de intrare-iere.
IC

void adauga prim(nod *&prim)


{nod *p=new nod; p->info=x; p->urm=prim; prim=p;}
Adugare dup ultimul nod
CT

Paii executai n acest algoritm sunt:


PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
PAS3. Nodul p este nod terminal (nu se leag de nimic adresa de legtur este NULL).
DA

PAS4. Nodul ultim se leag de nodul p adugat.


PAS5. Nodul p adugat devine nodul ultim.
Adugarea dup ultimul nod
DI

prim ultim
info urm info urm info urm info NULL
RA

p info NULL
p devine nodul ultim
TU

Implementarea algoritmului. Se folosete funcia procedural adauga_ultim() al crei para-


metru ultim de tip nod se transmite prin referin, deoarece este parametru de intrare-iere.
void adauga ultim(nod *&ultim)
{nod *p=new nod; p->info=x; p->urm=NULL; ultim->urm=p; ultim=p;}
I
ED
120 Implementarea structurilor de date

C
Adugarea n interiorul listei se poate face n dou moduri:
a. dup nodul cu adresa q;
b. nainte de nodul cu adresa q.

I
Adugarea n interiorul listei dup nodul cu adresa q

OG
Paii algoritmului sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
PAS3. Nodul p se leag de succesorul nodului q.

AG
PAS4. Nodul q se leag de nodul p adugat.
PAS5. Dac nodul q a fost ultimul nod, nodul p adugat devine nodul ultim.
Adugare dup nodul q

ED
prim q->urm ultim
info urm info urm info urm info NULL
q

P
p info urm
I
Implementarea algoritmului. Se folosete funcia procedural adauga_dupa() ai crei para-
metri sunt de tip nod: q (adresa nodului dup care se face adugarea), care se transmite prin
valoare, deoarece este parametru de intrare, i ultim (adresa ultimului nod), care se transmite

prin referin, deoarece este parametru de intrare-ieire.


void adauga dupa(nod *q, nod *&ultim)
IC

{nod *p=new nod;


p->info=x; p->urm=q->urm; q->urm=p; if (q==ultim) ultim=p;}
Adugarea n interiorul listei nainte de nodul de adres q
CT

Pentru a aduga nodul p naintea nodului q, trebuie s legm predecesorul nodului q de


nodul p. Dar, predecesorul unui nod nu este cunoscut. Adugarea unui nod n list nseam-
n, de fapt, inserarea n list a informaiei pe care o conine, ntre alte dou informaii, i
DA

anume: informaia din predecesorul nodului q trebuie s fie anterioar ei, iar informaia din

(1) Adugare naintea nodului q


prim q q->urm ultim
DI

v1 urm v2 urm v3 urm v4 NULL


RA

p v2 urm
(2)
prim q q->urm ultim
TU

v1 urm val urm v3 urm v4 NULL

p v2 urm
I
ED
Informatic 121

C
nodul q trebuie s o urmeze. Astfel, n list nu se va aduga nodul p nainte de nodul q, ci
dup el, interschimbnd apoi informaiile ntre cele dou noduri. Paii algoritmului sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.

I
PAS2. Se copiaz informaia din nodul q n nodul p.

OG
PAS3. Se scrie n nodul q informaia care trebuie adugat la list.
PAS4. Nodul p se leag de succesorul nodului q.
PAS5. Nodul q se leag de nodul p adugat.
PAS6. Dac nodul q a fost ultimul nod, nodul p adugat devine nodul ultim.

AG
Implementarea algoritmului. Se folosete funcia procedural adauga_in_fata() ai crei
parametri sunt de tip nod: q (adresa nodului naintea cruia se face adugarea), care se trans-
mite prin valoare, deoarece este parametru de intrare, i ultim (adresa ultimului nod), care se
transmite prin referin, deoarece este parametru de intrare-ieire.

ED
void adauga in fata(nod *q, nod *&ultim)
{nod *p=new nod; p->info=q->info; q->info=x; p->urm=q->urm; q->urm=p;
if (q==ultim) ultim=p;}
2.6.3.5. Parcurgerea listei

P
Prin acest algoritm se viziteaz fiecare nod al listei, pornind de la primul nod, pn la
ultimul nod, n ordinea de nlnuire a nodurilor furnizat de adresa urm din nodul
I
vizitat. Lista se parcurge pentru a prelucra informaia stocat n noduri.
Implementarea algoritmului. Se folosete funcia procedural parcurge() al crei parametru
prim de tip nod se transmite prin valoare, deoarece este parametru de intrare.
void parcuge(nod *prim)

{for (nod *p=prim; p!=NULL; p=p->urm)


//se prelucreeaz p->info;}
IC

Att vectorul, ct i lista sunt structuri liniare, iar algoritmii de parcurgere sunt asemntori:
Vectorul Lista
CT

Variabila folosit i de tip int pentru indicele elementului p de tip pointer ctre tipul nod al listei
pentru parcurgere curent din vector pentru adresa elementului curent din list
Iniializarea i=0 indicele primului element din p=prim adresa primului nod din list
variabilei vector
DA

Trecerea la ele- i=i+1 se incrementeaz indicele p=p->urm pointerului i se atribuie


mentul urmtor adresa nodului urmtor
Condiia de i==n indicele i are prima valoare mai p==NULL adresa memorat n pointerul
terminare mare dect cea a ultimului element p este constanta NULL
DI

2.6.3.6. Cutarea unui nod n list


ntr-o list se poate cuta:
1. Nodul care ndeplinete o anumit condiie, pe care o notm cu conditie i care
RA

este exprimat printr-o expresie logic ce conine cel puin un cmp cu informaie din
nod; valoarea condiiei este dependent de informaia stocat n nod. Algoritmul
este: se parcurge lista ncepnd de la primul nod, n ordinea de nlnuire a nodurilor,
pn se gsete nodul care ndeplinete condiia sau pn s-a ajuns la sfritul listei.
TU

2. Nodul care se gsete ntr-o anumit poziie n list pe care o notm cu poz.
Algoritmul este: se parcurge lista ncepnd de la primul nod, n ordinea de nlnuire
a nodurilor, pn cnd s-au parcurs poz noduri sau pn s-a ajuns la sfritull listei
Implementarea algoritmului. Se folosete o funcie operand cu tipul pointer ctre tipul nod. n
I
ED

ambele variante:
122 Implementarea structurilor de date

C
parametrul funciei este prim de tip nod i se transmite prin valoare, deoarece este
parametru de intrare;
variabila local p de tip pointer ctre nod se folosete pentru parcurgerea listei este

I
iniializat cu adresa primului nod;

OG
adresa nodului gsit se memoreaz n pointerul p care va fi returnat de funcie.
Varianta 1
nod *caut(nod *prim)
{for (nod *p=prim; p!=NULL && !conditie; p=p->urm); return p;}

AG
Varianta 2 Variabila local nr de tip int se folosete pentru a numra poziiile parcurse
este iniializat cu valoarea 1.
nod *caut(nod *prim, int poz)
{nod *p=prim; int nr=1;

ED
for (;p!=NULL && nr<poz; p=p->urm,nr++); return p;}

2.6.3.7. Eliminarea unui nod din list


Dup eliminarea nodului din poziia p din list se va elibera zona de memorie ocupat de

P
nod. Eliminarea unui nod se face numai dac lista nu este vid. Pentru eliminarea unui
nod din list, n funcie de situaie, se poate folosi unul dintre algoritmii urmtori:
1. eliminarea primului nod;
I
2. eliminarea ultimului nod;
3. eliminarea unui nod din interiorul listei.
Eliminarea primului nod

Paii executai n acest algoritm sunt:


PAS1. Se salveaz adresa nodului prim n pointerul q.
IC

PAS2. Succesorul nodului prim devine nodul prim.


PAS3. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul q.
CT

Eliminarea primului nod


prim ultim
info urm info urm info urm info NULL
DA

succesorul nodului prim devine nodul prim

Implementarea algoritmului. Se folosete funcia procedural elimina_prim() al crei para-


DI

metru prim de tip nod se transmite prin referin, deoarece este parametru de intrare-ieire.
void elimina prim(nod *&prim)
{nod q=prim; prim=prim->urm; delete q;}
RA

Eliminarea ultimului nod


Paii executai n acest algoritm sunt:
PAS1. Se salveaz adresa nodului ultim n pointerul q.
PAS2. Se caut predecesorul ultimului nod, prin parcurgerea listei ncepnd de la primul
TU

nod, pn la predecesorul nodului terminal (nodul care nu se leag de nimic


adresa de legtur are valoarea NULL).
PAS3. Predecesorul nodului ultim devine nod terminal (adresa de legtur este NULL).
PAS4. Predecesorul nodului ultim devine nodul ultim.
I
ED

PAS5. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul q.


Informatic 123

C
Eliminarea ultimului nod
prim ultim

I
OG
info urm info urm info NULL info NULL

predecesorul nodului ultim devine nodul ultim

Implementarea algoritmului. Se folosete funcia procedural elimina_ultim() al crei para-

AG
metru ultim de tip nod se transmite prin referin, deoarece este parametru de intrare-ieire.
void elimina ultim(nod *prim,nod *&ultim)
{nod *p,*q=ultim;
for (p=prim; p->urm->urm!=NULL; p=p->urm);

ED
p->urm=NULL; ultim=p; delete q;}
Eliminarea unui nod din interiorul listei
Pentru a elimina nodul p aflat n interiorul listei, trebuie s legm predecesorul nodului p

P
de succesorul lui. Dar, predecesorul unui nod nu este cunoscut. Eliminarea unui nod din
list nseamn de fapt eliminarea din list a informaiei pe care o conine. Astfel, din list
nu se va elimina nodul p, ci succesorul su (care este cunoscut), dup ce informaia din
I
el a fost copiat n nodul p. Paii executai n acest algoritm sunt:
PAS1. Se salveaz adresa succesorului nodului p n pointerul q.
PAS2. Se copiaz n nodul p toat informaia din succesorul lui (informaia propriu-zis
i informaia de legtur).

PAS3. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul q.


PAS4. Dac succesorul nodului p era nodul ultim, atunci nodul p devine nodul ultim.
IC

Implementarea algoritmului. Se folosete funcia procedural elimina() ai crei para-


metri sunt de tip nod: p (adresa nodului care se elimin), care se transmite prin valoare,
CT

deoarece este parametru de intrare, i ultim, care se transmite prin referin, deoarece
este parametru de intrare-ieire.
void elimina(nod *p,nod *&ultim)
{nod *q=p->urm;
DA

p->info=p->urm->info; p->urm=p->urm->urm; delete q;


if (p->urm==NULL) ultim=p;}

2.6.3.8. Eliberarea spaiului de memorie ocupat de list


DI

Dac n cadrul unei aplicaii care prelucreaz mai multe liste, nu mai este necesar una dintre
ele, se va elibera ntregul spaiu ocupat de list. Prin acest algoritm se viziteaz fiecare nod
al listei, pornind de la primul nod, pn la ultimul nod, n ordinea de nlnuire a nodurilor
furnizat de adresa urm din nodul vizitat, i se elibereaz zona de memorie ocupat de
RA

fiecare nod. Paii executai n acest algoritm sunt:


PAS1. Se iniializeaz pointerul p cu adresa primului nod din list prim (p prim).
PAS2. Ct timp nu s-a parcurs toat lista (pNULL) execut:
PAS3. Se salveaz adresa nodului p n pointerul q.
TU

PAS4. Se trece la succesorul nodului p (p p->urm).


PAS5. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul q.
Se revine la Pasul 2.
PAS6. Primul nod nu mai are adres alocat (prim NULL).
I
ED
124 Implementarea structurilor de date

C
Implementarea algoritmului. Se folosete funcia procedural eliberare() al crei parame-
tru este prim de tip nod. Fiind parametru de intrare-ieire se transmite prin referin
void eliberare(nod *&prim)

I
{nod *p=prim,*q;

OG
while(p!=NULL) {q=p; p=p->urm; delete q;}
prim=NULL;}

2.6.3.9. Liste ordonate


n funcie de cerinele aplicaiei listele generale pot fi clasificate astfel:

AG
Liste generale

Ordonate Neordonate

ED
Nodurile listei sunt ordonate pe baza valorii Nu exist o ordine a nodurilor n list.
unui cmp cu informaie numit cmp cheie. Operaiile de adugare de noi noduri i de
Operaiile de adugare de noi noduri i de modificare a valorii cmpurilor cu infor-
modificare a valorii cmpului cheie trebuie s maii se fac fr restricii. Adugarea se

P
se fac astfel nct s se pstreze ordonarea. face de obicei pe la o extremitate a listei.

n cazul listelor ordonate, dac informaia din nodul listei este o dat elementar, cheia
I
de ordonare va fi data elementar. Dac informaia din nodul listei este o nregistrare,
cheia de ordonare va fi unul dintre cmpurile nregistrrii. Pentru prelucrarea listelor
ordonate putei folosi:
algoritmul de sortare prin inserie;

algoritmul de interclasare a dou liste ordonate.


IC

Algoritmul de sortare prin inserie


Acest algoritm se folosete pentru ntreinerea unei liste ordonate. Se pornete de la lista care
CT

conine un singur nod (considerat o list ordonat) i orice adugare a unui nod la list se face
ntr-o poziie prin care se pstreaz ordonarea n list. n implementarea algoritmului s-a folosit
o list pentru care cmpul cheie este de tip numeric ntreg, iar ordonarea este cresctoare dup
valoarea cmpului cheie. Deoarece n acest algoritm nu este necesar informaia despre
DA

adresa ultimului nod, din subprograme au fost eliminate prelucrrile care se refer la acesta.
Numerele care trebuie memorate n nodurile listei se citesc de la tastatur pn se citete
valoarea 0 (are semnificaia c nu mai exist informaie de adugat).
Varianta 1 Se pornete de la lista care conine primul nod cu informaie. Paii execu-
DI

tai n acest algoritm sunt:


PAS1. Se adaug primul nod cu informaie la list.
PAS2. Ct timp mai exist informaie de adugat execut
PAS3. Se caut nodul naintea cruia trebuie adugat noul nod.
RA

PAS4. Dac s-a ajuns la sfritul listei, atunci se adaug noul nod ca ultimul nod din
list; altfel, se adaug noul nod n faa nodului gsit. Se revine la Pasul 2.
Implementarea algoritmului.
TU

#include<iostream.h>
struct nod {int info;
nod *urm;};
int n;
void adauga nod(nod *&prim)
I
ED

{prim=new nod; prim->info=n; prim->urm=NULL;}


Informatic 125

C
void adauga_in_fata(nod *q)
{nod *p=new nod; p->urm=q->urm; p->info=q->info; q->info=n; q->urm=p;}
void adauga_ultim(nod *q)

I
{nod *p=new nod; p->info=n; q->urm=p; p->urm=NULL;}

OG
nod * cauta(nod *prim)
{nod *q=prim;
while(q->info<n && q->urm!=NULL) q=q->urm;
return q;}
void afisare(nod *prim)

AG
{for (nod *p=prim; p!=NULL; p=p->urm) cout<<p->info<<" ";}
void main()
{nod *prim,*q;
cout<<"numar "; cin>>n;
adauga_nod(prim); //Se adaug primul nod

ED
cout<<"numar "; cin>>n;
while(n!=0) //Ct timp mai exist informaie de adugat
{q=cauta(prim);
//Se caut nodul q naintea cruia trebuie adugat nodul p

P
if (q->info<n) //Dac s-a ajuns la sfritul listei
adauga_ultim(q); //nodul p se adaug ca ultim nod
else adauga_in_fata(q); //nodul p se adaug n faa nodului q
I
cout<<"numar "; cin>>n;}
afisare(prim);} //Se afieaz informaiile din list
Varianta 2 Se pornete de la lista care conine un nod santinel (un nod care

marcheaz sfritul listei). Acest nod conine n cmpul cheie o informaie care are o
valoare care face ca el s fie ntotdeauna ultimul nod din list (de exemplu, n cazul unei
IC

liste ordonate cresctor, n care cmpul folosit pentru ordonare este de tip int, se adaug
un nod care are n acest cmp cea mai mare valoare pentru tipul int MAXINT). Cnd se
va afia informaia din list, ultimul nod din list nu se mai afieaz. Paii executai n
CT

acest algoritm sunt:


PAS1. Se adaug nodul santinel la list.
PAS2. Ct timp exist informaie de adugat execut
PAS3. Dac informaia care se adaug trebuie s fie la nceputul listei, atunci se
DA

adaug noul nod ca primul nod din list i se revine la Pasul 2; altfel, se
trece la pasul urmtor.
PAS4. Se caut nodul naintea cruia trebuie adugat noul nod.
PAS5. Se adaug noul nod n faa nodului gsit. Se revine la Pasul 2.
DI

Implementarea algoritmului.
#include<iostream.h>
#include<values.h>
RA

struct nod {int info;


nod *urm;};
int n;
void adauga_santinela(nod *&prim)
{prim=new nod; prim->info=MAXINT; prim->urm=NULL;}
TU

void adauga_prim(nod *&prim)


{nod *p=new nod; p->info=n; p->urm=prim; prim=p;}
void adauga_in_fata(nod *q)
{nod *p=new nod;
I

p->urm=q->urm; p->info=q->info; q->info=n; q->urm=p;}


ED
126 Implementarea structurilor de date

C
nod *cauta(nod *prim)
{ nod *p=prim;
for (;p->info<n;p=p->urm); return p;}

I
void afisare(nod *prim) //Nu se afieaz informaia din ultimul nod

OG
{for (nod *p=prim; p->urm!=NULL; p=p->urm) cout<<p->info<<" ";}
void main()
{ nod *prim,*q;
adauga_santinela(prim); //Se adaug nodul santinel
cout<<"numar "; cin>>n;

AG
while(n!=0) //Ct timp mai exist informaie de adugat
{if (n<prim->info) /*Dac informaia trebuie s fie la
nceputul listei */
adauga_prim(prim); //nodul p se adaug ca prim nod
else {q=cauta(prim);

ED
//Se caut nodul q naintea cruia trebuie adugat nodul p
adauga_in_fata(q);} //nodul p se adaug n faa nodului q
cout<<"numar "; cin>>n;}
afisare(prim);}

Algoritmul de interclasare a dou liste ordonate


P
Acest algoritm folosete acelai principiu ca i algoritmul de interclasare a doi vectori
I
ordonai. Cele dou liste sunt ordonate dup acelai cmp cheie i criteriu de ordonare i
se obine o a treia list care conine informaia din primele dou liste ordonat dup
acelai criteriu, folosind acelai cmp cheie. Paii executai n acest algoritm sunt:

PAS1. Se creeaz Lista 1 i Lista 2 ordonate dup acelai criteriu i dup acelai cmp cheie.
PAS2. Se adaug primul nod la Lista 3 astfel: dac n conformitate cu criteriul de ordonare
IC

folosit trebuie adugat informaia din primul nod al Listei 1, atunci se adaug
informaia din nodul prim al Listei 1 i n Lista 1 se trece la succesorul nodului
prim, iar n Lista 2 la nodul prim; altfel, se adaug informaia din nodul prim al
CT

Listei 2 i n Lista 2 se trece la succesorul nodului prim, iar n Lista 1 la nodul prim.
PAS3. Ct timp nu s-a ajuns la sfritul Listei 1 sau al Listei 2, execut:
PAS4. Se adaug la Lista 3 un nod dup ultimul nod astfel: dac n conformitate cu
criteriul de ordonare folosit trebuie adugat informaia din nodul curent al Listei
DA

1, atunci se adaug informaia din acest nod i n Lista 1 se trece la succesorul


nodului curent; altfel, se adaug informaia din nodul curent al Listei 2 i n Lista
2 se trece la succesorul nodului curent. Se revine la Pasul 3.
PAS5. Dac s-a ajuns la sfritul Listei 1, atunci la Lista 3 se adaug dup ultimul nod
DI

nodurile rmase n Lista 2; altfel, la Lista 3 se adaug dup ultimul nod nodurile
rmase n Lista 1.
Implementarea algoritmului. n implementarea algoritmului s-au folosit liste pentru care
RA

cmpul cheie este de tip numeric ntreg, iar ordonarea este cresctoare dup valoarea
cmpului cheie. Numerele care trebuie memorate n nodurile listelor se citesc de la tastatur n
variabila n pn se citete valoarea 0 (are semnificaia c nu mai exist informaie de adugat).
Din subprogramele n care nu este necesar informaia despre adresa ultimului nod au fost
TU

eliminate prelucrrile care se refer la acesta. Cele trei liste se identific prin adresa primului
nod (prim1, prim2 i respectiv prim3). Deoarece n acest algoritm nu este necesar
informaia despre adresa ultimului nod, din subprograme au fost eliminate prelucrrile care se
refer la acesta. Pentru parcurgerea celor dou liste se folosesc pointerii q i respectiv r, iar
I

pentru lista care se creeaz prin interclasare pointerul p.


ED
Informatic 127

C
#include<iostream.h>
struct nod {int info;
nod *urm;};

I
int n;

OG
void adauga_nod(nod *&prim)
{prim=new nod; prim->info=n; prim->urm=NULL;}
void adauga_in_fata(nod *q)
{nod *p=new nod;
p->urm=q->urm; p->info=q->info; q->info=n; q->urm=p;}

AG
void adauga_ultim(nod *q)
{nod *p=new nod; p->info=n; q->urm=p; p->urm=NULL;}
nod *cauta(nod *prim)
{nod *p=prim;
while(p->info<n && p->urm!=NULL) p=p->urm;

ED
return p;}
void creare(nod *&prim) //Se creeaz o list ordonat
{nod *q;
cout<<"numar "; cin>>n; adauga_nod(prim);

P
cout<<"numar "; cin>>n;
while(n!=0)
{q=cauta(prim);
I
if (q->info<n) adauga_ultim(q); else adauga_in_fata(q);
cout<<"numar "; cin>>n;}}
void afisare(nod *prim)
{nod *p=prim;

while(p!=NULL) {cout<<p->info<<" "; p=p->urm;}}


void main()
IC

{nod *prim1,*prim2,*prim3,*q,*r,*p;
creare(prim1); creare(prim2);
if (prim2->info>prim1->info)
CT

{n=prim1->info; q=prim1->urm; r=prim2;}


else {n=prim2->info; r=prim2->urm; q=prim1;}
adauga_nod(prim3); p=prim3;
while(q!=0 && r!=0)
DA

{if (r->info>q->info) {n=q->info; q=q->urm;}


else {n=r->info; r=r->urm;}
adauga_ultim(p); p=p->urm;}
if (q!=0)
while (q!=0) {n=q->info; adauga_ultim(p); p=p->urm; q=q->urm;}
DI

else
while (r!=0) {n=r->info; adauga ultim(p); p=p->urm; r=r->urm;}
afisare(prim3);} //Se afieaz informaiile din lista interclasat
RA

2.6.3.10. Prelucrarea listelor simplu nlnuite


Rezolvarea problemelor n care organizai datele sub form de liste presupune folosirea
algoritmilor prezentai, astfel:
TU

1. Se creeaz lista prin folosirea urmtorilor algoritmi:


Se adaug primul nod la lista vid (algoritmul pentru adugarea la list a primu-
lui nod).
Se adaug cte un nod la list. Poziia n care se adaug nodul depinde de cerin-
I

ele problemei. Dac lista nu este ordonat, adugarea se poate face la sfritul
ED
128 Implementarea structurilor de date

C
sau la nceputul listei (algoritmul pentru adugare la nceputul sau la sfritul
listei). Dac lista este ordonat, se parcurge mai nti lista pentru a gsi poziia de
inserare (algoritmul pentru cutarea unui nod n list) dup care se insereaz

I
noul nod n poziia gsit (algoritmul pentru adugare n interiorul listei).

OG
2. Se ntreine lista prin folosirea urmtorilor algoritmi:
Se adaug noi noduri la list. Ca i la crearea listei, n funcie de cerinele proble-
mei se va folosi unul dintre algoritmii de adugare.
Se elimin noduri din list. Mai nti se parcurge lista pentru a gsi nodul care se

AG
elimin (algoritmul pentru cutarea unui nod n list) dup care se elimin
nodul din poziia gsit folosind unul dintre algoritmii pentru eliminare n
funcie de poziia n care a fost gsit nodul.
Se modific informaia dintr-un nod al listei. Mai nti se parcurge lista pentru a gsi

ED
nodul n care se va modifica informaia (algoritmul pentru cutarea unui nod n
list). Dac lista nu este ordonat sau dac informaia care se modific nu face
parte dintr-un cmp cheie dintr-o list ordonat, se modific valoarea cmpului
respectiv. Dac lista este ordonat i, prin modificarea valorii cmpului, se poate

P
distruge aceast ordonare, se modific valoarea cmpului, se salveaz informaia
din nodul listei ntr-o variabil intermediar, se elimin din vechea poziie (algoritmul
pentru eliminarea unui nod din list), se parcurge lista pentru a gsi noua poziie
I
(algoritmul pentru cutarea unui nod n list) i se insereaz nodul n poziia
gsit (algoritmul pentru adugarea unui nod la list).
3. Se obin informaii din list. Se parcurge lista (algoritmul de parcurgere a listei)

i se viziteaz fiecare nod al listei pentru a extrage din el informaiile necesare.


IC

Scop: exemplificarea modului n care, pentru rezolvarea problemei, folosii algoritmii de


prelucrare a listelor simplu nlnuite i implementarea lor cu ajutorul subprogramelor.
CT

Enunul problemei 1. Se citete dintr-un fiier text un ir de numere separate prin spaiu
cu care se creeaz o list simplu nlnuit n ordinea n care sunt citite numerele din fiier.
S se verifice dac lista conine numai numere distincte i apoi s se adauge dup fiecare
DA

numr impar din list valoarea 100 i s se afieze numerele din list. Pentru testarea
programului se vor folosi dou seturi de numere: {2, 5, 10, 3, 8} i {2, 5, 10, 5, 8, 7}.
Nodurile listei nu sunt ordonate conform unui criteriu. Numerele se vor citi din fiier i se vor
scrie n list prin adugare dup ultimul nod. Problema se descompune n urmtoarele
DI

subprobleme, iar algoritmul de rezolvare a unei subprobleme este implementat cu ajutorul


unui subprogram:
P1 Se citete primul numr din fiier i se adaug primul nod la list (nodul prim)
RA

subprogramul adauga nod().


P2 Ct timp mai exist numere n fiier execut: se citete un numr din fiier i se
adaug un nod cu numrul respectiv dup ultimul nod din list subprogramul
adauga ultim().
TU

P3 Se verific dac numerele din list sunt distincte, astfel: se parcurge lista de la primul
nod pn la penultimul nod i se verific dac numrul din nodul curent mai exist n
nodurile care urmeaz dup el pn la sfritul listei subprogramul distincte().
P4 Se parcurge lista de la primul nod pn la sfritul ei i dac numrul din nod este impar
I

se adaug dup el un nod care conine valoarea 100 subprogramul prelucrare().


ED
Informatic 129

C
P5 Se parcurge lista de la primul nod pn la sfritul ei i se afieaz informaia din
fiecare nod subprogramul afisare().
#include<fstream.h>

I
struct nod {int info;

OG
nod *urm;};
fstream f("lista1.txt",ios::in);
int n;
void adauga nod(nod *&prim, nod *&ultim)
{prim=new nod; prim->info=n; prim->urm=NULL; ultim=prim;}

AG
void adauga ultim(nod *&ultim)
{nod *p=new nod; p->info=n; p->urm=NULL; ultim->urm=p; ultim=p;}
void adauga_dupa(nod *&q, nod *&ultim)
{nod *p=new nod; p->info=100; p->urm=q->urm; q->urm=p;

ED
if (q==ultim) ultim=p;}
int distincte(nod *prim)
{for (nod *p=prim; p->urm!=NULL; p=p->urm)
for (nod *q=p->urm; q!=NULL; q=q->urm)
if (p->info==q->info) return 0;

P
return 1;}
void prelucrare(nod *prim, nod *&ultim)
{for (nod *p =prim; p!=NULL; p=p->urm)
I
if (p->info%2==1) adauga dupa (p,ultim);}
void afisare(nod *prim)
{for (nod *p=prim; p!=NULL; p=p->urm) cout<<p->info<<" "; cout<<endl;}

void main()
{nod *prim, *ultim; f>>n adauga_nod(prim,ultim);
IC

while (f>>n) adauga_ultim(ultim); f.close();


if (distincte(prim)) cout<<"Elementele sunt distincte"<<endl;
else cout<<"elementele nu sunt distincte"<<endl;
prelucrare(prim,ultim); afisare(prim);}
CT

Enunul problemei 2. Se citete dintr-un fiier text un numr cu maxim 20 de cifre. S se


verifice dac numrul este palindrom. Pentru testarea programului se vor folosi dou
numere: 1234321 i 12345.
DA

Se vor crea dou liste: una cu cifrele numrului citite din fiier, prin adugare dup ultimul
nod, iar a doua, cu cifrele memorate n nodurile primei liste prin adugare n faa primului nod
i se vor compara cele dou liste. Din fiier se va citi fiecare cifr a numrului ntr-o variabil
de tip char i se va obine cifra scznd din codul ASCII al caracterului citit codul ASCII al
DI

cifrei 0. Cele dou liste se identific prin adresa primului nod (prim1 i respectiv prim2) i prin
adresa ultimului nod (ultim1 i respectiv ultim2). Problema se descompune n urmtoarele
subprobleme, iar algoritmul de rezolvare a unei subprobleme este implementat cu ajutorul
RA

unui subprogram
P1 Se citete primul numr din fiier i se adaug primul nod la Lista 1 (nodul prim1)
subprogramul adauga nod().
P2 Ct timp mai exist caractere n fiier, execut: se citete un caracter din fiier, se
TU

convertete n cifr i se adaug un nod cu cifra respectiv dup ultimul nod din Lista
1 subprogramul adauga ultim().
P3 Se adaug primul nod la Lista 2 (nodul prim2) care va conine informaia din primul
nod al Listei 1 (prim1) subprogramul adauga nod().
I
ED
130 Implementarea structurilor de date

C
P4 Se parcurge Lista 1 de la succesorul primului nod pn la sfritul ei i se adaug un nod
cu cifra respectiv naintea primului nod din Lista 2 subprogramul adauga prim().
P5 Se parcurg simultan ambele liste de la primul nod pn la sfrit i se verific dac

I
sunt egale cifrele memorate n nodul curent din cele dou liste subprogramul

OG
palindrom().
#include<fstream.h>
struct nod {int info;
nod *urm;};

AG
fstream f("lista2.txt",ios::in);
int n;
void adauga nod(nod *&prim, nod *&ultim)
{prim=new nod; prim->info=n; prim->urm=NULL; ultim=prim;}
void adauga ultim(nod *&ultim)

ED
{nod *p=new nod; p->info=n; p->urm=NULL; ultim->urm=p; ultim=p;}
void adauga_prim(nod *&prim)
{nod *p=new nod; p->info=n; p->urm=prim; prim=p;}
int palindrom(nod *prim1, nod *prim2)

P
{nod *p,*q;
for (p=prim1,q=prim2; p->urm!=NULL; p=p->urm,q=q->urm)
if (p->info!=q->info) return 0;
I
return 1;}
void main()
{char c; nod *prim1,*ultim1,*prim2,*ultim2,*p;
f>>c; n=c-'0'; adauga_nod(prim1,ultim1);

while (f>>c) {n=c-'0'; adauga_ultim(ultim1);} f.close();


n=prim1->info; adauga_nod(prim2,ultim2);
IC

for (p=prim1->urm; p!=NULL; p=p->urm)


{n=p->info; adauga_prim(prim2);}
if (palindrom(prim1,prim2)) cout<<"Este palindrom";
CT

else cout<<"Nu este palindrom";}


Enunul problemei 3. Se citete dintr-un fiier text un ir de numere separate prin spaiu
cu care se creeaz o list simplu nlnuit n ordinea n care sunt citite numerele din fiier.
Se mai citete de la tastatur un numr x. S se caute i s se tearg din list nodul care
DA

conine acest numr. Pentru testarea programului se va folosi irul de numere: {2, 5, 10, 3,
8}, iar pentru x patru valori: 2, 5, 8 i 7.
Nodurile listei nu sunt ordonate conform unui criteriu. Numerele se vor citi din fiier i se vor
scrie n list prin adugare dup ultimul nod. Problema se descompune n urmtoarele
DI

subprobleme, iar algoritmii pentru rezolvarea subproblemelor sunt implementai cu ajutorul


subprogramelor:
P1 Se citete valoarea pentru x de la tastatur.
RA

P2 Se citete primul numr din fiier i se adaug primul nod la list (nodul prim)
subprogramul adauga nod().
P3.Ct timp mai exist numere n fiier execut: se citete un numr din fiier i se
adaug un nod cu numrul respectiv dup ultimul nod din list subprogramul
TU

adauga ultim().
P4 Dac primul nod din list conine numrul x, atunci se elimin primul nod (subprogra-
mul elimina prim()); altfel, se caut predecesorul nodului care conine numrul x
(subprogramul cauta()) i dac se gsete acest nod, atunci se terge nodul care
I

urmeaz dup el (subprogramul elimina urm()).


ED
Informatic 131

C
P5 Se parcurge lista de la primul nod pn la sfritul ei i se afieaz informaia din
fiecare nod subprogramul afiare().
#include<fstream.h>

I
struct nod {int info;

OG
nod *urm;};
fstream f("lista3.txt",ios::in);
int n,x;
void adauga nod(nod *&prim, nod *&ultim)
{prim=new nod; ultim=prim; prim->info=n; prim->urm=NULL;}

AG
void adauga_ultim(nod *&ultim)
{nod *p=new nod; p->info=n; p->urm=NULL; ultim->urm=p; ultim=p;}
nod * cauta(nod *p)
{while(p->urm!=NULL && p->urm->info!=x) p=p->urm;

ED
return p;}
void elimina_prim(nod *&prim)
{nod *q=prim; prim=prim->urm; delete q;}
void elimina_urm(nod *p)
{nod *q=p->urm; p->urm=p->urm->urm; delete q;}

P
void afisare(nod *prim)
{for (nod *p=prim;p!=NULL;p=p->urm) cout<<p->info<<" ";
cout<<endl;}
I
void main()
{nod *prim,*ultim,*p; cout<<"x= "; cin>>x;
f>>n; adauga_nod(prim,ultim);

while(f>>n) adauga_ultim(ultim); f.close();


if (prim->info==x) elimina_prim(prim);
IC

else {p=cauta(prim);
if (p->urm!=NULL) elimina_urm(p);}
afisare(prim);}
CT

Enunul problemei 4. Se citete dintr-un fiier text un ir de numere separate prin spaiu
cu care se creeaz o list simplu nlnuit n ordinea n care sunt citite numerele din fiier.
S se elimine din list valorile care se repet, n afar de prima lor apariie. Pentru testarea
programului se va folosi irul de numere: {2, 4, 9, 9, 9, 6, 2, 9, 9}.
DA

Nodurile listei nu sunt ordonate conform unui criteriu. Numerele se vor citi din fiier i se vor
scrie n list prin adugare dup ultimul nod. Problema se descompune n urmtoarele
subprobleme, iar algoritmii pentru rezolvarea subproblemelor sunt implementai cu ajutorul
subprogramelor:
DI

P1 Se citete primul numr din fiier i se adaug primul nod la list (nodul prim)
subprogramul adauga nod().
P2 Ct timp mai exist numere n fiier execut: se citete un numr din fiier i se
RA

adaug un nod cu numrul respectiv dup ultimul nod din list subprogramul
adauga ultim().
P3 Se elimin din list valorile care se repet, astfel (subprogramul prelucrare()):
Pentru un pointer p care indic fiecare nod din list, ncepnd cu primul nod pn la
TU

penultimul nod, execut:


Se iniializeaz pointerul q cu adresa nodul curent (indicat de pointerul p).
Ct timp pointerul q nu indic ultimul nod, execut: dac nodul indicat de
pointerul p conine acelai numr cu succesorul nodului indicat de pointerul q,
I
ED
132 Implementarea structurilor de date

C
atunci se elimin succesorul nodului q ( subprogramul elimina urm());
altfel, pointerul q indic succesorul nodului.
P4 Se parcurge lista de la primul nod pn la sfritul ei i se afieaz informaia din

I
fiecare nod (subprogramul afisare()).

OG
#include<fstream.h>
struct nod {int info;
nod *urm;};
fstream f("lista4.txt",ios::in);

AG
int n;
void adauga nod(nod *&prim, nod *&ultim)
{prim=new nod; prim->info=x; prim->urm=NULL; ultim=prim;}
void adauga ultim(nod *&ultim)
{nod *p=new nod; p->info=x; p->urm=NULL; ultim->urm=p; ultim=p;}

ED
void elimina_urm(nod *p)
{nod *q=p->urm; p->urm=p->urm->urm; delete q;}
void prelucrare(nod *prim)
{nod *p,*q;

P
for (p=prim;p->urm!=NULL;p=p->urm)
{n=p->info; q=p;
while (q!=NULL)
I
{if (q->urm!=NULL && q->urm->info==n) elimina_urm(q);
else q=q->urm;}}}
void afisare(nod *prim)
{for (nod *p=prim; p!=NULL;p=p->urm) cout<<p->info<<" ";

cout<<endl;}
void main() {nod *prim,*ultim; f>>n; adauga_nod(prim,ultim);
IC

while (f>>n) adauga_ultim(ultim); f.close();


prelucrare(prim); afisare(prim);}
Enunul problemei 5. Adunarea a dou polinoame. Se citesc dintr-un fiier text de pe
CT

prima linie un numr n1, care reprezint numrul de coeficieni nenuli ai unui polinom, apoi
de pe urmtoarele n1 linii coeficienii nenuli i gradul, de pe linia urmtoare un numr n2
care reprezint numrul de coeficieni nenuli ai celui de al doilea polinom i apoi de pe
urmtoarele linii coeficienii nenuli i gradul. S se creeze cu aceste informaii dou liste
DA

simplu nlnuite i s se adune cele dou polinoame. Coeficientul i gradul fiecrui termen
din polinomul sum se vor salva ntr-un fiier. Pentru testarea programului se vor folosi
4 2 3 2
polinoamele -10x +5x -3x i 3x +7x +x+2.
DI

Se vor crea dou liste n care se vor memora cele dou polinoame. Informaia util va fi
memorat ntr-o nregistrare cu dou cmpuri: un cmp pentru coeficient i un cmp pentru
grad. Ambele liste se creeaz prin citirea datelor din fiier i adugare dup ultimul nod. n a
treia list se va memora polinomul obinut prin adunarea celor dou polinoame. Cele trei liste
RA

se identific prin adresa primului nod (prim1, prim2 i respectiv prim3) i prin adresa
ultimului nod (ultim1, ultim2 i respectiv ultim3). Problema de creare a listei sum a
polinoamelor se descompune n urmtoarele subprobleme, iar algoritmii pentru rezolvarea
subproblemelor sunt implementai cu ajutorul subprogramelor:
TU

P1 Se citesc din fiier n1 i coeficientul i gradul primului termen din primul polinom. Se
adaug primul nod la lista L1 (nodul prim1) subprogramul adauga_nod().
P2 Pentru urmtoarele n1-1 perechi de numere din fiier, execut: se citesc din fiier
coeficientul i gradul unui termen al primului polinom i se adaug un nod cu
I
ED

informaia respectiv dup ultimul nod din lista L1 subprogramul adauga_ultim().


Informatic 133

C
P3 Se citesc din fiier n2 i coeficientul i gradul primului termen din al doilea polinom.
Se adaug primul nod la lista L2 (nodul prim2) subprogramul adauga_nod().
P4 Pentru urmtoarele n2-1 perechi de numere din fiier, execut: se citesc din fiier

I
coeficientul i gradul unui termen al celui de al doilea polinom i se adaug un nod cu

OG
informaia respectiv dup ultimul nod din lista L2 subprogramul adauga_ultim().
P5 Se adaug primul nod (prim3) la lista L3 cu urmtoarea informaie: dac gradul din
primul nod din lista L1 este egal cu gradul primului nod din lista L2, atunci gradul este
egal cu gradul nodului din Lista 1, iar coeficientul este egal cu suma coeficienilor din

AG
nodurile celor dou liste i n ambele liste se trece la nodul urmtor; altfel, dac gradul
din primul nod din lista L1 este mai mare dect gradul primului nod din lista L2, atunci
gradul este egal cu gradul nodului din Lista 1, iar coeficientul este egal cu coeficientul
nodului din Lista 1 i n Lista 1 se trece la urmtorul nod; altfel, gradul este egal cu
gradul nodului din Lista 2, iar coeficientul este egal cu coeficientul nodului din Lista 2 i

ED
n Lista 2 se trece la urmtorul nod subprogramul adauga nod().
P6 Ct timp nu s-a ajuns la sfritul Listei 1 i al Listei 2, execut: se adaug un nod la
lista L3 dup ultimul nod, cu urmtoarea informaie: dac gradul din nodul curent din
lista L1 este egal cu gradul nodului curent din lista L2, atunci gradul este egal cu

P
gradul nodului din Lista 1, iar coeficientul este egal cu suma coeficienilor din nodurile
celor dou liste i n ambele liste se trece la nodul urmtor; altfel, dac gradul din
I
nodul curent din lista L1 este mai mare dect gradul din nodul curent din lista L2,
atunci gradul este egal cu gradul nodului din Lista 1, iar coeficientul este egal cu coefi-
cientul nodului din Lista 1 i n Lista 1 se trece la urmtorul nod; altfel, gradul este egal
cu gradul nodului din Lista 2, iar coeficientul este egal cu coeficientul nodului din Lista 2

i n Lista 2 se trece la urmtorul nod subprogramul adauga_ultim().


IC

#include<fstream.h>
fstream f1("lista5.txt",ios::in),f2("polinom.txt",ios::out);
struct nod {int c,g;
nod *urm;};
CT

int c,g,n;
void adauga_nod(nod *&prim,nod *&ultim)
{prim=new nod; ultim=prim; prim->urm=NULL; prim->c=c; prim->g=g;}
void adauga_ultim(nod *&ultim)
DA

{nod *p=new nod; p->urm=NULL; ultim->urm=p; ultim=p; p->c=c; p->g=g;}


void creare(nod *&prim,nod *&ultim)
{f1>>c>>g; adauga_nod(prim,ultim);
for (int i=2;i<=n;i++) {f1>>c>>g; adauga_ultim(ultim);}}
DI

void adunare(nod *prim1, nod *prim2, nod *&prim3, nod *&ultim3)


{nod *p=prim1,*q=prim2;
if (p->g==q->g) {g=p->g; c=p->c+q->c; p=p->urm; q=q->urm;}
else if (p->g>q->g) {g=p->g; c=p->c; p=p->urm;}
RA

else {g=q->g; c=q->c; q=q->urm;}


adauga_nod(prim3,ultim3);
while(q!=NULL && p!=NULL)
{if (p->g==q->g) {g=p->g; c=p->c+q->c; p=p->urm; q=q->urm;}
else if (p->g>q->g) {g=p->g; c=p->c; p=p->urm;}
TU

else {g=q->g; c=q->c; q=q->urm;}


adauga_ultim(ultim3);}
if (p!=NULL)
while(p!=NULL) {g=p->g; c=p->c; adauga_ultim(ultim3);}
I

else
ED
134 Implementarea structurilor de date

C
while(q!=NULL) {g=q->g; c=q->c;adauga_ultim(ultim3);}}
void afisare(nod *prim)
{for (nod *p=prim;p!=NULL;p=p->urm) cout<<p->c<<" "<<p->g<<endl;

I
cout<<endl;}

OG
void salvare(nod *prim)
{for (nod *p=prim;p!=NULL;p=p->urm) f2<<p->c<<" "<<p->g<<endl;}
void main()
{nod *prim1,*ultim1,*prim2,*ultim2,*prim3,*ultim3;
int n1,n2;

AG
f1>>n1; n=n1; creare(prim1,ultim1); afisare(prim1);
f1>>n2; n=n2; creare(prim2,ultim2); afisare(prim2);
adunare(prim1,prim2,prim3,ultim3); afisare(prim3); salvare(prim3);
f1.close(); f2.close();}

ED
Enunul problemei 6. Reuniunea i intersecia a dou mulimi. Se citesc dintr-un fiier
text de pe prima linie un numr n1, care reprezint numrul de elemente ale primei mulimi,
apoi de pe urmtoarea linie elementele mulimii, de pe linia urmtoare un numr n2
numrul de elemente ale celei de a doua mulimi, apoi de pe urmtoarea linie elementele

P
mulimii. S se determine reuniunea i intersecia celor dou mulimi. Pentru testarea
programului se vor folosi dou seturi de date de intrare: mulimile A={1,2,3,4,5} i
B={4,5,6,7} i mulimile A={1,2,3} i B={4,5}.
I
Se vor crea dou liste n care se vor memora cele dou mulimi. Ambele liste se creeaz prin
citirea datelor din fiier i adugare dup ultimul nod. n a treia list se va memora reuniunea
celor dou mulimi, iar n a patra list intersecia. Cele patru liste se identific prin adresa

primului nod (prim1, prim2, prim3 i respectiv prim4) i prin adresa ultimului nod (ultim1,
ultim2, ultim3 i respectiv ultim4).
IC

Pentru determinarea reuniunii se vor executa urmtorii pai:


Pas1. Se adaug primul nod la Lista 3 (nodul prim3) care conine numrul din primul nod
al Listei 1 (prim1).
CT

Pas2. Se parcurge Lista 1 de la succesorul primului nod pn la sfritul ei i se adaug


un nod cu numrul respectiv dup ultimul nod din Lista 3.
Pas3. Pentru fiecare nod din Lista 2, execut: se parcurge Lista 1 i dac numrul din
nodul curent din Lista 2 nu se gsete n Lista 1, atunci se adaug un nod cu
DA

numrul respectiv dup ultimul nod din Lista 3.


Pentru determinarea interseciei se vor executa urmtorii pai:
Pas1. Se iniializeaz Lista 4 ca list vid (prim4=NULL i ultim4=NULL).
DI

Pas2. Pentru fiecare nod din Lista 1, execut: se parcurge Lista 2 i dac numrul din
nodul curent din Lista 2 se gsete n Lista 1, atunci se adaug un nod cu
numrul respectiv ca prim nod n Lista 4 (nodul prim4).
Pas3. Dac s-a adugat primul nod la Lista 4, atunci pentru un nod din Lista 1 de la
RA

succesorul nodului curent pn la ultimul nod, execut: se parcurge Lista 2 i


dac numrul din nodul curent din Lista 1 se gsete n Lista 2, atunci se adaug
n Lista 4, un nod cu numrul respectiv, dup ultimul nod.
#include<fstream.h>
TU

struct nod {int info;


nod *urm;};
fstream f("lista6.txt",ios::in);
int x;
I

void adauga_nod(nod *&prim,nod *&ultim)


ED
Informatic 135

C
{prim=new nod; prim->info=x; prim->urm=NULL; ultim=prim;}
void adauga_ultim(nod *&ultim)
{nod *p=new nod; p->info=x; p->urm=NULL; ultim->urm=p; ultim=p;}

I
void creare(nod *&prim,nod *&ultim)

OG
{int n; f>>n>>x; adauga_nod(prim,ultim);
for (int i=2;i<=n;i++) {f>>x; adauga_ultim(ultim);}}
void reuniune(nod *prim1, nod *prim2, nod *&prim3, nod *&ultim3)
{nod *p,*q; int gasit;
x=prim1->info; adauga_nod(prim3,ultim3);

AG
for(p=prim1->urm;p!=NULL;p=p->urm) {x=p->info; adauga_ultim(ultim3);}
for (p=prim2;p!=NULL;p=p->urm)
{for(q=prim1,gasit=0; q!=NULL && !gasit; q=q->urm)
if(p->info==q->info) gasit=1;
if(!gasit) {x=p->info; adauga_ultim(ultim3);}}}

ED
void intersectie(nod *prim1, nod *prim2, nod *&prim4, nod *&ultim4)
{nod *p,*q; int gasit; prim4=NULL; ultim4=NULL;
for(gasit=0,p=prim1;p!=NULL && !gasit; p=p->urm)
for (q=prim2; q!=NULL && !gasit; q=q->urm)

P
if (p->info==q->info) {gasit=1; x=p->info;}
if (gasit)
{adauga_nod(prim4,ultim4);
I
for(;p!=0;p=p->urm)
{for (gasit=0,q=prim2; q!=NULL && !gasit; q=q->urm)
if(p->info==q->info) gasit=1;
if(gasit) {x=p->info; adauga_ultim(ultim4);}}}}

void afisare(nod *prim)


{for (nod *p=prim; p!=NULL ;p=p->urm) cout<<p->info<<" ";
IC

cout<<endl;}
void main()
{nod *prim1,*ultim1,*prim2,*ultim2,*prim3,*ultim3,*prim4,*ultim4;
CT

creare(prim1,ultim1); creare(prim2,ultim2); f.close();


reuniune(prim1,prim2,prim3,ultim3); cout<<"Reuniunea= "; afisare(prim3);
intersectie(prim1,prim2,prim4,ultim4); cout<<"Intersectia= ";
if (prim4!=NULL) afisare(prim4);
DA

else cout<<"Multimea vida";}

Scriei cte un program care s rezolve cerinele fiecrei probleme. Fieca-


Tem re problem se va descompune n subprobleme i algoritmul pentru rezol-
DI

varea unei subprobleme se va implementa cu un subprogram. Datele se


transmit ntre subprograme cu ajutorul parametrilor de comunicaie i nu al variabilelor
globale. Dup executarea unei operaii de prelucrare a listei simplu nlnuite, se vor afia
numerele din nodurile listei pentru a se verifica dac operaia de prelucrare s-a executat
RA

corect. Se vor alege seturi de date de intrare astfel nct s se verifice algoritmul pe toate
traseele lui. Pentru urmtorii 18 itemi n nodurile listelor se memoreaz numere ntregi. irul de
numere se citete dintr-un fiier text n care sunt scrise pe acelai rnd, separate prin spaiu.
1. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele. Se
TU

mai citesc de la tastatur dou numere x i y. Se insereaz n list numrul y naintea


numrului x.
2. Se creeaz o list n care ordinea de acces este invers celei n care sunt citite nume-
rele. Se elimin din list cel mai mic numr i cel mai mare numr.
I
ED
136 Implementarea structurilor de date

C
3. Se creeaz o list i se afieaz n ordinea invers citirii din fiier numai numerele pare.
4. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. Se mai citete un numr n de la tastatur. Se afieaz elementul cu numrul de

I
ordine n din list. Dac nu exist, se afieaz un mesaj de informare.

OG
5. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. Se insereaz naintea fiecrui numr factorii si primi.
6. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. Se insereaz ntre fiecare pereche de noduri cel mai mare divizor comun al celor

AG
dou numere.
7. Se creeaz dou liste n care ordinea de acces este cea n care sunt citite numerele din
fiiere. Se creeaz a treia list prin concatenarea listei care are cele mai puine
elemente la lista care are cele mai multe elemente. Dac listele au acelai numr de

ED
elemente, se va aduga lista a doua la prima list.
8. Se creeaz dou liste n care ordinea de acces este cea n care sunt citite numerele din
fiiere. Se creeaz a treia list prin concatenarea celei de a doua liste la prima list. Se
elimin din a treia list numerele care se repet.

P
9. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din fiier.
Se divizeaz lista n dou liste: una care conine numere care sunt palindrom i una care
conine numerele care nu sunt palindrom. Se salveaz lista cu numere palindrom ntr-un
I
alt fiier. Dac nu au existat numere palindrom, n fiier se va scrie un mesaj de informare.
n lista care nu conine numere palindrom se insereaz dup fiecare numr inversul su.
10. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din

fiier. Se afieaz numerele care au ultimele trei cifre identice, se elimin din list
numerele care au ultimele trei cifre consecutive i se insereaz valoarea 10 naintea
IC

numerelor care au suma ultimelor trei cifre egal cu 10.


11. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. Se afieaz numerele care au mai mult de doi divizori primi, se insereaz divizorii
CT

proprii n faa numerelor care au mai mult de trei divizori proprii i se elimin din list
numerele care au cel puin dou cifre identice.
12. Se creeaz o list numai cu numerele prime din fiier. Se afieaz cel mai mare numr
prim i cel mai mic numr prim. Se verific dac lista conine numai numere distincte i
DA

se afieaz un mesaj de informare. Dac lista nu conine numai numere distincte, se


elimin numere din list astfel nct s conin numai numere distincte. Se salveaz lista
creat ntr-un alt fiier. Dac nu au existat numere prime n fiier, se va scrie un mesaj
de informare. (Indicaie. Se va crea o list ordonat cresctor i se vor afia numerele
DI

prime din primul nod i din ultimul nod).


13. Se creeaz dou liste cu numerele citite din fiiere. n primul fiier numerele sunt
ordonate cresctor, iar n al doilea fiier numerele sunt ordonate descresctor. Se
RA

creeaz a treia list prin interclasarea primelor dou.


14. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. S se inverseze ordinea de acces n list, astfel nct parcurgerea s se fac de
la ultimul numr ctre primul numr. (Indicaie. Se mut ultimul nod la nceputul listei i
TU

apoi, pn se ajunge la numrul memorat la adresa care a fost a primului nod se


insereaz nodul ultim dup ultimul nod inserat.)
15. Se creeaz o list n care ordinea de acces este cea n care sunt citite numerele din
fiier. S se afieze n ordine invers numerele din list. (Indicaie. Se implementeaz
I

un algoritm recursiv de parcurgere a listei.)


ED
Informatic 137

C
16. Se creeaz o list ordonat cu numerele din fiier i se divizeaz apoi lista n dou liste:
una cu numere pare i una cu numere impare.
17. n fiier sunt memorate foarte multe numere (maxim 10.000). Foarte multe dintre aceste

I
numere se repet (exist maxim 100 de numere distincte). Se creeaz o list ordonat

OG
cresctor numai cu numerele distincte i cu frecvena lor de apariie. Se afieaz cel mai
mare numr i cel mai mic numr. Se calculeaz media aritmetic a numerelor care au
valoarea cea mai mare sau au valoarea cea mai mic i se afieaz numai numerele
care sunt mai mari dect media aritmetic.

AG
18. Pentru dou mulimi de numere A i B s se determine diferenele A-B i B-A.
19. Se citete dintr-un fiier text un numr cu maxim 20 de cifre. Se creeaz o list cu cifrele
numrului, se elimin din list cifrele pare i se afieaz numrul astfel obinut.
20. Se calculeaz produsul a dou polinoame. Informaiile despre cele dou polinoame se

ED
citesc dintr-un fiier. (Indicaie. Pentru fiecare nod din prima list se parcurge a doua
list i, dac produsul coeficienilor nu este nul, se creeaz un nod n lista a treia care va
avea coeficientul egal cu produsul coeficienilor i gradul egal cu suma gradelor. Lista a
treia este o list ordonat descresctor dup grad.)

P
21. Se creeaz dou liste cu n noduri i respectiv m noduri care conin numere ntregi
generate aleatoriu n intervalul [a,b]. Valorile pentru numrul de noduri n, i respectiv m,
i pentru limitele intervalului, a i b, se citesc de la tastatur. S se afieze numai
I
numerele distincte din cele dou liste i numrul care are cea mai mare frecven de
apariie n cele dou liste.

2.6.4. Algoritmi pentru prelucrarea listelor circulare simplu


nlnuite
IC

Algoritmii de adugare a primului nod la lista vid i de adugare dup ultimul nod
sunt la fel ca i cei de la listele simplu nlnuite:
CT

Lista circular simplu nlnuit


prim ultim
info urm info urm info urm info urm
DA

2.6.4.1. Crearea listei


Deoarece n algoritmii de prelucrare trebuie s se cunoasc adresa primului nod, este impor-
DI

tant adugarea primului nod la lista vid. Paii algoritmului de creare a unei liste sunt:
PAS1. Se adaug primul nod la list (nodul prim).
PAS2. Ct timp mai exist informaie execut: se adaug un nod la list dup ultimul nod.
RA

PAS3. Se leag ultimul nod de primul nod.


Implementarea algoritmului. Se folosete funcia procedural creare() al crei parame-
tru este prim de tip nod: care se transmite prin referin deoarece este parametru de
intrare-ieire. Se folosete variabila global n pentru citirea informaiei din nod. Se conside-
TU

r c nu mai exist informaie atunci cnd valoarea citit pentru n are valoarea 0.
void creare(nod *&prim)
{nod *ultim; cin>>n; adauga_nod(prim,ultim);
while(n!=0) {cin>>n; adauga_ultim(ultim);}
I

ultim->urm=prim;}
ED
138 Implementarea structurilor de date

C
2.6.4.2. Parcurgerea listei
Deoarece lista circular nu conine un ultim nod care s fie considerat ca terminator al
listei, se va considera ca nod care termin lista nodul prim. Paii algoritmului de prelu-

I
crare a unei liste circulare sunt:

OG
PAS1. Se prelucreaz primul nod din list (nodul prim).
PAS2. Pentru fiecare nod din list ncepnd de la succesorul nodului prim pn la
primul nod, execut: se prelucreaz nodul curent.
Implementarea algoritmului. Se folosete funcia procedural parcurge() al crei para-

AG
metru prim de tip nod se transmite prin valoare deoarece este parametru de intrare.
void parcuge(nod *prim)
{//se prelucreaz prim->info;
for (nod *p=prim->urm; p!=prim; p=p->urm) //se prelucreaz p->info;}

ED
2.6.4.3. Eliminarea unui nod din list
Dac se elimin din list nodul care urmeaz dup nodul curent p trebuie s se verifice
dac acest nod nu este nodul prim, ca s nu se piard adresa primului element din list.

P
Paii algoritmului de eliminare a nodului urmtor nodului curent sunt:
PAS1. Se salveaz adresa succesorului nodului p n pointerul q.
PAS2. Se leag nodul p de succesorul succesorului lui.
I
PAS3. Dac succesorul nodului p era nodul prim, atunci succesorul nodului prim devine
nodul prim.
PAS4. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul q.

Implementarea algoritmului. Se folosete funcia procedural elimina_urm() ai crei para-


metri de tip nod sunt: p (pentru adresa nodului precedent nodului ce se elimin), care se
IC

transmite prin valoare deoarece este parametru de intrare i prim, care se transmite prin
referin, deoarece este parametru de intrare-ieire.
void elimina_urm(nod *p,nod *&prim)
CT

{nod *q=p->urm; p->urm=p->urm->urm;


if(q==prim) prim=prim->urm;
delete q;}
DA

Scop: exemplificarea modului n care, pentru rezolvarea problemei, folosii algoritmii de prelu-
crare a listelor circulare simplu nlnuite i implementarea lor cu ajutorul subprogramelor.
DI

Enunul problemei. Se citete dintr-un fiier text un ir de numere separate prin spaiu cu
care se creeaz o list circular simplu nlnuit n ordinea n care sunt citite numerele din
fiier. S se tearg numerele pare din list i s se afieze numerele din list. Pentru
testarea programului se vor folosi dou seturi de numere: {2, 2, 3, 4, 4} i {2, 2, 2, 4, 4}.
RA

Problema se descompune n urmtoarele subprobleme, iar algoritmii pentru rezolvarea


subproblemelor sunt implementai cu ajutorul subprogramelor:
P1 Se creeaz lista circular simplu nlnuit subprogramul creare().
TU

P2 Se parcurge lista de la succesorul primului nod pn la primul nod i dac numrul


din succesorul nodului curent este par, atunci se elimin succesorul nodului curent
subprogramul elimin urm(); altfel se trece la succesorul nodului curent.
P3 Dac numrul din nodul prim este par, atunci se elimin nodul prim i lista este vid
I

subprogramul elimin prim().


ED
Informatic 139

C
P4 Dac lista nu este vid (subprogramul este vid()), atunci se afieaz numerele
din fiecare nod (subprogramul afisare()).
#include<fstream.h>

I
struct nod {int info;

OG
nod *urm;};
fstream f("lista7.txt",ios::in);
int x;
void adauga_nod(nod *&prim,nod *&ultim)
{prim=new nod; prim->info=x; prim->urm=NULL; ultim=prim;}

AG
void adauga_ultim(nod *&ultim)
{nod *p=new nod; p->info=x; p->urm=NULL; ultim->urm=p; ultim=p;}
void creare(nod *&prim)
{nod *ultim; f>>x; adauga_nod(prim,ultim);

ED
while (f>>x) adauga_ultim(ultim);
ultim->urm=prim;}
void elimina_urm(nod *p,nod *&prim)
{nod *q=p->urm; p->urm=p->urm->urm;
if(q==prim) prim=prim->urm;

P
delete q;}
void elimina_prim(nod *&prim)
{nod *q=prim; prim=NULL; delete q;}
I
int este vida(nod *prim) {return prim==NULL;}
void afisare(nod *prim)
{cout<<prim ->info<<" ";

for (nod *p=p->urm;p!=prim;p=p->urm) cout<<p->info<<" "; cout<<endl;}


void main()
IC

{nod *prim,*p; creare(prim); afisare(prim);


for(p=prim->urm;p!=prim;)
if (p->urm->info%2==0) elimina_urm(p,prim);
else p=p->urm;
CT

if(prim->info%2==0) elimina prim(prim);


if (!este_vida(prim)) afisare(prim);}
Scriei cte un program care s rezolve cerinele fiecrei probleme. Fiecare
DA

Tem problem se va descompune n subprobleme i algoritmul pentru rezolvarea


unei subprobleme se va implementa cu un subprogram. Datele se transmit
ntre subprograme cu ajutorul parametrilor de comunicaie i nu al variabilelor globale. Se
creeaz liste circulare simplu nlnuite n nodurile crora se memoreaz numere ntregi.
DI

irul de numere se citete dintr-un fiier text n care sunt memorate pe acelai rnd, separate
prin spaiu. Dup executarea unei operaii de prelucrare a listei, se vor afia numerele din noduri
pentru a verifica dac operaia s-a executat corect. Se vor alege seturi de date de intrare astfel
nct s se verifice algoritmul pe toate traseele lui. Pentru urmtorii 4 itemi listele se creeaz
RA

astfel nct ordinea de acces s fie cea n care sunt citite numerele din fiier.
1. S se insereze, dup fiecare numr divizibil cu cea mai mare cifr a sa, valoarea cifrei,
i s se elimine numerele care au ultimele dou cifre consecutive.
2. S se verifice dac numerele sunt n progresie geometric i s se afieze primul
TU

termen al progresiei geometrice. (Observaie. Dac numerele sunt n progresie geome-


tric, nu este obligatoriu ca irul de numere citit din fiier s nceap cu primul termen al
progresiei geometrice.)
3. S se insereze ntre dou numere pare din list media lor aritmetic pn cnd nu mai
I
ED

exist perechi de numere pare.


140 Implementarea structurilor de date

C
4. Din lista circular creat s se creeze alte dou liste circulare simplu nlnuite una cu
numerele divizibile cu cea mai mare cifr, iar alta cu numerele divizibile cu cea mai mic
cifr i s se verifice dac cele dou liste conin numere comune.

I
5. Se creeaz o list ordonat cresctor i se creeaz apoi din aceast list o list cu

OG
numerele care sunt ptrate perfecte.

2.6.5. Algoritmi pentru prelucrarea listelor dublu nlnuite


n cazul listelor dublu nlnuite informaia de legtur trebuie s conin i adresa

AG
succesorului nodului (pointerul *ant ctre tipul nod):
struct nod
{int info; //informaia propriu-zis
nod *ant ,*urm;}; //informaia pentru legtur

ED
nod *prim, *ultim, *p;
Algoritmii de la listele simplu nlnuite se modific prin adugarea instruciunilor care
ntrein i adresa de legtur cu predecesorul nodului. Algoritmul de adugare a unui
nod p n interiorul listei naintea unui nod q se simplific deoarece se cunoate adresa

P
att a succesorului, ct i a predecesorului.
Lista dublu nlnuit
I
prim NULL info urm ant info urm

IC

ultim ant info NULL ant info urm


CT

2.6.5.1. Adugarea primului nod la list


Implementarea algoritmului. Se folosete funcia procedural adauga_nod() ai crei para-
DA

metri prim i ultim de tip nod se transmit prin referin deoarece sunt parametri de ieire.
void adaug nod (nod *&prim, nod *&ultim)
{prim = new nod; prim->info=x; prim->ant=NULL; prim->urm=NULL;
ultim=prim;}
DI

2.6.5.2. Adugarea unui nod la list


Adugare n faa primului nod
Implementarea algoritmului. Se folosete funcia procedural adauga_prim() al crei para-
RA

metru prim de tip nod se transmite prin referin deoarece este parametru de intrare-iere.
void adauga prim(nod *&prim)
{nod *p=new nod; p->info=x; p->ant=NULL; p->urm=prim; prim=p;}
Adugare dup ultimul nod
TU

Implementarea algoritmului. Se folosete funcia procedural adauga_ultim() al crei para-


metru ultim de tip nod se transmite prin referin deoarece este parametru de intrare-ieire.
void adauga ultim(nod *&ultim)
I

{nod *p=new nod; p->info=x;


ED

p->ant=ultim; p->urm=NULL; ultim->urm=p; ultim=p;}


Informatic 141

C
Adugarea n interiorul listei

prim ... q>ant q q>urm ... ultim

I
OG
a) dup nodul cu adresa q
Nodul p care se adaug se insereaz ntre nodul q i nodul q->urm. Succesorul su este nodul
q->urm, iar predecesorul su nodul q. Nodul p va fi succesorul nodului q i predecesorul no-
dului q->urm.

AG
Implementarea algoritmului. Se folosete funcia procedural adauga_dupa() ai crei para-
metri sunt de tip nod: q (adresa nodului dup care se face adugarea), care se transmite prin
valoare deoarece este parametru de intrare i ultim (adresa ultimului nod), care se transmite
prin referin deoarece este parametru de intrare-ieire.

ED
void adauga dupa(nod *q, nod *&ultim)
{nod *p=new nod; p->info=x; p->urm=q->urm; p->ant=q;
if (q==ultim) ultim=p; else q->urm->ant=p; q->urm=p;}

P
b) nainte de nodul de adres q
Nodul p care se adaug se insereaz ntre nodul q->ant i nodul q. Succesorul su este nodul
q, iar predecesorul su nodul q->ant. Nodul p va fi succesorul nodului q->ant i predecesorul
I
nodului q.
Implementarea algoritmului. Se folosete funcia procedural adauga_in_fata() ai crei
parametri sunt de tip nod: q (adresa nodului naintea caruia se face adugarea), care se trans-

mite prin valoare deoarece este parametru de intrare.


void adauga in fata(nod *q)
IC

{nod *p=new nod; p->info=x;


p->urm=q; p->ant=q->ant; q->ant->urm=p; q->ant=p;}

2.6.5.3. Parcurgerea listei


CT

Vizitarea fiecrui nod al listei se poate face n dou moduri:


pornind de la primul nod, pn la ultimul nod, n ordinea de nlnuire a nodurilor
furnizat de adresa urm din nodul vizitat;
DA

pornind de la ultimul nod, pn la primul nod, n ordinea de nlnuire a nodurilor


furnizat de adresa ant din nodul vizitat
Implementarea algoritmului. Se folosete funcia procedural parcurge-inainte(),
respectiv parcurge-inapoi(), al crei parametru prim, respectiv ultim, de tip nod, se
DI

transmite prin valoare deoarece este parametru de intrare.


void parcuge_inainte(nod *prim)
{for (nod *p=prim; p!=NULL; p=p->urm) //se prelucreaz p->info}
void parcuge_inapoi(nod *ultim)
RA

{for (nod *p=ultim; p!=NULL; p=p->ant) //se prelucreaz p->info}

2.6.5.4. Eliminarea unui nod din list


Eliminarea primului nod
TU

Implementarea algoritmului. Se folosete funcia procedural elimina_prim() al crei para-


metru prim de tip nod se transmite prin referin deoarece este parametru de intrare-ieire.
void elimina prim(nod *&prim)
I

{nod *q=prim; prim->urm->ant=NULL; prim=prim->urm; delete q;}


ED
142 Implementarea structurilor de date

C
Eliminarea ultimului nod
Implementarea algoritmului. Se folosete funcia procedural elimina_ultim() al crei para-
metru ultim de tip nod se transmite prin referin deoarece este parametru de intrare-ieire.

I
void elimina ultim(nod *&ultim)

OG
{nod *q=ultim; ultim->ant->urm=NULL; ultim=ultim->ant; delete q;}
Eliminarea unui nod din interiorul listei
Pentru a elimina nodul p aflat n interiorul listei, trebuie s legm predecesorul nodului p
(p->ant) de succesorul lui (p->urm). Succesorul nodului p->ant va fi nodul p->urm, iar pre-

AG
decesorul nodului p->urm va fi nodul p->ant.
Implementarea algoritmului. Se folosete funcia procedural elimina() al crei parametru
este de tip nod: p (adresa nodului care se elimin), care se transmite prin valoare deoarece

ED
este parametru de intrare.
void elimina(nod *p)
{nod *q=p; p->ant->urm=p->urm; p->urm->ant=p->ant; delete q;}

P
Scop: exemplificarea modului n care, pentru rezolvarea problemei, folosii algoritmii de prelu-
crare a listelor dublu nlnuite i implementarea lor cu ajutorul subprogramelor.
I
Enunul problemei 1. Se citete dintr-un fiier text un ir de numere separate prin spaiu
cu care se creeaz o list dublu nlnuit n ordinea n care sunt citite numerele din fiier.
S se adauge valoarea 1 dup fiecare numr par i s se tearg apoi numerele pare din

list. S se afieze numerele din list dup fiecare operaie de prelucrare, n ambele moduri
(de la primul la ultimul, i de la ultimul la primul). Pentru testarea programului se va folosi
IC

irul de numere: {2, 2, 5, 3, 4, 4}.


n prelucrarea listelor dublu nlnuite trebuie ntreinute att adresa primului nod, ct i
adresa ultimului nod. Problema se descompune n urmtoarele subprobleme, iar algoritmii
CT

pentru rezolvarea subproblemelor sunt implementai cu ajutorul subprogramelor:


P1 Se creeaz lista dublu nlnuit subprogramul creare().
P2 Se adaug un nod cu valoarea 1 dup fiecare numr par, astfel (subprogramul
DA

prelucrare 1()):
Se parcurge lista de la primul nod pn la penultimul nod i, dac numrul din
nodul curent este par, se adaug dup el un nod cu valoarea 1 subprogramul
adauga dupa().
DI

Dac numrul din nodul ultim este par, atunci se adaug dup el un nod care con-
ine valoarea 1 i acest nod devine nodul ultim subprogramul adauga ultim().
P3 Se elimin nodurile cu numere pare, astfel (subprogramul prelucrare 2()):
Se parcurge lista de la succesorul primului nod pn la penultimul nod i, dac
RA

numrul din nodul curent este par, atunci se elimin din list (subprogramul
elimina urm()); altfel, se trece la succesorul nodului curent.
Dac numrul din nodul prim este par, atunci se elimin din list i succesorul su
devine nodul prim subprogramul elimina_prim().
TU

#include<fstream.h>
struct nod {int info;
nod *ant,*urm;};
fstream f("lista8.txt",ios::in);
I

int x;
ED
Informatic 143

C
void adauga_nod(nod *&prim,nod *&ultim)
{prim=new nod; prim->info=x;
prim->urm=NULL; prim->ant=NULL; ultim=prim;}

I
void adauga_ultim(nod *&ultim)

OG
{nod *p; p=new nod; p->info=x;
p->urm=NULL; p->ant=ultim; ultim->urm=p; ultim=p;}
void adauga_dupa(nod *p)
{nod *q=new nod; q->info=x;
q->urm=p->urm; q->ant=p; p->urm->ant=q; p->urm=q;}

AG
void elimina_prim(nod *&prim)
{nod *q=prim; prim->urm->ant=NULL; prim=prim->urm; delete q;}
void elimina(nod *&p)
{nod *q=p; p->ant->urm=p->urm; p->urm->ant=p->ant; p=p->urm;
delete q;}

ED
void creare(nod *&prim,nod *&ultim)
{f>>x; adauga_nod(prim,ultim);
while (f>>x) adauga_ultim(ultim);}
void prelucrare 1(nod *prim,nod *&ultim)

P
{for(nod *p=prim;p->urm!=NULL;p=p->urm)
if (p->info%2==0) adauga_dupa(p);
if(ultim->info%2==0) adauga_ultim(ultim);}
I
void prelucrare 2(nod *&prim)
{for(nod *p=prim->urm;p->urm!=NULL;)
if (p->info%2==0) elimina(p); else p=p->urm;
if (prim->info%2==0) elimina_prim(prim);}

void afisare_urm(nod *prim)


{for (nod *p=prim;p!=NULL;p=p->urm) cout<<p->info<<" ";cout<<endl;}
IC

void afisare_ant(nod *ultim)


{for (nod *p=ultim;p!=NULL;p=p->ant) cout<<p->info<<" "; cout<<endl;}
void main()
CT

{nod *prim,*ultim,*p;
creare(prim,ultim); afisare_urm(prim); afisare_ant(ultim);
x=1; prelucrare 1(prim,ultim); afisare_urm(prim); afisare_ant(ultim);
prelucrare 2(prim); afisare_urm(prim); afisare_ant(ultim);}
DA

Enunul problemei 2 Calcularea rezistenei echivalente. S se calculeze rezistena


echivalent ntre punctele A i B pentru circuitul electric din figur.
DI
RA

Pentru calcularea rezistenei echivalente se pornete de la ultimele rezistene Rn i Rn-1


care sunt legate n serie. Se calculeaz rezistena lor echivalent Re1, care va fi legat n
paralel cu rezistena Rn-2. Prin calcularea rezistenei echivalente a celor dou rezistene
legate n paralel, Re1 i Rn-2, se va obine o nou rezisten echivalent Re2 care este legat
TU

n serie cu rezistena Rn-3. Calcularea rezistenei echivalente a circuitului electric este un


proces repetitiv n care alterneaz calcularea unei rezistene echivalente a dou rezistene
legate n serie cu calcularea unei rezistene echivalente a dou rezistene legate n paralel.
Pentru a ti care dintre variantele de calcul se alege, se folosete variabila s care are
I
ED

valoarea 1 dac rezistenele sunt legate n serie, i valoarea 0 dac sunt legate n paralel.
144 Implementarea structurilor de date

C
Valorile pentru rezistene se citesc dintr-un fiier text n care sunt memorate pe acelai rnd,
separate prin spaiu. Se creeaz o list dublu nlnuit n care ordinea de acces este cea n
care sunt citite numerele din fiier. Lista se parcurge de la ultimul nod pn la primul nod.

I
#include<fstream.h>

OG
struct nod {float info;
nod *ant,*urm;};
fstream f("rezistente.txt",ios::in);
float x;
void adauga_nod(nod *&prim,nod *&ultim)

AG
{prim=new nod; prim->info=x; prim->urm=NULL; prim->ant=NULL; ultim=prim;}
void adauga (nod *&ultim)
{nod *p; p=new nod; p->info=x;
p->urm=NULL; p->ant=ultim; ultim->urm=p; ultim=p;}

ED
void creare(nod *&prim, nod *&ultim)
{f>>x; adauga_nod(prim,ultim);
while (f>>x) adauga(ultim);}
float R(nod *ultim)
{int s=1; float r=ultim->info; nod *p=ultim->ant;

P
while (p!=NULL)
if (s) {r+=p->info; p=p->ant; s=0;}
else {r=(r*p->info)/(r+p->info); p=p->ant; s=1;}
I
return r;}
void main(){nod *prim, *ultim; creare(prim,ultim); f.close();
cout<<"Rezistenta echivalenta= "<<R(ultim);}

Recomandare. Listele dublu nlnuite se folosesc n problemele n care, pentru


prelucrarea informaiilor:
IC

se execut frecevent operaii de inserare i de eliminare de noduri;


lista trebuie parcurs n ambele sensuri.
Exemplu. n problemele n care trebuie prelucrate numere foarte mari (pentru memorarea
CT

crora nu pot fi folosite tipurile de date implementate) se folosesc listele dublu nlnuite:
pentru operaiile aritmetice (adunare, scdere, nmulire) listele n care sunt memorate
cele dou numere vor fi parcurse de la ultimul nod, pn la primul nod;
pentru compararea a dou numere sau determinarea numrului de cifre ale numrului,
DA

listele n care sunt memorate numerele vor fi parcurse de la primul pn la ultimul nod.
Scriei cte un program care s rezolve cerinele fiecrei probleme. Fiecare
Tem problem se va descompune n subprobleme i algoritmul pentru
DI

rezolvarea unei subprobleme se va implementa cu un subprogram. Datele


se transmit ntre subprograme cu ajutorul parametrilor de comunicaie i nu al variabilelor
globale. Se creeaz liste dublu nlnuite n nodurile crora se memoreaz numere ntregi.
irul de numere se citete dintr-un fiier text n care sunt memorate pe acelai rnd, separate
RA

prin spaiu. Dup executarea unei operaii de prelucrare a listei, se vor afia numerele din
noduri pentru a verifica dac operaia s-a executat corect. Se vor alege seturi de date de
intrare astfel nct s se verifice algoritmul pe toate traseele lui. Listele se creeaz astfel
nct ordinea de acces s fie cea n care sunt citite numerele din fiier.
TU

1. S se elimine numerele prime i s se insereze ntre fiecare pereche de numere rmase


cel mai mare divizor comun al lor.
2. S se calculeze cifra de control a fiecrui numr i, dac numrul este divizibil cu cifra
de control, cifra este adugat dup numr; altfel, numrul este eliminat din list. Cifra
I
ED
Informatic 145

C
de control a unui numr este suma repetat a cifrelor numrului pn cnd se obine o
sum mai mic dect 10.
3. S se modifice adresele din nodurile listei astfel nct s se obin dou liste liniare

I
dublu nlnuite care s conin numerele din poziiile pare, respectiv din poziiile impare.

OG
4. Se citesc dintr-un fiier dou numere foarte mari. S se scrie urmtoarele subprograme
pentru prelucrarea numerelor:
a. calcularea sumei, a diferenei i produsului numerelor;
b. compararea a dou numere (subprogramul trebuie s verifice dac cele dou

AG
numere sunt egale, iar dac nu sunt egale, s precizeze care numr este mai mare);
c. verificarea numrului dac are un numr par sau un numr impar de cifre, fr s se
numere cifrele numrului;
d. determinarea numrului de cifre ale unui numr;
e. verificarea numrului dac este palindrom.

ED
2.6.6. Algoritmi pentru prelucrarea stivelor
Cele dou extremiti ale stivei se numesc vrf i baz. Accesul la nodurile stivei

P
(adugarea, extragerea sau consultarea unui nod) este permis numai printr-o singur
extremitate numit vrf i ultimul nod inserat este primul nod extras (se extrage cea mai
nou informaie adugat). La o operaie de adugare a unui nod, vrful stivei stivei urc,
I
iar la o operaie de extragere a unui nod, vrful stivei coboar.
Implementarea dinamic a stivei se face la fel ca a unei liste liniare, cu deosebirea c:
vrful stivei va fi indicat de pointerul varf ctre tipul nod;

pentru adugarea unui nod, se poate folosi numai algoritmul de adugare n faa
primului nod;
IC

pentru extragerea unui nod se poate folosi numai algoritmul pentru eliminarea primului
nod.
Altfel spus, prelucrarea unei stive se face de la vrf spre baz i se prelucreaz ntotdea-
CT

una nodul din vrful stivei. Accesul la informaia din acest nod se face cu varf->info.
Stiva vid este stiva care nu conine nici un nod i adresa nodului vrf are valoarea
NULL (varf = NULL;). n stiva vid nu se mai pot executa operaii de extragere de
DA

noduri. Stiva poate s ajung s fie vid n dou cazuri: la iniializare sau dup
extragerea ultimului nod. Pentru testarea unei stive dac este vid, se poate
implementa funcia operand este_vida() care va furniza valoarea 1 (adevrat), dac
stiva este vid, i valoarea 0 (fals) dac stiva nu este vid.
DI

int este vida(nod *varf)


{return varf==NULL;}
Pentru prelucrri cu ajutorul stivei putei folosi urmtorii algoritmi:
iniializarea stivei;
RA

adugarea unui nod la stiv;


extragerea unui nod din stiv;
consultarea nodului din vrful stivei.
TU

2.6.6.1. Iniializarea stivei


Prin acest algoritm se creeaz stiva vid. n acest caz, nodul vrf nu exist i pointerul
varf are valoarea NULL.
Implementarea algoritmului. Se folosete funcia procedural init() al crei parametru
I
ED

varf se transmite prin referin, deoarece este parametru de ieire.


146 Implementarea structurilor de date

C
void init(nod *&varf)
{varf = NULL;}
2.6.6.2. Adugarea unui nod la stiv

I
OG
Nodul se adaug la stiv ca predecesor al vrfului. Paii algoritmului sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
PAS3. Nodul p se leag de nodul varf.
PAS4. Nodul p adugat devine nodul varf.

AG
Implementarea algoritmului. Se folosete funcia procedural adauga() al crei parametru
varf se transmite prin referin, deoarece este parametru de intrare-ieire.
void adauga(nod *&varf)
{nod *p=new nod; p->info=x; p->urm=varf; varf=p;}

ED
2.6.6.3. Extragerea unui nod din stiv
Nodurile se extrag din stiv pentru a putea consulta informaia care exist n nodurile
urmtoare. Un nod se poate extrage numai n cazul n care stiva nu este vid. Se poate

P
extrage numai nodul din vrful stivei (se elibereaz spaiul care a fost ocupat de nod). n
vrful stivei va ajunge succesorul nodului extras. Paii algoritmului sunt:
PAS1. Se salveaz adresa nodului varf n pointerul p.
I
PAS2. Succesorul nodului varf devine nodul varf.
PAS3. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul p.
Implementarea algoritmului. Se folosete funcia procedural extrage() al crei para-

metru varf se transmite prin referin, deoarece este parametru de intrare-ieire.


void extrage (nod *&varf)
IC

{nod *p =varf; varf=varf->urm; delete p;}


2.6.6.4. Prelucrarea stivei
CT

Prin acest algoritm se consult informaia din fiecare nod al stivei. Deoarece nu poate fi
consultat dect informaia din vrful stivei, pentru a ajunge la un nod trebuie s se
extrag toate nodurile pn la el.
DA

Implementarea algoritmului. Se folosete funcia procedural prelucrare() al crei parame-


tru varf de tip nod se transmite prin referin, deoarece este parametru de intrare-ieire.
void prelucrare(nod *&varf)
{while (varf!=NULL) {//se prelucreaz varf->info
extrage(varf);)}
DI

Scop: exemplificarea modului n care, pentru rezolvarea problemei, folosii algoritmii de prelu-
RA

crare a stivelor i implementarea lor cu ajutorul subprogramelor.


Enunul problemei. Se citete dintr-un fiier text un ir de numere separate prin spaiu
care se depun ntr-o stiv n ordinea n care sunt citite numerele din fiier. S se elimine
TU

numrul de la baza stivei i numerele rmase n stiv s se scrie ntr-un fiier text. Pentru
testarea programului se va folosi irul de numere: {1, 2, 5, 3, 4}.
n prelucrarea stivelor, pentru a putea ajunge la informaia care trebuie prelucrat, trebuie
extrase toate nodurile, pn la nodul care conine acea informaie, deoarece nu poate fi
I

prelucrat dect informaia din vrful stivei. Pentru a nu se pierde informaia din nodurile
ED
Informatic 147

C
extrase, ele vor fi descrcate ntr-o alt stiv (de rezerv), iar dup prelucrarea informaiei,
nodurile vor fi ncrcate din nou n stiv.
Consultarea nodului care conine numrul 3

I
OG
5 varf 5 varf
descarc consult ncarc
4 4
3 3 varf 3
2 4 varf_r 2 4 varf_r 2

AG
1 5 1 5 1 varf_r=NULL
stiva stiva de rezerv stiva stiva de rezerv stiva stiva de rezerv
Problema se descompune n urmtoarele subprobleme, iar algoritmul de rezolvare a unei
subprobleme este implementat cu ajutorul unui subprogram:

ED
P1 Se creeaz stiva cu numerele citite din fiier (nodul varf) subprogramul creare()).
P2 Se descarc stiva ntr-o alt stiv (nodul varf r) pn la penultimul nod (subpro-
gramul descarca()).

P
P3 Se extrage ultimul nod din stiv subprogramul extrage().
P4 Se ncarc n stiv (nodul varf) nodurile din stiva de rezerv (nodul varf r) sub-
programul incarca().
I
P5 Se scriu numerele din stiv (nodul varf) n fiierul text subprogramul salveaza().
#include<fstream.h>
struct nod {int info;
nod *urm;};

fstream f1("stiva1.txt",ios::in),f2("stiva2.txt",ios::out);
int x;
IC

void init(nod *&varf) {varf=NULL;}


void adauga(nod *&varf) {nod *p=new nod; p->info=x; p->urm=varf; varf=p;}
int este vida(nod *varf) {return varf==NULL;}
CT

void extrage(nod *&varf) {nod *p=varf; varf=varf->urm; delete p;}


void creare(nod *&varf)
{init(varf); while (f1>>x) adauga(varf);}
void descarca(nod *&varf,nod *&varf r)
DA

{init(varf r);
while (varf->urm!=NULL) {x=varf->info; extrage(varf); adauga(varf r);}}
void incarca(nod *&varf,nod *&varf r)
{while (!este vida(varf_r))
DI

{x=varf r->info; extrage(varf_r); adauga(varf);}}


void salveaza(nod *&varf)
{while (!este vida(varf)) {f2<<varf->info<<" "; extrage(varf);}}
void main() {nod *varf, *varf_r; creare(varf); f1.close();
RA

descarca (varf,varf r); extrage(varf);


incarca(varf,varf_r); salveaza(varf); f2.close();}
Fiecare problem se va descompune n subprobleme i algoritmul pentru
Tem rezolvarea unei subprobleme se va implementa cu un subprogram. Datele
TU

se transmit ntre subprograme cu ajutorul parametrilor de comunicaie i nu


al variabilelor globale. Se creeaz stive n nodurile crora se memoreaz informaia (numere
sau caractere). Informaia se citete dintr-un fiier text n care, numerele sau caracterele, sunt
memorate pe acelai rnd, separate prin spaiu. Se vor alege seturi de date de intrare astfel
I

nct s se verifice algoritmul pe toate traseele lui.


ED
148 Implementarea structurilor de date

C
1. ntr-o stiv sunt memorate numere din intervalul [1,10], ordonate cresctor, iar ntr-o alt
stiv, numere din intervalul [20,30], ordonate cresctor. S se concateneze cele dou
iruri de numere, pstrnd ordonarea cresctoare. (Indicaie. Se rstoarn a doua stiv

I
ntr-o a treia stiv, se rstoarn i prima stiv n a treia, peste numerele din prima stiv, i

OG
se extrag numerele din a treia stiv.)
2. Se compar dou stive fr a pierde coninutul lor n urma extragerii de noduri.
3. Se elimin din stiv numerele pare.
4. Se memoreaz ntr-o stiv un ir de litere mici. Se citete de la tastatur o liter mic a alfa-

AG
betului lit. S se creeze dou stive: una va conine literele din stiva iniial care preced n
alfabet litera lit i alta va conine literele din stiva iniial care succed n alfabet litera lit
5. S se afieze n ordine invers numerele dintr-o list liniar simplu nlnuit. (Indicaie.
Se ncarc numerele din list ntr-o stiv, n ordinea de parcurgere a listei, i apoi se

ED
extrag i se afieaz numerele din stiv.)
6. Se ordoneaz cresctor un ir de numere, cu ajutorul a dou stive. Determinai com-
plexitatea algoritmului. (Indicaie. Se folosesc dou stive. Se scrie un numr n Stiva 1.
Se citete un numr. Dac numrul din vrful Stivei 1 este mai mare dect numrul citit,

P
atunci noul numr se adaug la Stiva 1; altfel, se descarc din Stiva 1 n Stiva 2 numere
pn cnd n vrful Stivei 1 ajunge un numr mai mare dect numrul citit, se adaug la
Stiva 1 numrul citit, i se ncarc n Stiva 1 numerele din Stiva 2.)
I
7. S se verifice dac o expresie aritmetic ce conine paranteze este balansat, adic dac
fiecare parantez deschis este nchis corect. De exemplu, expresia (a+b+{c/[d-e]})+
(d/s) este balansat, iar expresia (a+b+{c/[d-e}])+(d/s) nu este balansat. (Indicaie. Se

codific parantezele 1(; 2 [; 3{; 4); 5]; 6}). Dac stiva nu este vid i dac diferena
dintre codul dintre paranteza citit i codul parantezei din vrful stivei este 3, atunci se
IC

elimin nodul din vrful stivei; altfel, se adaug la stiv codul parantezei citite. Dac stiva
este vid la terminarea evalurii expresiei, nseamn c expresia este balansat.)
CT

2.6.7. Algoritmi pentru prelucrarea cozilor


Cele dou extremiti ale cozii se numesc cap i baz. Adugarea de noduri la coad se
face prin nodul baz, iar extragerea i consultarea unui nod este permis numai prin
extremitatea cap (se extrage cea mai veche informaie adugat).
DA

Implementarea dinamic a cozii se face la fel ca a unei liste liniare, cu deosebirea c:


primul nod al cozii va fi indicat de pointerul cap ctre tipul nod, iar ultimul nod al cozii va
fi indicat de pointerul baza ctre tipul nod;
DI

pentru adugarea unui nod, se poate folosi numai algoritmul de adugare dup
ultimul nod;
pentru extragerea unui nod se poate folosi numai algoritmul pentru eliminarea
primului nod.
RA

Altfel spus, prelucrarea unei cozi se face de la cap spre baz i se prelucreaz ntotdeauna
nodul din capul cozii. Accesul la informaia din acest nod se face cu cap->info.
Coada vid este coada care nu conine nici un nod i adresa nodului cap are valoarea
TU

NULL (cap = NULL;). n coada vid nu se mai pot executa operaii de extragere de
noduri. Coada poate s ajung s fie vid n dou cazuri: la iniializare sau dup
extragerea ultimului nod. Pentru testarea unei cozi dac este vid se poate implementa
funcia operand este_vida() care va furniza valoarea 1 (adevrat), dac este vid, i
I

valoarea 0 (fals) dac nu este vid.


ED
Informatic 149

C
int este vida(nod *cap)
{return cap==NULL;}
Pentru prelucrri cu ajutorul cozii putei folosi urmtorii algoritmi:

I
iniializarea cozii;

OG
adugarea unui nod la coad;
extragerea unui nod din coad;
consultarea nodului din capul cozii.
2.6.7.1. Iniializarea cozii

AG
Prin acest algoritm se creeaz coada care conine un nod. n acest caz, nodurile cap i
baz vor avea aceeai adres.
Implementarea algoritmului. Se folosete funcia procedural init() ai crei parametri
cap i baza se transmit prin referin, deoarece sunt parametri de ieire.

ED
void init(nod *&cap, nod *&baza)
{cap=new nod; cap->info=x; cap->urm=NULL; baza=cap;}
2.6.7.2. Adugarea unui nod la coad

P
Nodul se adaug la coad ca succesor al bazei. Paii algoritmului sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
I
PAS3. Nodul p se leag de nodul baza.
PAS4. Nodul p adugat devine nodul baza.
Implementarea algoritmului. Se folosete funcia procedural adauga() al crei parametru

baza se transmite prin referin deoarece este parametru de intrare-ieire.


void adauga(nod *&baza)
IC

{nod *p=new nod; p->info=x; p->urm=NULL; baza->urm=p; baza=p;}


2.6.7.3. Extragerea unui nod din coad
CT

Nodurile se extrag din coad pentru a putea consulta informaia care exist n nodurile
urmtoare. Un nod se poate extrage numai n cazul n care coada nu este vid. Se poate
extrage numai nodul din capul cozii (se elibereaz spaiul care a fost ocupat de nod). n
capul cozii va ajunge succesorul nodului extras. Paii algoritmului sunt:
DA

PAS1. Se salveaz adresa nodului cap n pointerul p.


PAS2. Succesorul nodului cap devine nodul cap.
PAS3. Se cere eliberarea zonei de memorie de la adresa memorat n pointerul p.
Implementarea algoritmului. Se folosete funcia procedural extrage() al crei para-
DI

metru cap se transmite prin referin, deoarece este parametru de intrare-ieire.


void extrage(nod *&cap)
{nod *p =cap; cap=cap->urm; delete p;}
RA

2.6.7.4. Prelucrarea cozii


Prin acest algoritm se consult informaia din fiecare nod al cozii. Deoarece nu poate fi
consultat dect informaia din capul cozii, pentru a ajunge la un nod trebuie se
extrag toate nodurile pn la el.
TU

Implementarea algoritmului. Se folosete funcia procedural prelucrare() al crei parame-


tru cap de tip nod se transmite prin referin, deoarece este parametru de intrare-ieire.
void prelucrare(nod *&cap)
I

{while (cap!=NULL) {//se prelucreaz cap->info


ED

extrage(cap);)}
150 Implementarea structurilor de date

C
Scop: exemplificarea modului n care, pentru rezolvarea problemei, folosii algoritmii de prelu-

I
crare a cozilor i implementarea lor cu ajutorul subprogramelor.

OG
Enunul problemei. Se citete dintr-un fiier text un ir de numere separate prin spaiu
care se depun ntr-o coad n ordinea n care sunt citite din fiier. S se elimine numrul din
mijlocul cozii, dac numrul de noduri este impar, i cele dou numere din mijloc, dac
numrul de noduri este par, iar numerele rmase n coad s se scrie ntr-un fiier text.

AG
Pentru testarea programului se vor folosi dou seturi de numere: {1, 2, 5, 3, 4} i {1, 2, 5, 4}.
n prelucrarea cozilor, pentru a putea ajunge la informaia care trebuie prelucrat, trebuie
extrase toate nodurile pn la nodul care conine acea informaie, deoarece nu poate fi pre-
lucrat dect informaia din capul cozii. Pentru a nu se pierde informaia din nodurile extrase,

ED
ele vor fi descrcate ntr-o alt coad (de rezerv), iar dup prelucrarea informaiei, nodurile
vor fi descrcate n continuare n coada de rezerv, pn cnd coada iniial devine vid.
Consultarea nodului care conine numrul 3

P
coada coada coada
1 2 3 4 5 consult 3 4 5 cap=NULL
cap baz cap baz
I
descarc
descarc
coada de rezerv coada de rezerv
1 2 1 2 3 4 5

cap_r baza_r cap_r baza_r


IC

Problema se descompune n urmtoarele subprobleme, iar algoritmul de rezolvare a unei


subprobleme este implementat cu ajutorul unui subprogram:
P1 Se creeaz coada cu numerele citite din fiier (nodurile cap i baza) subprogramul
CT

creare().
P2 Se descarc coada ntr-o alt coad (nodurile cap r i baza r) pn la nodurile care
trebuie eliminate subprogramul descarca 1().
P3 Se extrage nodul sau se extrag nodurile din mijlocul cozii subprogramul extrage().
DA

P4 Se descarc restul nodurilor din coad (nodul cap) n coada de rezerv (nodul
baza_r) subprogramul descarca_2().
P5 Se scriu numerele din coada de rezerv (nodul cap r) n fiierul text subprogramul
salveaza().
DI

#include<fstream.h>
struct nod {int info;
nod *urm;};
fstream f1("coada1.txt",ios::in),f2("coada2.txt",ios::out);
RA

int x,n,i,j;
void init(nod *&cap,nod *&baza)
{cap=new nod; cap->info=x; cap->urm=NULL; baza=cap;}
int este vida(nod *cap) {return cap==NULL;}
TU

void adauga(nod *&baza)


{nod *p=new nod; p->info=x; p->urm=NULL; baza->urm=p; baza=p;}
void extrage(nod *&cap) {nod *p=cap; cap=cap->urm; delete p;}
void creare(nod *&cap, nod *&baza)
I

{f1>>x; init(cap,baza); n++;


ED
Informatic 151

C
while (f1>>x) {adauga(baza); n++;}}
void descarca 1(nod *&cap,nod *&cap r, nod *&baza_r)
{x=cap->info; extrage(cap); init(cap r,baza r);i++;

I
while (i<j) {x=cap->info; extrage(cap); adauga(baza_r);i++;}}

OG
void descarca 2(nod *&cap,nod *&baza r)
{while (!este_vida(cap))
{x=cap->info; extrage(cap); adauga(baza_r);}}
void salveaza(nod *&cap)
{while (!este_vida(cap)) {f2<<cap->info<<" "; extrage(cap);}}

AG
void main()
{nod *cap,*baza,*cap r,*baza r; creare(cap,baza); f1.close();
if (n%2==0) j=n/2-1; else j=n/2;
descarca_1(cap,cap r,baza r); extrage(cap);
if (n%2==0) extrage(cap);

ED
descarca 2(cap,baza r); salveaza(cap r); f2.close();}
Fiecare problem se va descompune n subprobleme i algoritmul
Tem pentru rezolvarea unei subprobleme se va implementa cu un subpro-

P
gram. Datele se transmit ntre subprograme cu ajutorul parametrilor de
comunicaie i nu al variabilelor globale. Se creeaz cozi n nodurile crora se memo-
reaz numere ntregi. irul de numere se citete dintr-un fiier text n care sunt memorate
I
pe acelai rnd, separate prin spaiu. Se vor alege seturi de date de intrare astfel nct s
se verifice algoritmul pe toate traseele lui.
1. Se elimin din coad numerele pare.
2. Se verific dac numerele dintr-o coad sunt ordonate (cresctor sau descresctor).

3. Se concateneaz dou cozi, adugnd a doua coad la sfritul primei cozi.


IC

4. Se formeaz din dou cozi o a treia coad care conine mai nti numerele pare din pozi-
iile impare din prima coad i apoi numerele impare din poziiile pare din a doua coad.
5. Se inverseaz ordinea numerelor dintr-o coad cu ajutorul unei stive.
CT

2.6.8. Aplicaii practice


1. Analiza lexical a unui text. S se afieze, n ordine alfabetic, cuvintele dintr-un text
i frecvena lor de apariie n text.
DA

2. Exist dou automate care elibereaz bonuri de ordine pentru o coad de ateptare. Pe
fiecare bon de ordine este trecut numrul bonului i momentul la care a fost eliberat
(exprimat n or, minut i secund). Bonurile au numere unice. Deservirea persoanelor
se face n ordinea momentului de eliberare a bonurilor. S se organizeze o coad de
DI

ateptare pe baza bonurilor emise de cele dou automate.


3. Jocul lui Josephus. ntr-un grup de n copii, acetia sunt aranjai n cerc i sunt numrai
ncepnd cu primul copil pn la numrul k. Copilul care are numrul k iese din joc, iar
RA

numrtoarea ncepe din nou de la 1 cu urmtorul copil. S se afieze ordinea de ieire


din joc a copiilor. Se vor implementa dou soluii, folosind o structur de date de tip:
a) coad; b) list circular simplu nlnuit.
4. S se simuleze, cu ajutorul unei stive, o main de adunat i multiplicat. Numerele se
TU

introduc ntr-o stiv i operaia se ncheie atunci cnd se citete de la tastatur


operatorul + (pentru adunarea numerelor) sau operatorul * (pentru nmulirea
numerelor). Se mai folosesc: caracterul A, pentru a anula ultimul numr introdus, i
caracterul C, pentru a anula toate numerele introduse.
I
ED
152 Implementarea structurilor de date

C
5. Un automobil trebuie s parcurg un traseu care formeaz un poligon, cu ntoarcere la staia
de pornire. Pe traseu exist n staii de alimentare cu carburant care formeaz vrfurile poli-
gonului. Fiecare staie de alimentare i este caracterizat de coordonatele (xi,yi). Automobilul

I
consum 1 litru de carburant la fiecare 20 km i nu exist restricie pentru capacitatea rezer-

OG
vorului. Se citesc dintr-un fiier text urmtoarele informaii: de pe primul rnd numrul de sta-
ii n, de pe urmtorul rnd un ir de n numere ci care reprezint cantitatea de combustibil cu
care este alimentat la staia i, iar de pe urmtorul rnd n perechi de numere xi i yi care re-
prezint coordonatele staiei i. Din ce punct trebuie s plece automobilul astfel nct s par-

AG
curg traseul cu ntoarcere n punctul de pornire i s nu rmn fr combustibil.

Pentru exerciiile urmtoare, dac nu se specific semnificaia variabilelor de memorie, se

ED
folosesc urmtoarele date:
struct nod {int info;
nod *urm;};
nod *prim,*ultim,*p,*q,*r,*u,*vf,*cap,*baza;

P
int x,k;
Rspundei:
I
1. Analizai din punct de vedere al complexitii algoritmii pentru prelucrarea listelor. Se
va folosi n determinarea complexitii timpul maxim de execuie. Pentru compararea
algoritmilor completai urmtorul tabel:

Lista simplu nlnuit Lista dublu nlnuit


Neordonat Ordonat Neordonat Ordonat
IC

Caut (L,k)
Adaug (L,x)
Elimin (L,x)
CT

Succesorul (L,x)
Predecesorul (L,x)
Minim (L)
Maxim (L)
DA

2. O list simplu nlnuit conine, n ordine, urmtoarele noduri: 2 4 6 8 10


12 14 16 18 20. Ce se va afia n urma execuiei urmtoarei secvene
de program?
DI

for(p=prim,k=1;k<5;k++,p=p->urm); cout<< p->info;


3. O list simplu nlnuit conine, n ordine, urmtoarele noduri: 1 2 3 4 5
6 7 8. Ce se va afia n urma execuiei urmtoarei secvene de program?
for(k=0,p=prim;p->urm!=NULL; p=p->urm) if (p->info%2) k+= p->info;
RA

cout<<k;
4. Ce se va afia n urma execuiei urmtoarei secvene de program, dac lista simplu
nlnuit conine, n ordine, urmtoarele noduri: 1 2 3 4 5? Dar dac
nodurile ei sunt, n ordine: 1 0 3 0 5?
TU

for(p=prim; p->info!=0;p=p->urm); cout<<p->info;


5. Ce se va afia n urma execuiei urmtoarei secvene de program, dac lista simplu
nlnuit conine, n ordine, urmtoarele noduri: 1 2 3 7 8 9? Dar dac
nodurile ei sunt, n ordine: 1 2 4 5 7 8?
I
ED

for(k=0,p=prim;p->info!=0;p=p->urm)
Informatic 153

C
if (p->urm->info-p->info==1) k++;
cout<<k;

Adevrat sau Fals:

I
OG
1. Dac p este primul nod al listei, pentru a afia informaia din al doilea nod se execut
secvena de instruciuni: p=p->urm; cout<<p->info;
2. Dac p este primul nod al listei, pentru a afia informaia din al doilea nod se execut
instruciunea: cout<<p->urm->info;

AG
3. Dac p este primul nod al listei, pentru a afia informaia din al treilea nod se execut
instruciunea: cout<<p->urm->urm->info;

Alegei:

ED
1. Dac p este primul nod al listei, iar q al doilea nod al listei, prin ce instruciune se
leag nodul p de nodul q?
a. p=q; b. q=p->urm; c. p=q->urm; d. p->urm=q;
2. Care dintre urmtoarele variante realizeaz corect legturile n cazul inserrii unui

P
nod nou ntr-o list simplu nlnuit, dac nodul nou are adresa p, iar nodul dup
care se insereaz are adresa q?
a. p->urm=q; q->urm=p->urm; b. p->urm=q->urm; q->urm=p;
I
c. q->urm=p->urm; d. p->urm=q->urm; p->urm=q;
3. Dac p este primul nod al listei, ce instruciune trebuie executat pentru a afia
informaia memorat n al treilea nod?
a. cout<<p->urm->urm->info->info; b. cout<<p->urm->info->urm->info;

c. cout<<p->urm->urm->info; d. cout<< p->urm->urm->urm->info;


4. Dac p, q i r sunt trei noduri consecutive ale listei, pentru a interschimba nodul q cu
IC

nodul r, care dintre secvenele de instruciuni este corect?


a. r->urm=q; q->urm=r->urm; p->urm=r;
b. p->urm=r; r->urm=q; q->urm=r->urm;
CT

c. q->urm=r->urm; r->urm=q; p->urm=r;


d. r->urm=q; p->urm=r; q->urm=r->urm;
5. Dac p este un nod al listei i q un pointer ctre tipul nod, care dintre secvenele de
instruciuni urmtoare realizeaz corect legturile astfel nct s se elimine din list
DA

cele dou noduri care urmeaz dup nodul p?


a. p->urm=p->urm->urm->urm->urm; b. p->urm=p->urm->urm;
c. p->urm->urm=p->urm->urm->urm; d. q=p->urm; p->urm=q->urm->urm;
6. Dac L1 este o list organizat ca stiv, stabilii care este adresa corect de
DI

extragere din stiv:


a. delete p; p=p->urm; b. r=p->urm; p=r; delete p;
c. r=p; p=p->urm; delete p; d. r=p->urm; p=r; delete r;
7. Care dintre urmtoarele secvene de program calculeaz, n variabila k, suma ele-
RA

mentelor din lista simplu nlnuit:


a. for(k=0,p=prim;p!=NULL;p= p->urm) k+= p->info;
b. for(k=0,p=prim; p->urm!=NULL;p= p->urm) k+=p->info;
c . k=0; p=prim; while (p!=NULL) {k+= p->info; p= p->urm;}
TU

d. p=prim; k= p->info;
do {p= p->urm; k+= p->info;} while (p->urm!=NULL);
n urmtorii 7 itemi, variabilele p i q memoreaz adresele de nceput ale listelor
liniare simplu nlnuite nevide L1 i respectiv L2. Elementele listelor sunt de tipul nod.
I
ED

(Bacalaureat Sesiunea iunie-iulie 2003)


154 Implementarea structurilor de date

C
8. Trebuie mutat primul element al listei L1 imediat dup primul element al listei L2, n
rest listele rmnnd neschimbate. Care dintre urmtoarele atribuiri sunt necesare i
n ce ordine se efectueaz? 1) r=q->urm; 2) r=p->urm; 3) q->urm=p; 4) p=r;

I
5) p->urm=r; 6) p->urm =q->urm;

OG
a. 1 6 3 4 b. 1 3 5 c. 2 6 3 4 d. 2 3 6 4
9. Trebuie mutat primul element al listei L1 imediat dup primul element al listei L2, n
rest listele rmnnd neschimbate. Care dintre urmtoarele atribuiri sunt necesare i
n ce ordine se efectueaz? 1) r=q->urm; 2) r=p->urm; 3) q->urm=p; 4) p=r;

AG
5) p->urm=r; 6) p->urm =q->urm;
a. 1 6 3 4 b. 1 3 5 c. 2 6 3 4 d. 2 3 6 4
10. Dac la sfritul executrii secvenei alturate valoarea r=p->urm;
variabilei r este nul, atunci lista L1: while (r!=p && r)

ED
a. are cel puin dou elemente b. este vid r=r->urm;
c. este incorect constituit d. nu este circular
11. Funcia egale(ad1,ad2) returneaz valoarea 1 dac i numai dac informaiile utile
memorate la adresele ad1 i ad2 coincid, altfel returneaz valoarea 0. Secvena

P
alturat calculeaz n variabila ntreag n numrul de elemente din lista L1:
a. distincte consecutive aflate la nceputul listei n=0; r=p;
b. egale consecutive aflate la nceputul listei while (egale(r,p) && r)
I
c. care sunt egale cu primul element {r=r->urm; n++;}
d. care sunt egale dou cte dou
12. Dac L1 este o coad, cu p adresa primului element i u adresa ultimului element, iar
r este adresa unui element ce urmeaz a fi adugat n coad, stabilii care dintre

urmtoarele este o operaie corect de adugare:


a. r=u->urm; u=r; b. r->urm=p; p=r;
IC

c. u->urm=r; u=r; d. r->urm=u; u=r;


13. Pentru a uni listele L1 i L2 plasnd lista L1 n continuarea listei L2, se efectueaz
operaiile:
CT

a. r=q; while (r->urm) {r=r->urm; r->urm=p;}


b. r=p; while (r) r=r->urm; r=q;
c. r=q; while (r->urm) r=r->urm; r->urm=p;
d. r=p; while (r->urm) r=r->urm; r->urm=q;
DA

14. Pentru a determina numrul de elemente ale listei L1 se utilizeaz o variabil


ntreag n astfel:
a. n=0; r=p; while (r->urm) {r=r->urm; n++;}
b. n=0; r=p; while (r) r=r->urm; n++;
DI

c. n=0; r=p; while (r) {r=r->urm; n++;}


d. n=0; r=p; do {n++;} while (r)
n urmtorii 6 itemi, variabilele p i u memoreaz adresa primului, respectiv a ultimului
RA

element al listei liniare simplu nlnuite nevide L. Elementele listelor sunt de tipul nod.
(Bacalaureat Sesiunea august 2003)
15. tiind c L este format din 4 elemente, atunci adresa penultimului element este:
a. p->urm->urm-> b. p->urm->urm c. p->urm d. p->urm->urm->urm
TU

16. Elementele din lista L aflate la adresele q i r sunt vecine (consecutive) n list dac
i numai dac:
a. q->urm == r->urm b. r->urm == q && q->urm == r
c. q->urm == r || r->urm == q d. q == r
I
ED
Informatic 155

C
17. tiind c este definit o funcie cnt astfel nct cnt(a1,a2) returneaz numrul de
elemente situate n list ntre elementele de la adresa a1 i a2 (fr a numra
elementele de la adresele respective), care dintre urmtoarele expresii arat al

I
ctelea este elementul memorat la adresa q n lista L?

OG
a. cnt(p,q)+2 b. cnt(q,u)+2 c. cnt(q,u)+1 d. cnt(p,q)+1
18. Este definit o funcie min astfel nct min(a1,a2) returneaz valoarea 1 dac i
numai dac cel puin unul dintre elementele memorate la adresele a1 i a2 se afl n
lista L i returneaz valoarea 0 n caz contrar. Care dintre urmtoarele expresii are

AG
valoarea 1 dac i numai dac elementul de la adresa q se afl n lista L?
a. min(p,q) b. min(q,u) c. min(p,u) d. min(q,q)
r=p;
19. Un element aflat la adresa q face parte din lista L dac la while (r!=q && r)
sfritul executrii secvenei alturate variabila r are valoarea: r=r->urm;

ED
a. 1 b. p c. q d. NULL / 0
20. Lista L are exact dou elemente dac:
a. p->urm==u b. u->urm==NULL / !u->urm
c. p=u d. p->urm==NULL / !p->urm

P
21. Dac n variabila p este memorat iniial adresa primului nod al unei liste simplu
nlnuite cu cel puin 10 elemente, pentru a obine n variabila p adresa penultimului
nod al listei se execut secvena:
I
a. while (!p) p->urm; b. while (!p->urm) p->urm;
c. while (p->urm->urm) p->urm; d. while (p->urm) p->urm;
(Bacalaureat Sesiunea special 2003)

22. tiind c ntr-o list circular simplu nlnuit cu cel puin dou elemente, adresele p i
q reprezint adresele a dou elemente distincte din list, atunci elementul memorat la
IC

adresa p este succesorul elementului memorat la adresa q n list dac i numai dac:
a. p->urm == q; b. q->urm == p
c. p->urm == q->urm; d. q->urm->urm == p
CT

(Bacalaureat Sesiunea special 2004)


23. Dac ntr-o list circular simplu nlnuit, cu cel puin 4 elemente, se cunoate
adresa p a unui element din list, atunci este accesibil adresa elementului din list
precedent celui aflat la adresa p?
DA

a. Nu.
b. Da, n orice situaie.
c. Da, numai dac p este adresa primului element al listei.
d. Da, numai dac p este adresa ultimului element al listei.
DI

(Bacalaureat Sesiunea iunie-iulie 2004)


24. ntr-o list liniar simplu nlnuit nevid, pentru eliminarea elementului ce urmeaz
dup elementul aflat la adresa p (elementul de la adresa p nu este nici primul, nici
ultimul) un elev utilizeaz trei instruciuni simple (nestructurate). Care dintre instruc-
RA

iunile urmtoare poate fi una dintre cele trei?


a. p->urm->urm = p; b. dispose(p)
c. p->urm = p->urm->urm; d. p->urm = p
(Bacalaureat Sesiunea iunie-iulie 2004)
TU

25. Nodurile unei liste dublu nlnuite rein n cmpurile info, adp i adu o informaie
numeric, adresa nodului precedent i respectiv adresa nodului urmtor. tiind c lista
este corect construit i c dou noduri p i q ale acesteia se nvecineaz, atunci:
a. p->adp==q->adu b. p->adu==q->adu c. p->adu==q d. p->adp==q->adp
I

(Bacalaureat Simulare 2006)


ED
156 Implementarea structurilor de date

C
26. Dac ntr-o list liniar simplu nlnuit adresa de nceput a listei este p, iar adresa de
sfrit este u, atunci transformarea listei n list circular se realizeaz prin instruciunea:
a. p->urm=u b. p=u->urm c. u->urm=p d. u=p->urm

I
(Bacalaureat Sesiunea iunie-iulie 2004)

OG
27. Se consider o list simplu nlnuit ale crei noduri rein n cmpul urm adresa nodului
urmtor al listei sau NULL dac nu exist un nod urmtor. Pentru inserarea unui nod aflat
la adresa p imediat dup un nod al listei aflat la adresa q, se utilizeaz unele dintre urm-
toarele atribuiri: 1) p->urm=q; 2) q->urm=p; 3) p=q->urm; 4) q=p->urm;

AG
5) p->urm =q->urm; 6) q->urm=p->urm;. Stabilii care dintre acestea se utilizeaz
i n ce ordine:
a. 3 6 b. 2 4 c. 5 2 d. 2 3
(Bacalaureat Simulare 2006)

ED
28. Variabila vf memoreaz adresa elementului din vrful stivei. Fiecare element al stivei
memoreaz ntr-un cmp adr adresa urmtorului element din stiv. Variabila q poate
memora adresa oricrui element al stivei. S se realizeze eliminarea elementului din
vrful stivei:
a. q->adr=vf;vf->adr=q;delete q; b. q=vf->adr;vf=q->adr;delete q;

P
c. q=vf;vf=vf->adr; delete vf; d. q=vf;vf=q->adr; delete q;
(Bacalaureat Simulare 2003)
I
29. O list liniar simplu nlnuit cu adresa de nceput memorat n variabila p este
vid dac:
a. *p==NULL / !*p b. p==NULL / !p
c. p!=NULL / p d. *p!=NULL / *p

(Bacalaureat Sesiunea special 2003)


30. ntr-o list dublu nlnuit cu cel puin 4 elemente, fiecare ele-
IC

q=p->adu->adp;
ment reine n cmpul adp i adu adresa elementului prece-
p=q->adu;
dent i respectiv urmtor din list. Dac p reprezint adresa p->adp=NULL;
primului element din list, iar q este de acelai tip cu p, atunci delete q;
CT

secvena alturat realizeaz:


a. interschimbarea primelor dou componente b. eliminarea primului element
c. eliminarea celui de-al doilea element d. eliminarea ultimului element
(Bacalaureat Sesiunea special 2005)
DA

31. ntr-o list dublu nlnuit cu cel puin 4 elemente, fiecare element reine n cmpul
adp i adu adresa elementului precedent i respectiv urmtor din list. Dac p
reprezint adresa primului element din list, atunci p->adu->adu->adp este
a. adresa primului element b. adresa celui de-al doilea element
DI

c. adresa celui de-al treilea element d. adresa celui de-al patrulea element
(Bacalaureat Simulare 2005)
32. ntr-o list circular simplu nlnuit fiecare element reine n cmpul next adresa
RA

elementului urmtor. tiind c, pentru variabila p ce memoreaz adresa unui element


oarecare din list, este adevrat relaia p->next=p, atunci lista este format din:
a. zero componente b. o component c. 2 componente d. minim 3 componente
(Bacalaureat Sesiunea august-septembrie 2005)
TU

33. Dac vf indic ultimul nod al stivei, care dintre urmtoarele expresii trebuie s fie
adevrate, pentru ca stiva s fie vid?
a. vf==NULL b. vf->urm==0
c. vf->urm==NULL d. vf==0
I
ED
Informatic 157

C
34. Dac vf indic ultimul nod al stivei, iar q un pointer ctre tipul nod, care dintre
urmtoarele secvene de instruciuni extrage nodul din vrful stivei?
a. q=vf->urm;vf=q->urm;delete q; b. q=vf;vf=vf->urm;delete q;

I
c. q=vf;vf=q->urm;delete q; d. q=vf;vf=q->urm;delete q;

OG
35. Dac variabila cap memoreaz adresa primului nod din coad i variabila baza
memoreaz adresa ultimului nod din coad, care dintre urmtoarele expresii trebuie
s fie adevrate, pentru a avea o coad vid?
a. baza==NULL b. cap->urm==baza c. cap==baza d. cap==NULL

AG
Miniproiecte:
Observaie: Pentru realizarea urmtoarelor miniproiecte se va lucra n echip. Profe-
sorul va numi conductorii de proiect, le va distribui proiectele i le va aloca un buget pentru

ED
realizarea lor (pentru simplificare, bugetul va fi folosit numai pentru plata membrilor echipei
care vor realiza proiectul). Conductorii de proiect vor negocia cu profesorul termenul de
predare a aplicaiei, echipa cu care o vor realiza, i, dac este cazul, bugetul care li s-a
alocat iniial. Pe timpul realizrii aplicaiilor, membrii echipelor pot migra de la o echip la

P
alta, cu condiia s rmn ncadrai ntr-una dintre echipe, iar migraia s se fac numai cu
acceptul conductorilor echipelor ntre care migreaz. Fiecare echip va fi format din:
Conductorul proiectului i va forma echipa i va distribui sarcinile pentru fiecare
I
membru, negociind iniial suma repartizat din bugetul alocat pentru realizarea sarcinii. Va
fixa termene de execuie pentru fiecare membru al echipei i va urmri modul n care sunt
respectate aceste termene. n cazul n care unul dintre membrii echipei nu i realizeaz
corect i la timp sarcinile, va redistribui o parte dintre sarcini ntre ceilali membri ai echipei,

renegociind suma din buget alocat fiecruia dintre ei. La sfrit, va da calificative fiecrui
membru al echipei, n funcie de modul n care i-au respectat termenele, de modul n
IC

care au cooperat cu ceilali membrii ai echipei i de calitatea lucrrilor executate.


Analistul va analiza cerinele informaionale ale aplicaiei, va determina funciile apli-
CT

caiei i va elabora modul de rezolvare (datele i structurile de date folosite, procesele


n care este descompus aplicaia care vor fi implementate cu subprograme i
meniul care asigur interfaa cu utilizatorul). n realizarea acestor sarcini va fi ajutat i
ndrumat de conductorul proiectului.
DA

Grupul de programatori (numrul lor trebuie s fie stabilit n funcie de dimensiunea


proiectului) va implementa n limbajul de programare soluia gsit de analistul echipei.
Conductorul proiectului le va repartiza subprogramele pe care le vor realiza i specifica-
iile fiecrui subprogram: datele de intrare, datele de ieire i funcia subprogramului.
DI

Testorul va testa aplicaia. El va trebui s aleag seturi de date de intrare astfel nct
s gseasc erorile de logic i de execuie ale aplicaiei.
Documentaristul va ntocmi documentaiile aplicaiei: documentaia pentru beneficiar
i documentaia pentru proiectantul aplicaiei.
RA

La terminarea proiectului membrii echipelor vor primi note pentru evaluarea activitii lor.
Sistemul de evaluare trebuie s in cont de veniturile realizate pentru munca depus, de
calificativul obinut de la conductorul de proiect i de calitatea muncii evaluat de profesor.
TU

1. Pentru biblioteca colii sunt aduse cri de la mai multe edituri. Crile trebuie organizate
n ordinea alfabetic a autorilor, i pe fiecare autor n ordinea alfabetic a titlurilor. Este
posibil ca pentru acelai autor i acelai titlu s se primeasc mai multe exemplare. Se
va folosi cte o stiv pentru fiecare autor, n care se va simula teancul de titluri primite,
I

pentru fiecare titlu memorndu-se i numrul de exemplare. Numele autorilor i adresa


ED
158 Implementarea structurilor de date

C
vrfului stivei de cri asociate se vor memora ntr-o list ale crei elemente conin n
informaia util dou cmpuri: un cmp de tip ir de caractere pentru numele autorului i
un cmp de tip pointer cte tipul nod al stivei pentru vrful stivei. Scriei o aplicaie care

I
s asigure urmtoarele operaii prin intermediul unui meniu:

OG
a. Distribuirea pe autori i titluri a unui teanc de cri sosit de la o editur.
b. Afiarea titlurilor i a numrului de exemplare ale unui autor al crui nume se citete
de la tastatur.
c. Afiarea n ordine alfabetic a autorilor i a numrului de titluri i de exemplare

AG
pentru fiecare autor.
d. Numele autorilor cu cele mai multe, respectiv cu cele mai puine titluri.
e. Numele autorilor cu cele mai multe, respectiv cu cele mai puine exemplare.
2. La un concurs particip mai muli candidai identificai dup nume i prenume. Fiecare

ED
candidat primete la nscriere un numr de identificare. Concursul const n trei probe,
notele putnd lua valori de la 1 la 10. Rezultatul concursului se stabilete pe baza medi-
ei aritmetice a notelor primite. Trebuie prevzute dou variante de admitere a candida-
ilor: sunt admii toi candidaii care au o medie mai mare dect m i sunt admii, n

P
ordinea mediilor, primii k candidai (valorile pentru m i k se citesc de la tastatur).
Scriei o aplicaie care s asigure urmtoarele operaii prin intermediul unui meniu:
a. nscrierea unui nou candidat la concurs.
I
b. Retragerea unui candidat din concurs.
c. Completarea notelor i calcularea mediei pentru fiecare candidat.
d. Modificarea informaiilor despre un candidat.
e. Afiarea candidailor admii n fiecare dintre cele dou variante n ordinea descres-

ctoare a mediilor.
IC

f. Afiarea candidailor admii n fiecare dintre cele dou variante n ordinea alfabetic
a numelui i prenumelui.
3. ntr-un depou exist o linie pe care se gsesc mai multe locomotive, aranjate n ordinea
CT

n care au intrat n depou, i o linie pe care se


gsesc mai multe vagoane, aranjate n ordinea n
care au intrat n depou. Fiecare locomotiv i ieire
fiecare vagon are un numr de identificare. n plus,
DA

pentru fiecare vagon este precizat i clasa (clasa


1 i clasa 2). Pentru linia care conine locomotivele
exist un triaj cu k linii de manevr. Valoarea
pentru k se citete de la tastatur. n triajul vagoa-
DI

nelor exist o linie de intrare i o linie de ieire pe care depla-


sarea se poate face numai n sensul sgeilor i o linie de
ma-nevr pe care deplasarea se poate face n ambele ieire
sensuri. Scriei o aplicaie care s asigure urmtoarele
RA

operaii prin inter-mediul unui meniu:


a. Intrarea unei locomotive n depou.
b. Afiarea locomotivelor din depou.

c. Intrarea unui vagon n depou.
TU

d. Afiarea vagoanelor din depou, precizndu-se cte


vagoane sunt de clasa 1 i cte sunt de clasa 2.
e. Formarea unei garnituri. Garnitura este format dintr-o
locomotiv cu numrul de iden-tificare p i n vagoane, dintre care m vagoane sunt de
I
ED

clasa 1 (valorile pentru p, n i m se citesc de la tastatur).


Informatic 159

C
2.7. Graful

I
2.7.1. Definiia matematic a grafului

OG
Se numete graf (G) o pereche ordonat de mulimi (X,U), unde X este o mulime finit i
nevid, iar U o mulime de perechi formate cu elemente distincte din mulimea X (familie
de submulimi cu dou elemente din mulimea X).

AG
Terminologie:
Elementele mulimii X se numesc vrfuri sau noduri. Mulimea X se mai numete i
mulimea vrfurilor sau mulimea nodurilor grafului G. Ea este de forma:

ED
X = {x1, x2, x3, ..., xi, ..., xn}
unde xi reprezint nodul i al grafului G care are n noduri.
Ordinul grafului reprezint numrul de noduri ale grafului, n:

P
ordinul grafului = card(X) = n
Elementele mulimii U sunt perechi de noduri, adic submulimi cu dou elemente din
I
mulimea X i se noteaz cu uk. Elementul uk este definit de perechea de forma {xi, xj},
unde xi, xj X i xixj (elemente distincte din mulimea X). Elementul uk leag nodurile xi
i xj i se noteaz astfel: [xi, xj]. Mulimea U este de forma:

U={u1, u2, u3, ..., uk, ..., um}


Clasificarea grafurilor:
IC

Criteriul de clasificare folosit este proprietatea de simetrie a mulimii U.


Mulimea U are proprietatea de simetrie dac i numai dac,
CT

pentru orice pereche de noduri (xi, xj), dac {xi, xj}U, atunci i {xj, xi}U
n funcie de proprietatea de simetrie, grafurile se clasific n:
Grafuri neorientate. Un graf G=(X,U) este un graf neorientat dac mulimea U are
DA

proprietatea de simetrie. Mulimea U este format din perechi neordonate {xj, xi}.
Grafuri orientate. Un graf G=(X,U) este un graf orientat dac mulimea U nu are
proprietatea de simetrie. Mulimea U este format din perechi ordonate {xj, xi}.
Pentru a identifica tipul de graf pe care l vei folosi pentru a reprezenta datele, definii rela-
DI

ia dintre nodurile grafului i verificai dac relaia are proprietatea de simetrie, astfel:
Dac nodul x n relaie cu nodul y implic i c nodul y este n relaie cu nodul x, atunci
graful este neorientat.
RA

Dac nodul x n relaie cu nodul y nu implic i c nodul y este n relaie cu nodul x,


atunci graful este orientat.
TU

Scop: identificarea tipului de graf pe care l folosii pentru a rezolva problema.


Enunul problemei 1. Pe harta unui jude exist mai multe localiti care sunt legate prin
osele pe care se circul n ambele sensuri. S se identifice traseele pe care se poate
I

ajunge de la localitatea A la localitatea B.


ED
160 Implementarea structurilor de date

C
Nodurile grafului sunt localitile. Relaia care se stabilete ntre nodurile grafului este:
nodul x este n relaie cu nodul y, dac exist o osea care leag direct localitatea asociat
nodului x cu localitatea asociat nodului y. Relaia are proprietatea de simetrie, deoarece

I
oseaua care leag direct localitatea asociat nodului x cu localitatea asociat nodului y

OG
leag direct i localitatea asociat nodului y cu localitatea asociat nodului x. Pentru
reprezentarea cilor de comunicaie dintre localiti se va folosi un graf neorientat.
Enunul problemei 2. Pe harta unui cartier exist mai multe intersecii care sunt legate
de strzi. Pe unele strzi se poate circula n ambele sensuri, pe alte strzi numai ntr-un

AG
anumit sens. S se identifice traseele prin care se poate ajunge de la intersecia A la
intersecia B.
Nodurile grafului sunt interseciile. Relaia care se stabilete ntre nodurile grafului este: nodul
x este n relaie cu nodul y, dac exist trafic care leag direct intersecia asociat nodului x

ED
cu intersecia asociat nodului y (se poate circula de la nodul x la nodul y). Relaia nu are
proprietatea de simetrie deoarece, dac exist o strad care leag direct intersecia asociat
nodului x cu intersecia asociat nodului y i pe aceast strad exist trafic de la nodul x la
nodul y, nu este obligatoriu ca pe acea strad s existe trafic i de la nodul y la nodul x.

P
Pentru reprezentarea traficului auto dintre intersecii se va folosi un graf orientat.
Enunul problemei 3. La nivelul unui grup de persoane se face un studiu social. ntre
persoane se stabilesc relaii de prietenie, dar i relaii de simpatie. S se descrie cu
I
ajutorul grafului relaiile dintre persoane.
Nodurile grafului sunt membrii grupului de persoane. ntre persoane se pot stabili relaiile:
Relaia de prietenie este o relaie definit astfel: persoana x este n relaie cu persoana

y, dac este prieten cu ea. Relaia este simetric deoarece, dac persoana x este
prieten cu persoana y, atunci i persoana y este prieten cu persoana x (relaia de
IC

prietenie presupune reciprocitate). Pentru reprezentarea relaiilor de prietenie dintre


membrii grupului se va folosi un graf neorientat.
Relaia de simpatie este o relaie definit astfel: persoana x este n relaie cu persoana
CT

y, dac o simpatizeaz. Relaia nu este simetric deoarece, dac persoana x


simpatizeaz persoana y, nu este obligatoriu ca persoana y s simpatizeze persoana x
(relaia de simpatie nu presupune reciprocitate). Pentru reprezentarea relaiilor de
DA

simpatie dintre membrii grupului se va folosi un graf orientat.


1. Prin ce tip de graf va fi reprezentat un grup de persoane ntre care
Tem s-au stabilit relaii de vecintate?
2. Prin ce tip de graf va fi reprezentat un grup de persoane ntre
DI

care s-au stabilit relaii de cunotin?

2.7.2. Graful neorientat


RA

2.7.2.1. Terminologie
Elementele mulimii U (perechile de noduri) se numesc muchii. Mulimea U se mai
numete i mulimea muchiilor grafului G. O muchie, fiind un element din mulimea U,
TU

este determinat de o submulime cu dou elemente din mulimea X: muchia k a


grafului (uk), care unete nodurile xi i xj, este determinat de submulimea {xi, xj} i se
noteaz cu [xi, xj]. [xi, xj] i [xj, xi] reprezint aceeai muchie a grafului. Graful G are
m muchii:
I
ED

numrul de muchii = card(U) = m


Informatic 161

C
Numim noduri adiacente orice pereche de noduri care formeaz o muchie {xi,xj}U.
Fiecare dintre cele dou noduri (xi i xj) este nod incident cu muchia uk = [xi,xj].
Nodurile vecine unui nod xi sunt toate nodurile xj care sunt adiacente cu el.

I
Se numete nod extrem al unei muchii oricare dintre cele dou noduri care se gsesc

OG
la captul muchiei. Nodurile xi i xj sunt extremitile muchiei [xi, xj].
Se numesc muchii incidente dou muchii ui i uj care au o extremitate comun
nodul xk.
Un graf neorientat G este definit de o pereche de mulimi:

AG
mulimea nodurilor sale X i mulimea muchiilor sale U. El poate fi considerat ca
o mulime de noduri din care unele pot fi unite dou cte dou printr-o muchie.
Graful se reprezint n plan prin intermediul unor elemente geometrice: nodurile se
reprezint prin cercuri, iar muchiile prin linii drepte care unesc anumite cercuri.

ED
Nodul xi al grafului G

Muchia uk=[xi,xj] a grafului G

Nodul xj al grafului G
P
I
Elementele mulimii X (nodurile) se identific cu ajutorul unor etichete, care pot fi numere
sau litere. Pentru simplificare, vom folosi ca etichete un ir de numere consecutive,
ncepnd cu numrul 1. De exemplu, pentru un graf cu n noduri, vom folosi etichetele: 1, 2,
3, , n-1, n. O muchie se va nota cu [i,j], unde i i j sunt etichetele nodurilor incidente cu

muchia. De exemplu, muchia [2,3] este muchia care unete nodurile cu etichetele 2 i 3.
IC

Exemplul 1:
n graful G1=(X1,U1) din figura 1: G
G
G111
Ordinul grafului este 8.
CT

Graful are 8 noduri (n=8) i mulimea nodurilor este


X1={1,2,3,4,5,6,7,8}.
Graful are 9 muchii (m=9) i mulimea muchiilor este Fig. 1
DA

U1={[1,2], [1,3], [1,4], [2,3], [2,5], [3,4], [3,5], [6,7], [6,8] }.


Nodul 1 este nod adiacent cu nodurile 2, 3 i 4, iar nodul 6 este adiacent cu nodurile 7
i 8. Nodurile 3 i 4 sunt adiacente deoarece perechea de noduri [3,4]U1. Nodurile 5 i
6 nu sunt adiacente deoarece perechea de noduri [5,6]U1.
DI

Nodul 5 este nod incident cu muchiile [2,5] i [3,5], dar nu este incident cu muchia [1,2].
Nodul 3 este nod extrem muchiilor [1,3], [2,3], [3,4] i [3,5].
Muchiile [1,2] i [2,3] sunt muchii incidente deoarece au un nod comun (nodul 2).
Muchiile [1,4] i [2,3] nu sunt muchii incidente deoarece nu au un nod comun.
RA

Teorema 1
Dac graful neorientat G are n noduri (x1, x2, ..., xn), atunci numrul total de grafuri
neorientate care se pot forma cu aceste noduri este g:
TU

2
Cn
g2
Demonstraie. Notm cu X mulimea nodurilor grafului, cu U mulimea muchiilor, cu A mulimea
tuturor submulimilor de dou elemente din X i cu B mulimea {0,1}. Mulimea A are urmtoarele
I

elemente (submulimi):
ED
162 Implementarea structurilor de date

C
[1,2],
[1,3], [1,4], , [1,n] n-1 submulimi
[2,3], [2,4], , [2,n] n-2 submulimi

I
[n-1,n] 1 submulime

OG
n (n 1)
Numrul total de submulimi este: (n 1) (n 2) ... 1 C n2
2
Notm cu a card(A) i cu b card(B). Fiecrui graf i putem asocia o 1, dac [x,y] U
funcie f:AB definit alturat. Invers, unei funcii f:AB i putem f(x,y) =

AG
ataa un graf, astfel: f(x,y)=1 dac i numai dac [x,y]U. Rezult 0, dac [x,y] U
c numrul total de grafuri care se pot forma cu n noduri este egal cu
a
numrul de funcii f. Dar, numrul de funcii f:AB este egal cu b , unde b=2 i a= C n2

ED
1. n graful G1 cu ce noduri este adiacent nodul 1?
Tem 2. n graful G1 cu ce muchii este incident nodul 1?
3. Dai exemple de dou noduri adiacente i de dou noduri care nu
sunt adiacente n graful G1.

P
4. Dai exemplu de dou muchii incidente i de dou muchii care nu sunt incidente n
graful G1.
G
G
G222 5. Desenai graful G2=(X2, U2) definit astfel:
I
X2={1,2,3,4,5,6,7,8}
U2={[1,2], [1,3], [1,5], [2,3], [2,5], [3,4], [4,5], [4,6], [4,7] }.
6. Desenai graful traseelor rutiere care fac legtura ntre localitile Braov, Bucureti,
Buzu, Ploieti i Constana. Dac exist mai multe trasee rutiere ntre dou localiti

(de exemplu, Bucureti i Braov), adugai la graf noduri pentru localitile care
IC

identific unic aceste trasee (de exemplu, Vlenii de Munte, Trgovite i Piteti).
7. Desenai graful judeelor din Romnia (ntre dou judee exist o muchie dac cele
dou judee sunt nvecinate).
CT

8. Cte grafuri se pot construi cu 3 muchii? Desenai toate grafurile care


se pot construi cu 3 muchii.
G
G
G333 9. Pentru graful G3 din figura 2, precizai ordinul, numrul de noduri,
numrul de muchii i mulimile X3 i U3.
DA

10. Structura unei molecule de substan chimic poate fi reprezentat Fig. 2


printr-un graf neorientat, n care nodurile sunt atomii i gruprile din
care este compus molecula, iar muchiile sunt legturile dintre ele.
n figura 3 este prezentat graful moleculei de ap H2O. Repre-
DI

zentai grafurile moleculelor de H2SO4, NH3, CH4 i C2H4.

2.4.2.2. Gradul unui nod al grafului neorientat Fig. 3


RA

Nodul unui graf este caracterizat prin grad.


Gradul unui nod xk al grafului G este egal cu numrul muchiilor incidente
cu nodul i se noteaz cu d(xk).
TU

Terminologie:
Se numete nod terminal un nod care are gradul egal cu 1 d(xk) = 1 (este incident
cu o singur muchie).
Se numete nod izolat un nod care are gradul egal cu 0 d(xk) = 0 (nu este adiacent
I

cu nici un alt nod al grafului, adic nu se gsete n extremitatea nici unei muchii).
ED
Informatic 163

C
Exemplul 1:
G
G
G444
Graful G4=(X4,U4) din figura 4 este definit astfel:
X4={1,2,3,4,5,6,7,8,9,10,11}

I
U4={[1,2], [1,4], [2,3], [2,5], [3,4], [3,5], [5,6], [5,7], [5,8],

OG
[7,9] }. Fig. 4
n graful G4:
Gradul nodului 5 este 5, deoarece are 5 muchii incidente: [2,5], [3,5], [5,6], [5,7] i [5,8].
Nodul 9 este nod terminal, deoarece are gradul 1 (o singur muchie incident: [7,9]).

AG
Nodul 10 este nod izolat, deoarece are gradul 0 (nicio muchie incident).
Exemplul 2:
Fie graful G5=(X5,U5), unde X5={1,2,3,4,5,6,7,8} i U5={[1,2], [1,5], [2,3], [2,5], [3,4], [3,5], [4,5], G
G
G555

ED
[4,6], [4,7]}. Din lista muchiilor unui graf neorientat, putei preciza urmtoarele informaii:
Determinai gradul unui nod numrnd de cte ori apare eticheta nodului n lista de mu-
chii. Nodul 5 are gradul 3 (n mulimea muchiilor, eticheta 5 apare de 3 ori: [1,5], [2,5], [3,5]).
Determinai dac un nod este terminal verificnd dac eticheta lui apare o singur

P
dat. Nodul 7 este nod terminal (eticheta lui apare numai ntr-o singur muchie: [4,7]).
Determinai dac un nod este izolat verificnd dac eticheta lui nu apare n lista de
muchii. Nodul 8 este nod izolat (eticheta lui nu apare n lista muchiilor).
I
Determinai numrul de noduri izolate (n1) astfel: numrai etichetele distincte care
apar n lista muchiilor (n2) i n1=n-n2. n graful G5, n lista de muchii exist 7 etichete
distincte. Numrul de noduri izolate este 1 (8-7).

Observaie: ntr-un graf cu n noduri, oricare ar fi nodul xk, gradul su este mai mare sau
egal cu 0 i mai mic sau egal cu n-1 (0d(xk)n-1).
IC

1. n graful G4: precizai gradul nodului 3 i identificai nodul cu gradul cel


Tem mai mare, nodurile izolate i nodurile terminale.
CT

2. n graful G3: identificai nodurile care au gradul 2, precizai cte noduri


au gradul impar i care este nodul cu gradul cel mai mare.
3. n graful G5: precizai gradul nodului 3, identificai nodurile izolate i nodurile terminale,
precizai cte noduri au gradul 2 i cte noduri au gradul impar.
DA

Teorema 2
Dac graful G are m muchii (u1, u2, ..., um) i n noduri (x1, x2, ..., xn), atunci ntre gradul
nodurilor i numrul de muchii exist urmtoarea relaie: suma gradelor tuturor nodurilor
DI

grafului este egal cu dublul numrului de muchii:


n
d(x i ) 2 m
i 1
RA

Demonstraie. Fiecare muchie uk = [xi, xj] corespunde unei uniti din gradul nodului xi i unei uniti
din gradul nodului xj. Rezult c fiecare muchie contribuie cu 2 uniti la suma gradelor.
Exemplu. n graful G4: d(1) + d(2) + d(3) + d(4) + d(5) + d(6) + d(7) + d(8) + d(9) + d(10) +
d(11) = 2+2+3+2+4+1+2+1+1+0+0 = 18 = 29 = 2m
TU

Propoziia 1. Pentru orice graf G, numrul nodurilor de grad impar este par.
Demonstraie. Suma gradelor nodurilor fiind un numr par, aceast sum trebuie s conin un
numr par de termeni care sunt numere impare.
I

Exemplu. n graful G3 exist 4 noduri cu grad impar (3, 6, 8 i 9).


ED
164 Implementarea structurilor de date

C
Propoziia 2. Numrul minim de muchii, mmin, pe care trebuie s le aib un graf neorientat,
cu n noduri, ca s nu existe noduri izolate, este:
n 1
m min

I

2

OG
Demonstraie. Pentru ca un nod xi s nu fie izolat, trebuie ca d(xi)1. Pentru ca toate nodurile s nu
fie izolate, trebuie ca suma gradelor s fie mai mare sau egal cu n. Dar, suma gradelor este dublul
numrului de muchii m. nseamn c, pentru n par mmin=n/2, iar pentru n impar mmin=(n+1)/2.
Teorema 3

AG
Dac graful G are n noduri (n2), atunci cel puin dou noduri au acelai grad.
Demonstraie prin reducere la absurd. Presupunem c nu este adevrat. Cum, oricare ar fi nodul
xk, 0d(xk)n-1, nseamn c singurul ir de n numere, diferite ntre ele dou cte dou, care pot

ED
reprezenta gradele unghiurilor este 0, 1, 2, , n-1. Deoarece un nod este izolat, cel mai mare grad al
unui nod nu poate fi dect n-2 (nodul nu se poate lega de el nsui i de nodul izolat). Rezult c irul
de numere definit mai sus (singurul ir care se poate defini) nu poate reprezenta irul gradelor n graf.
1. n graful G1 verificai c este ndeplinit relaia dintre gradul nodurilor

P
Tem i numrul de muchii ale grafului. Identificai nodurile cu grad impar i
verificai c numrul lor este par.
2. Dac un graf are 8 noduri, care este numrul minim de muchii pe care trebuie s le
I
aib, ca s nu fie noduri izolate. Desenai un graf care, avnd numrul minim de muchii
stabilit, nu conine noduri izolate. Dac un graf are 9 noduri, care este numrul minim de
muchii pe care trebuie s le aib, ca s nu fie noduri izolate. Desenai un graf care

avnd numrul minim de muchii stabilit nu conine noduri izolate.


IC

2.7.2.3. irul grafic


Se numete ir grafic un ir s de n numere ntregi pozitive (d1, d2, ..., dn) care pot
CT

reprezenta gradele unui graf neorientat, cu n noduri.


Propoziia 3
Condiiile necesare ca un ir de n numere ntregi pozitive (d1, d2, ..., dn)
DA

s fie un ir grafic sunt:


(1) di n-1, pentru orice i=1,n;
(2) suma d1 + d2 + ... + dn trebuie s fie un numr par.
Demonstraie. Necesitatea condiiei (1) rezult din faptul c gradul maxim al unui nod dintr-un graf cu
DI

n noduri poate fi n-1. Necesitatea condiiei (2) rezult din Teorema 2 suma gradelor fiind egal cu
dublul numrului de muchii, este un numr par.
Aceste condiii nu sunt ntotdeauna i suficiente. Pentru a verifica dac irul de
RA

numere este ir grafic, se face analiza irului de numere.


Exemple:
(a) s=(1,1,2,3,3,4,5,5,7,8)
Acest ir nu ndeplinete una dintre condiiile necesare (2) suma numerelor este 39.
TU

(b) s=(1,1,1,2,2,3,5,6,8,9)
Acest ir ndeplinete condiiile necesare (suma numerelor este 38 i fiecare numr este
mai mic sau egal cu 9: 9=10-1). Aceste condiii nu sunt ns suficiente. Din analiza irului
rezult c nodul 10, avnd gradul 9, este legat de toate celelalte 9 noduri. Nodurile 1, 2 i
I

3 sunt noduri terminale. Ele nu pot fi legate dect de nodul 10. Rezult c gradul maxim
ED
Informatic 165

C
pe care l poate avea oricare dintre celelalte ase noduri este 6 (ele nu se pot lega de ele
nsele i de nodurile 1, 2 i 3). Dar nodul 9 are gradul 8, ceea ce este imposibil.
(c) s=(1,1,1,2,3,4,5,6,6,9)

I
i acest ir ndeplinete condiiile necesare (suma numerelor este 38 i fiecare numr

OG
este mai mic sau egal cu 9). n plus, fa de irul (b), avnd aceleai grade pentru
nodurile 1, 2, 3 i 10, ndeplinete i condiia ca celelalte noduri s aib gradul mai mic
sau egal cu gradul maxim posibil (6). Dar, exist dou noduri cu gradul 6. Ele trebuie s
se lege amndou de nodul 4, la care este legat i nodul 10. Nodul 4 trebuie s aib cel

AG
puin gradul 3. Dar nodul 4 are gradul 2, ceea ce este imposibil.
(d) s=(1,1,1,3,3,4,4,5,5,9)
Acest ir ndeplinete condiiile necesare (suma numerelor este 38 i fiecare numr este
mai mic sau egal cu 9) i este un ir grafic cruia i se poate asocia graful G6=(X6,U6), cu G G
G666
18 muchii, definit astfel:

ED
X6={1,2,3,4,5,6,7,8,9,10}
U6={[1,10], [2,10], [3,10], [4,8], [4,9], [4,10], [5,8], [5,9], [5,10], [6,7], [6,8], [6,9], [6,10],
[7,8], [7,9], [7,10], [8,10], [9,10]}.

P
Precizai dac irurile s1=(1,1,2,2,4) i s2=(0,1,1,1,4) pot fi iruri grafice.
Tem Pentru irul care este ir grafic, gsii un graf care i se poate asocia.
I
2.7.3. Graful orientat
Spre deosebire de graful neorientat, n graful orientat perechile de noduri sunt ordonate.

Graful orientat se mai numete i digraf.


IC

2.7.3.1. Terminologie
Elementele mulimii U (perechile de noduri) se numesc arce. Mulimea U se mai nume-
te i mulimea arcelor grafului G. Un arc, fiind un element din mulimea U, este
CT

determinat de o submulime ordonat, cu dou elemente, din mulimea X: arcul k al


grafului (uk), ce unete nodurile xi i xj, este determinat de submulimea {xi,xj} i se
noteaz cu [xi, xj]. [xi, xj] i [xj, xi] nu reprezint acelai arc al grafului. Graful G are
DA

m arce:
numrul de arce = card(U) = m
Se numesc noduri adiacente n graful G oricare din perechile de noduri care formeaz
un arc (xi,xj)U sau (xj,xi)U. Fiecare dintre cele dou noduri (xi i xj) este nod
DI

incident cu arcul uk = [xi, xj] sau cu arcul uk = [xj, xi].


Nodurile xi i xj sunt extremitile arcului [xi, xj]. Nodul xi este extremitatea iniial a
arcului, iar nodul xj este extremitatea final a arcului.
RA

Se numesc arce incidente dou arce ui i uj care au o extremitate comun nodul xk.
Se numete succesor al nodului xi orice nod la care ajunge un arc care iese din nodul
xi. Mulimea succesorilor nodului xi este format din mulimea nodurilor la care ajung
arcele care ies din nodul xi. Se noteaz cu S(xi) i se definete ca mulimea:
TU

S(x) = {xj X(xi, xj)U}.


Se numete predecesor al nodului xi orice nod de la care intr un arc n nodul xi.
Mulimea predecesorilor nodului xi este format din mulimea nodurilor de la care
ajung arcele care intr n nodul xi. Se noteaz cu P(xi) i se definete ca mulimea:
I

P(x) = {xj X(xj, xi)U}.


ED
166 Implementarea structurilor de date

C
Mulimea arcelor care ies din nodul xi se noteaz cu U+(xi) i se definete ca mulimea
U+(xi) = {u=(xi, xj)uU}.
Mulimea arcelor care intr n nodul xi se noteaz cu U-(xi) i se definete ca muli-

I
mea U-(xi) = {u=(xj, xi)uU}.

OG
Nodul surs al grafului este nodul care are mulimea succesorilor format din toate
celelalte noduri, mai puin el, iar mulimea predecesorilor si este mulimea vid.
Nodul destinaie al grafului este nodul care are mulimea predecesorilor format din
toate celelalte noduri, mai puin el, iar mulimea succesorilor si este mulimea vid.

AG
Observaii
1. card(S(x))=card(U+(x)) i card(P(x))=card(U-(x)).
2. Pentru nodul surs al grafului card(S(x))=card(X)-1 i card(P(x))=0.

ED
3. Pentru nodul destinaie al grafului card(P(x))=card(X)-1 i card(S(x))=0.
4. Dac un graf are un nod surs, atunci nu poate avea un nod destinaie, i invers.
Un graf orientat G este definit de o pereche de mulimi: mulimea nodurilor sale X
i mulimea arcelor sale U. El poate fi considerat ca o mulime de noduri din care

P
unele pot fi unite dou cte dou, prin unul sau dou arce.
Graful orientat se reprezint n plan prin intermediul unor elemente geometrice: nodurile
I
se reprezint prin cercuri, iar arcele prin linii drepte care unesc anumite cercuri i care au o
sgeat la captul care corespunde extremitii finale a arcului.
Nodul xi al grafului G

Arcul uk=[xi,xj] al grafului G


IC

Nodul xj al grafului G
CT

Exemplu:
G
G
G777 n graful G7=(X7,U7) din figura 5:
Ordinul grafului este 5.
Graful are 5 noduri (n=5) i mulimea nodurilor este X7={1,2,3,4,5}.
DA

Graful are 7 arce (m=7) i mulimea arcelor este U7={[1,2], [1,4],


Fig. 5
[2,3], [4,1], [4,3], [5,2], [5,3] }.
Nodul 1 este nod adiacent cu nodurile 2 i 4, iar nodul 3 este adiacent cu nodurile 2, 4
i 5. Nodurile 3 i 4 sunt adiacente deoarece perechea de noduri [4,3]U7. Nodurile 5 i
DI

4 nu sunt adiacente, deoarece nici una dintre perechile de noduri [4,5] i [5,4] U7.
Nodul 4 este nod incident cu arcele [1,4], [4,1] i [4,3], dar nu este incident cu arcul [1,2].
Nodul 2 este extremitatea iniial a arcului [2,3] i extremitatea final a arcului [1,2] i
[5,2].
RA

Arcele [1,2] i [5,2] sunt arce incidente deoarece au un nod comun (nodul 2). Arcele
[1,4] i [2,3] nu sunt arce incidente, deoarece nu au un nod comun.
Mulimea succesorilor nodului 1 este format din nodurile 2 i 4. Nodul 2 este nod
TU

succesor al nodului 1, dar i al nodului 5. Nodul 1 este nod succesor al nodului 4, dar i
nodul 4 este nod succesor al nodului 1. Nodul 3 nu are succesori.
Mulimea predecesorilor nodului 3 este format din nodurile 2, 4 i 5. Nodul 2 este
nod predecesor al nodului 3. Nodul 1 este nod predecesor al nodului 4, dar i nodul 4
I

este nod predecesor al nodului 1. Nodul 5 nu are predecesori.


ED
Informatic 167

C
Teorema 4
Dac graful orientat G are n noduri (x1, x2, ..., xn), atunci numrul total de grafuri
orientate care se pot forma cu aceste noduri este g:

I
OG
n ( n 1 )
g4 2

3, dac [x,y] U i [y,x] U


Demonstraie. Se demonstreaz la fel ca Teorema 1,
2, dac [x,y] U
cu deosebirea c mulimea B este {0,1,2,3}

AG
f(x,y) =
card(B)=4, iar funcia f este definit alturat.
1, dac [y,x] U
0, dac [x,y] U i [y,x] U

Tem 1. n graful G7 cu ce noduri este adiacent nodul 2?

ED
2. n graful G7 cu ce arce este incident nodul 2?
3. Dai exemplu de dou noduri adiacente n graful G7.
4. Dai exemplu de dou noduri care nu sunt adiacente n graful G7.
5. Dai exemplu de dou arce incidente n graful G7.

P
6. Dai exemplu de dou arce care nu sunt incidente n graful G7.
7. n graful G7 precizai ce fel de extremitate este nodul 4 pentru fiecare arc cu care este
I
incident. Precizai mulimea succesorilor i mulimea predecesorilor nodului 4.
8. Desenai graful G8=(X8,U8), definit astfel. G
G
G888
X8={1,2,3,4,5,6,7}
U8={[1,2], [1,5], [2,1], [2,4], [3,4], [4,3], [5,3], [6,5], [6,7], [7,5] }.

9. Cte grafuri orientate se pot construi cu 3 arce?


Desenai 10 dintre aceste grafuri.
IC

10. Pentru graful G9 din figura 6, precizai ordinul, numrul de G


GG999
noduri, numrul de arce i mulimile X9 i U9.
CT

2.7.3.2. Gradele unui nod al grafului orientat Fig. 6

Nodul unui graf orientat este caracterizat prin gradul intern i gradul extern.
DA

Gradul intern al unui nod xi al grafului G este egal cu numrul arcelor care intr n nodul
-
xi (arce de forma [xj, xi]) i se noteaz cu d (x).
Gradul extern al unui nod xi al grafului G este egal cu numrul arcelor care ies din nodul
xi (arce de forma [xi, xj]) i se noteaz cu d+(x).
DI

Terminologie:
Se numete nod terminal un nod care are suma gradelor egal cu 1 (gradul intern sau
gradul extern egal cu 1 i gradul extern, respectiv gradul intern, egal cu 0 d+(xk) = 1 i
- -
d (xk) = 0 sau d (xk) = 1 i d+(xk) = 0). Nodul terminal este incident cu un singur arc.
RA

Se numete nod izolat un nod care are suma gradelor egal cu 0 (gradul intern i
-
gradul extern egale cu 0 d+(xk) = d (xk) = 0). Nodul izolat nu este adiacent cu nici un
alt nod al grafului, adic nu se gsete la extremitatea niciunui arc.
TU

Observaii:
-
1. d+(x)=card(S(x)) i d (x)=card(P(x)).
-
2. Dac graful are n noduri, pentru un nod surs al grafului d+(x)=n-1 i d (x)=0, iar
- +
pentru un nod destinaie al grafului d (x)=n-1 i d (x)=0.
I
ED
168 Implementarea structurilor de date

C
Exemplul 1:
G
G
G111000 Graful G10=(X10,U10) din figura 7 este definit astfel:
X10={1,2,3,4,5,6,7,8,9,10}

I
U10={[1,2], [1,4], [2,1], [2,3], [2,5], [2,6], [2,7], [4,1],

OG
[7,2], [8,9], [9,8] }.
n graful G10: Fig. 7
Gradul intern al nodului 2 este 2, deoarece are 2 arce
care intr: [1,2] i [7,2]. Gradul extern al nodului 2 este 4, deoarece are 4 arce care ies:

AG
[2,1], [2,3], [2,5] i [2,7].
Nodul 5 este nod terminal deoarece are suma gradelor egal cu 1 (gradul intern este 1
i gradul extern este 0) i un singur arc incident: [2,5]).
Nodul 10 este nod izolat, deoarece are gradul 0 (niciun arc incident).

ED
Exemplul 2:
G
G
G111111 Fie graful G11=(X11,U11), unde X11={1,2,3,4,5,6,7,8} i U11={[1,2], [1,5], [2,1], [2,3], [2,5],
[3,4], [3,5], [4,3], [4,5], [4,6], [4,7], [5,4]}. Din lista arcelor unui graf orientat, putei preciza

P
urmtoarele informaii:
Gradul extern al unui nod numrnd de cte ori apare eticheta nodului n lista de
arce, ca prim element din pereche. Nodul 3 are gradul extern 2 (n mulimea arcelor,
I
eticheta 3 apare de 2 ori ca prim element: [3,4] i [3,5]).
Gradul intern al unui nod numrnd de cte ori apare eticheta nodului n lista de
arce, ca al doilea element din pereche. Nodul 5 are gradul 4 (n mulimea arcelor,
eticheta 5 apare de 4 ori ca al doilea element: [1,5], [2,5], [3,5] i [4,5]).

Mulimea succesorilor unui nod este format din nodurile a cror etichet apare ca al
doilea element n perechile n care primul element este nodul precizat. Mulimea
IC

succesorilor nodului 4 este {3, 5, 6, 7} arcele: [4,3], [4,5], [4,6] i [4,7].


Mulimea predecesorilor unui nod este format din nodurile a cror etichet apare ca
CT

prim element n perechile n care al doilea element este nodul precizat. Mulimea
predecesorilor nodului 3 este {2, 4} arcele: [2,3] i [4,3].
Exemplul 3
G
G
G111222 Fie grafurile G12=(X12,U12), unde X12={1,2,3,4} i U12={[1,2], [1,3], [1,4] [2,3], [3,4], [4,3]}, i
DA

G13=(X13,U13), unde X13={1,2,3,4} i U13={[2,1], [2,3], [3,1], [3,4], [4,1], [4,3]}. Din lista
G
G
G111333 muchiilor unui graf, putei preciza urmtoarele informaii:
Nodul surs al unui graf apare pe primul loc din pereche de n-1 ori i niciodat pe
locul al doilea. n graful G12, nodul 1 este nod surs. Desenai graful G12 pentru a
DI

verifica aceast afirmaie.


Nodul destinaie al unui graf apare pe al doilea loc din pereche de n-1 ori i niciodat
pe primul loc. n graful G13, nodul 1 este nod destinaie. Desenai graful G13 pentru a
RA

verifica aceast afirmaie.


Observaie: ntr-un graf cu n noduri, oricare ar fi nodul xk, oricare dintre gradele sale este
-
mai mare sau egal cu 0 i mai mic sau egal cu n-1 (0d+(xk) n-1 i 0d (xk) n-1).
TU

1. n graful G9 precizai gradul intern i gradul extern ale nodului 5,


Tem identificai nodul cu gradul extern cel mai mare i nodurile cu gradul
intern cel mai mic.
2. n graful G10 identificai nodurile care au gradul intern 1, precizai cte noduri au gradul
I

intern egal cu gradul extern, care sunt nodurile terminale i care sunt nodurile izolate.
ED
Informatic 169

C
3. n graful G11 precizai gradul intern i gradul extern ale nodului 4, identificai nodurile
izolate i nodurile terminale, identificai nodurile care au gradul extern maxim i nodurile
care au gradul intern egal cu gradul extern.

I
OG
Teorema 5
Dac graful orientat G are m arce (u1, u2, ..., um) i n noduri (x1, x2, ..., xn), atunci ntre
gradele nodurilor i numrul de muchii exist urmtoarea relaie: suma gradelor interne
ale tuturor nodurilor este egal cu suma gradelor externe ale tuturor nodurilor i cu

AG
numrul de arce:
n n
d (xi ) d (xi ) m
i 1 i 1

Demonstraie. Fiecare arc uk = [xi, xj] corespunde unei uniti din gradul extern al nodului xi i unei

ED
uniti din gradul intern al nodului xj. Rezult c fiecare arc contribuie cu o unitate la suma gradelor
interne i cu o unitate la suma gradelor externe.
Exemplu. n graful G9: d+(1) + d+(2) + d+(3) + d+(4) + d+(5) + d+(6) = 1+3+1+2+2+1 = 10 i
- - - - - -
d (1) + d (2) + d (3) + d (4) + d (5) + d (6) = 1+2+2+2+2+1 = 10, m fiind egal cu 10.

Tem i numrul de arce ale grafului.


P
n graful G11 verificai c este ndeplinit relaia dintre gradurile nodurilor
I
2.7.4. Reprezentarea i implementarea grafului

Exist mai multe moduri de reprezentare la nivel logic a unui graf, care pot fi implementate n
memoria unui calculator, folosind diverse tipuri de structuri de date. Aceste reprezentri pot fi
IC

folosite n algoritmii care prelucreaz grafuri i, implicit, n programele prin care vor fi imple-
mentai n calculator aceti algoritmi. Printre modurile de reprezentare a unui graf se numr:
reprezentarea prin matricea de adiacen;
CT

reprezentarea prin matricea de inciden;


reprezentarea prin lista muchiilor (arcelor);
reprezentarea prin lista de adiacen (listele vecinilor);
DA

reprezentarea prin matricea costurilor.


Fiecare reprezentare prezint avantaje n ceea ce privete utilizarea eficient a memoriei
interne, n funcie de tipul grafului (cu noduri puine, dar cu muchii multe sau cu noduri
multe, dar cu muchii puine) i din punct de vedere al eficienei algoritmilor de prelucrare
DI

(n funcie de aplicaie). n urmtoarele reprezentri se consider c graful G=(X,U) are n


noduri i m muchii.

2.7.4.1. Reprezentarea prin matricea de adiacen


RA

Matricea de adiacen a unui graf este o matrice ptrat binar de ordinul n (An,n),
ale crei elemente ai,j sunt definite astfel:
1, dac [i, j] U
TU

a i, j 0, dac [i, j] U

Implementarea grafului prin matricea de adiacen se face printr-un tablou bidimensional
(o matrice ptrat cu dimensiunea n), astfel:
I
ED

int a[<n>][<n>];
170 Implementarea structurilor de date

C
Exemple:
Graful neorientat G1
1 2 3 4 5 6 7 8 Graful orientat G9

I
1 0 1 1 1 0 0 0 0 1 2 3 4 5 6

OG
2 1 0 1 0 1 0 0 0 1 0 1 0 0 0 0
3 1 1 0 1 1 0 0 0 2 1 0 1 1 0 0
4 1 0 1 0 0 0 0 0 3 0 0 0 0 1 0
4 0 1 0 0 1 0

AG
5 0 1 1 0 0 0 0 0
6 0 0 0 0 0 0 1 1 5 0 0 1 0 0 1
7 0 0 0 0 0 1 0 0 6 0 0 0 0 1 0
8 0 0 0 0 0 1 0 0

ED
Proprietile matricei de adiacen:
1. Elementele de pe diagonala principal au valoarea 0 din definiia grafului rezult c
orice muchie (arc) [i, j] trebuie s respecte condiia ij.

P
2. n cazul unui graf neorientat, matricea de adiacen este o matrice simetric fa de
diagonala principal, deoarece, dac exist muchia [i, j], atunci exist i muchia [j, i].
I
Aceast reprezentare este recomandat pentru problemele n care se testeaz pre-
zena unei muchii sau a unui arc ntre dou noduri, se calculeaz gradul unui nod
etc. deoarece permite un acces rapid la nodurile i muchiile (arcele) unui graf.

Algoritmi pentru reprezentarea grafurilor folosind matricea de adiacen


Din matricea de adiacen putei obine urmtoarele informaii:
IC

Graf neorientat Graf orientat


Suma elementelor matricei de adiacen este Suma elementelor matricei de adiacen este
CT

egal cu 2m (dublul numrului de muchii). egal cu m (numrul de arce).


Gradul unui nod i este egal cu suma Gradul extern al nodului i este egal cu suma
elementelor de pe linia i (sau cu suma elementelor de pe linia i.
elementelor din coloana i). Gradul intern al nodului i este egal cu suma
DA

elementelor din coloana i.


Nodurile adiacente nodului i sunt nodurile j Succesorii nodului i sunt nodurile j (j=1,n)
(j=1,n) pentru care elementele din linia i sunt pentru care elementele din linia i sunt egale cu
egale cu 1 (a[i][j]=1). Mai pot fi definite ca 1 (a[i][j]=1).
DI

nodurile j (j=1,n) pentru care elementele din Predecesorii nodului i sunt nodurile j (j=1,n)
coloana i sunt egale cu 1 (a[j][i]=1). pentru care elementele din coloana i sunt
egale cu 1 (a[j][i]=1).
Nodurile adiacente nodului i sunt nodurile j
RA

(j=1,n) pentru care elementele din linia i sau


din coloana i sunt egale cu 1 (a[i][j]=1 sau
a[j][i]=1) reuniunea dintre mulimea
succesorilor i mulimea predecesorilor nodului.
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
TU

gradul nodului. cardinalul mulimii de noduri adiacente nodului i.


Muchia [i,j] a grafului reprezint un element al Arcul [i,j] al grafului reprezint un element al
matricei de adiacen care ndeplinete condiia: matricei de adiacen care ndeplinete condiia:
a[i][j] = 1 (sau a[j][i] = 1). a[i][j] = 1
I
ED
Informatic 171

C
Exemplu
Se consider graful din figura alturat. Identificai matricea de adiacen a
grafului.

I
OG
a) 0 1 1 1 b) 0 1 1 1 c) 0 1 1 1 d) 0 1 0 1
1 0 1 0 1 1 1 0 1 0 1 0 1 0 1 0
1 1 0 1 1 1 0 1 1 1 0 0 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0

AG
(Bacalaureat Sesiunea special 2003)
Rspunsul corect este matricea a). Pentru a identifica matricea de adiacen a grafului din
figur, se vor elimina pe rnd variantele incorecte, prin verificarea urmtoarelor condiii:
1. Matricea trebuie s fie binar toate matricele ndeplinesc aceast condiie;

ED
2. Elementele de pe diagonala principal trebuie s aib valoarea 0 matricea b) nu
ndeplinete aceast condiie.
3. Deoarece graful este neorientat, matricea trebuie s fie simetric matricea c) nu
ndeplinete aceast condiie.

P
4. Din analiza grafului se observ c dou noduri au gradul 2 i dou noduri au gradul
3; n matricea de adiacen trebuie s existe dou linii care s conin dou ele-
mente cu valoarea 1 i dou linii care s conin trei elemente cu valoarea 1
I
matricea d) nu ndeplinete aceast condiie.
1. Scriei matricea de adiacen a grafului G4. Folosind informaiile din
Tem matricea de adiacen, determinai: gradul nodului 5, nodurile izolate

i nodurile terminale.
2. Scriei matricea de adiacen a grafului neorientat G14=(X14,U14), unde X14={1,2,3,4} i
IC

U14={[1,2], [2,3], [3,4], [4,1]}. Ce proprietate are acest graf? G


G
G111444
3. Scriei matricea de adiacen a grafului G8. Folosind informaiile din matricea de adia-
CT

cen, determinai: gradul intern al nodului 5, gradul extern al nodului 4, succesorii i


predecesorii nodului 2 i predecesorii nodului 3.
4. Scriei matricea de adiacen a grafului G11. Folosind informaiile din matricea de
adiacen, determinai: gradul intern al nodului 5, gradul extern al nodului 2, nodurile
DA

adiacente nodului 5, succesorii i predecesorii nodului 4,


nodurile terminale i nodurile izolate.
5. Scriei matricea de adiacen a grafului orientat G15 din
figura 8.
G
G
DI

6. Scriei matricea de adiacen a grafului G12. Cum iden- G111555


tificai n matricea de adiacen nodul surs al grafului?
7. Scriei matricea de adiacen a grafului G13. Cum Fig. 8
identificai n matricea de adiacen nodul destinaie al grafului?
RA

Implementarea algoritmilor pentru reprezentarea grafurilor cu matricea de adiacen


1. Crearea matricei de adiacen prin introducerea datelor de la tastatur. Deter-
minarea gradului unui nod. Salvarea matricei de adiacen ntr-un fiier text.
TU

Se citesc de la tastatur muchiile (arcele) unui graf orientat (neorientat), se creeaz matri-
cea de adiacen a grafului, se afieaz nodurile izolate i terminale i se salveaz matri-
cea de adiacen n fiierul text graf1.txt, pentru graful neorientat, i graf2.txt, pentru graful
orientat. n fiierul text se scriu, pe primul rnd, ordinul grafului, i pe urmtoarele rnduri,
I
ED

liniile matricei de adiacen. Funcia scrie() se folosete pentru a scrie matricea de


172 Implementarea structurilor de date

C
adiacen n fiier. Deoarece matricea de adiacen a fost declarat ca variabil global,
elementele ei sunt iniializate cu valoarea 0. Pentru testarea programelor se folosesc
graful neorientat G1 i graful orientat G9.

I
Graful neorientat. Funcia grad() se folosete pentru a determina gradul unui nod.

OG
#include<fstream.h>
int a[10][10],n,m;
fstream f("graf1.txt",ios::out);
void scrie()

AG
{int i,j; f<<n<<endl;
for(i=1;i<=n;i++)
{for (j=1;j<=n;j++) f<<a[i][j]<<" "; f<<endl;}
f.close();}
int grad(int i)

ED
{int j,g=0;
for (j=1;j<=n;j++) g+=a[i][j]; return g;}
void main()
{int i,j,k;

P
cout<<"numar de noduri "; cin>>n; cout<<"numar de muchii "; cin>>m;
for(k=1;k<=m;k++)
{cout<<"primul nod al muchiei "<<k<<": "; cin>>i;
I
cout<<"al doilea nod al muchiei "<<k<<": "; cin>>j;
a[i][j]=1; a[j][i]=1;}
cout<<"Nodurile izolate sunt: ";
for(i=1;i<=n;i++) if (grad(i)==0) cout<<i<<" ";

cout<<endl<<"Nodurile terminale sunt: ";


for(i=1;i<=n;i++) if (grad(i)==1) cout<<i<<" ";
IC

scrie();}
Graful orientat. Funcia grad int()se folosete pentru a determina gradul intern al unui
nod, iar funcia grad_ext()se folosete pentru a determina gradul extern al unui nod.
CT

#include<fstream.h>
int a[10][10],n,m;
fstream f("graf2.txt",ios::out);
void scrie() {//este identic cu cea de la graful neorientat}
DA

int grad ext(int i)


{int j,g=0;
for (j=1;j<=n;j++) g+=a[i][j]; return g;}
int grad int(int i)
DI

{int j,g=0;
for (j=1;j<=n;j++) g+=a[j][i]; return g;}
void main()
{int i,j,k;
RA

cout<<"numar de noduri "; cin>>n; cout<<"numar de arce "; cin>>m;


for(k=1;k<=m;k++)
{cout<<"nodul initial al arcului "<<k<<": "; cin>>i;
cout<<"nodul final al arcului "<<k<<": "; cin>>j; a[i][j]=1;}
TU

cout<<"Nodurile izolate sunt: ";


for(i=1;i<=n;i++) if (grad int(i)+grad ext(i)==0) cout<<i<<" ";
cout<<endl<<"Nodurile terminale sunt: ";
for(i=1;i<=n;i++) if (grad int(i)+grad ext(i)==1) cout<<i<<" ";
scrie();}
I
ED
Informatic 173

C
2. Crearea matricei de adiacen prin citirea datelor din fiier. Determinarea num-
rului de vecini ai unui nod. Afiarea muchiilor (arcelor) grafului.
Se citesc din fiierele text create anterior matricele de adiacen ale celor dou grafuri

I
graf1.txt, respectiv graf2.txt. Se afieaz nodurile care au cei mai muli vecini (cele mai multe

OG
noduri adiacente). Se determin numrul de muchii (arce) ale grafului i se afieaz muchiile
(arcele). Funcia citeste() se folosete pentru a citi matricea de adiacen din fiier.
Graful neorientat. Funcia nr m() se folosete pentru a determina numrul de muchii ale
grafului. La afiarea muchiilor, pentru a nu se afia de dou ori aceeai muchie, se

AG
parcurge matricea de adiacen numai deasupra diagonalei principale.
#include<fstream.h>
int a[10][10],n;
fstream f("graf1.txt",ios::in);

ED
void citeste()
{int i,j; f>>n;
for(i=1;i<=n;i++)
for (j=1;j<=n;j++) f>>a[i][j]; f.close();}

P
int nr m()
{int i,j,m=0;
for(i=1;i<=n;i++)
I
for (j=1;j<=n;j++) m+=a[i][j]; return m/2;}
int grad(int i) {// este identic cu cea de la exemplul anterior}
void main()
{int i,j,max; citeste(); max=grad(1);

for(i=2;i<=n;i++) if (grad(i)>max) max=grad(i);


cout<<"Nodurile cu cei mai multi vecini sunt: ";
IC

for(i=1;i<=n;i++) if (grad(i)==max) cout<<i<<" ";


cout<<endl<<"Graful are "<<nr m()<<" muchii "<<endl;
cout<<"Muchiile grafului sunt: ";
CT

for(i=1;i<=n;i++)
for (j=i+1;j<=n;j++) if (a[i][j]==1) cout<<i<<"-"<<j<<" "; }
Graful orientat. Funcia nr_a() se folosete pentru a determina numrul de arce ale
grafului. Funcia vecini() se folosete pentru a determina numrul de vecini ai unui nod.
DA

La afiarea arcelor, se parcurge toat matricea de adiacen.


#include<fstream.h>
int a[10][10],n;
fstream f("graf2.txt",ios::in);
DI

void citeste(){//este identic cu cea de la graful neorientat}


int nr a()
{int i,j,m=0;
for(i=1;i<=n;i++)
RA

for (j=1;j<=n;j++) m+=a[i][j]; return m;}


int vecini(int i)
{int j,v=0;
for (j=1;j<=n;j++) if (a[i][j]==1 || a[j][i]==1) v++; return v;}
void main()
TU

{int i,j,max; citeste(); max=vecini(1);


for(i=2;i<=n;i++) if (vecini(i)>max) max=vecini(i);
cout<<"Nodurile cu cei mai multi vecini sunt: ";
for(i=1;i<=n;i++) if (vecini(i)==max) cout<<i<<" ";
I

cout<<endl<<"Graful are "<<nr a()<<" arce "<<endl;


ED
174 Implementarea structurilor de date

C
cout<<"Arcele grafului sunt: ";
for(i=1;i<=n;i++)
for (j=1;j<=n;j++) if (a[i][j]==1) cout<<i<<"-"<<j<<" ";}

I
3. Crearea matricei de adiacen prin citirea muchiilor (arcelor) din fiier. Determi-

OG
narea vecinilor unui nod.
Datele se citesc din fiierul text graf3.txt, pentru graful neorientat, i graf4.txt, pentru graful
orientat. n fiier sunt scrise, pe primul rnd, desprite prin spaii, numrul de noduri i nu-
mrul de muchii (arce) ale grafului, i apoi pe cte un rnd, separate prin spaiu, cele dou

AG
noduri terminale ale fiecrei muchii (arc). Se afieaz vecinii fiecrui nod. Funcia
citeste() se folosete pentru a citi datele din fiier, iar funcia vecini() pentru a deter-
mina vecinii unui nod. Fiierele text se creeaz cu ajutorul unui editor de texte. Pentru
testarea programelor se folosesc graful neorientat G1 i graful orientat G9.

ED
Graful neorientat.
#include<fstream.h>
int a[10][10],n,m;
fstream f("graf3.txt",ios::in);

P
void citeste()
{int k,i,j; f>>n>>m;
for(k=1;k<=m;k++) {f>>i>>j; a[i][j]=1; a[j][i]=1;} f.close();}
I
void vecini(int i)
{for(int j=1;j<=n;j++) if(a[i][j]==1) cout<<j<<" ";}
void main()
{int i; citeste(); cout<<"Vecinii fiecarui nod sunt: "<<endl;

for (i=1;i<=n;i++) {cout<<"Nodul "<<i<<": "; vecini(i); cout<<endl;}}


IC

Graful orientat.
#include<fstream.h>
int a[10][10],n,m;
CT

fstream f("graf4.txt",ios::in);
void citeste()
{int k,i,j; f>>n>>m;
for(k=1;k<=m;k++) {f>>i>>j; a[i][j]=1;} f.close();}
DA

void vecini(int i)
{for(int j=1;j<=n;j++) if(a[i][j]==1 || a[j][i]==1) cout<<j<<" ";}
void main()
{int i; citeste(); cout<<"Vecinii fiecarui nod sunt: "<<endl;
for (i=1;i<=n;i++){cout<<"Nodul "<<i<<": "; vecini(i); cout<<endl;}}
DI

4. Generarea matricei de adiacen.


Pentru a testa programele care prelucreaz grafuri implementate cu matricea de adiacen,
putei s generai aleatoriu matricea de adiacen. Funcia generare() genereaz matri-
RA

cea de adiacen a unui graf neorientat, cu n noduri i m muchii.


#include<iostream.h>
#include<stdlib.h>
int a[10][10],n,m;
TU

void generare()
{int k=0,i,j; randomize();
while(k<m)
{i=rand()%n+1; j=rand()%n+1;
I

if(i!=j && a[i][j]==0) {a[i][j]=1; a[j][i]=1; k++;}}}


ED
Informatic 175

C
void main() {cout<<"n= "; cin>>n; cout<<"m= "; cin>>m;
while (m>n*(n-1)/2) {cout<<"m= "; cin>>m;}
generare(); ... }

I
1. ntr-un fiier este scris o matrice ptrat, astfel: pe primul rnd, un

OG
Tem numr care reprezint dimensiunea matricei, i pe urmtoarele rnduri,
valori numerice desprite prin spaiu care reprezint elementele de
pe cte o linie a matricei. S se verifice dac aceast matrice poate fi matricea de adia-
cen a unui graf. n caz afirmativ, s se precizeze dac graful este orientat sau neorientat

AG
2. Scriei un program care s genereze aleatoriu matricea de adiacen a unui graf orientat.
3. Scriei un program care citete dintr-un fiier matricea de adiacen a unui graf neorien-
tat i care determin numrul minim de muchii care trebuie adugate pentru ca graful s
nu conin noduri izolate.

ED
4. Scriei un program care citete, din dou fiiere text, g1.txt i g2.txt, matricele de
adiacen a dou grafuri, Ga=(X,Ua) i Gb=(X,Ub), i care determin matricea de
adiacen a grafului reuniune Gr=(X,Ur), unde Ur= Ua Ub, care se salveaz n fiierul
g3.txt i matricea de adiacen a grafului intersecie Gi=(X,Ui), unde Ui= Ua Ub, care

P
se salveaz n fiierul g4.txt.
5. Scriei un program care citete din fiierul text graf2.txt informaii despre un graf
orientat (de pe prima linie numrul de noduri, apoi matricea de adiacen) i de la
I
tastatur o mulime A de numere care reprezint etichetele unor noduri din graf i
care afieaz mulimea arcelor ce au o extremitate ntr-un nod din mulimea A i o
extremitate n muimea X-A (X fiind mulimea nodurilor grafului). Pentru testarea
programului, se vor folosi graful G9 i mulimea A={1,3,4,6}.

2.7.4.2. Reprezentarea prin matricea de inciden


IC

Matricea de inciden a unui graf neorientat este o matrice binar cu n linii i m


coloane (An,m), ale crei elemente ai,j sunt definite astfel:
CT

1, dac [i, j] U
a i, j 0, dac [i, j] U

Implementarea grafului neorientat prin matricea de inciden se face printr-un tablou
DA

bidimensional (o matrice cu dimensiunea nm), astfel:


int a[<n>][<m>];
Graful neorientat G1
DI

1 2 3 4 5 6 7 8 9
1 1 1 1 0 0 0 0 0 0
2 1 0 0 1 1 0 0 0 0
RA

3 0 1 0 1 0 1 1 0 0
Graful G1 4 0 0 1 0 0 1 0 0 0
Fig. 9 5 0 0 0 0 1 0 1 0 0
6 0 0 0 0 0 0 0 1 1
TU

Proprietile matricei de inciden a


7 0 0 0 0 0 0 0 1 0
grafului neorientat:
8 0 0 0 0 0 0 0 0 1
1. Pe fiecare coloan exist dou ele-
mente cu valoarea 1 (pe liniile i i j care corespund nodurilor incidente cu muchia), iar
I

restul elementelor au valoarea 0.


ED
176 Implementarea structurilor de date

C
2. Matricea de inciden are 2m elemente egale cu 1, deoarece fiecare muchie este
incident cu dou noduri.

I
Matricea de inciden a unui graf orientat este o matrice cu n linii i m coloane

OG
(An,m), ale crei elemente ai,j sunt definite astfel:

1, dac nodul i este extremitat ea final a arcului j



a i, j 1, dac nodul i este extremitat ea ininii a arcului j
0, dac nodul i nu este extremitat e a arcului j

AG
Implementarea grafului neorientat prin matricea de inciden se face printr-un tablou
bidimensional (o matrice cu dimensiunea nm), astfel:
int a[<n>][<m>];

ED
Graful orientat G9
1 2 3 4 5 6 7 8 9 10
1 1 -1 0 0 0 0 0 0 0 0

P
2 -1 1 -1 -1 1 0 0 0 0 0
3 0 0 1 0 0 1 -1 0 0 0
4 0 0 0 1 -1 0 0 -1 0 0
I
Graful G9 5 0 0 0 0 0 -1 1 1 1 -1
Fig. 10 6 0 0 0 0 0 0 0 0 -1 1

Proprietile matricei de inciden a grafului orientat:


1. Pe fiecare coloan exist un element cu valoarea 1 (pe linia i care corespunde extremitii
IC

finale a arcului) i un element cu valoarea -1 (pe linia j care care corespunde extremitii
iniiale a arcului), iar restul elementelor au valoarea 0.
2. Matricea de inciden are m elemente egale cu 1 i m elemente egale cu -1, deoarece fie-
CT

care arc are o extremitate final i o extremitate iniial. Suma elementelor matricei este 0.
Aceast reprezentare este recomandat pentru grafurile care au un numr mare de
noduri i un numr mic de muchii.
DA

Algoritmi pentru reprezentarea grafurilor folosind matricea de inciden


Din matricea de inciden putei obine urmtoarele informaii:
Graf neorientat Graf orientat
DI

Gradul unui nod i este egal cu suma Gradul intern al unui nod i este egal cu
elementelor de pe linia i. numrul de elemente cu valoarea 1 de pe
linia i. Gradul extern al unui nod i este egal
cu numrul de elemente cu valoarea -1 de pe
RA

linia i.
Nodurile adiacente nodului i sunt nodurile j Succesorii nodului i sunt nodurile j (j=1,n) pen-
(j=1,n) pentru care elementele din linia j sunt tru care elementele din linia j sunt egale cu 1
egale cu 1 n coloana k (k=1,m) n care i n coloana k (k=1,m) n care elementele de pe
TU

elementele de pe linia i au valoarea 1: linia i au valoarea -1: a[i][k] = -1 i a[j][k] = 1.


a[i][k] = 1 i a[j][k] = 1. Predecesorii nodului i sunt nodurile j (j=1,n)
penru care elementele din linia j sunt egale cu
-1 n coloana k (k=1,m) n care elementele de pe
I

linia i au valoarea 1: a[i][k] = 1 i a[j][k] = -1.


ED
Informatic 177

C
Graf neorientat Graf orientat
Nodurile adiacente nodului i sunt date de
reuniunea dintre mulimea succesorilor i

I
mulimea predecesorilor nodului.

OG
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
gradul nodului. cardinalul mulimii de noduri adiacente nodului i.
Muchia k = [i,j] a grafului este determinat de Arcul k = [i,j] al grafului este determinat de
dou elemente ale matriceii a[i]kj] i a[j]kj], care dou elemente ale matricei, a[i]kj] i a[j]kj], care
ndeplinesc condiia a[i][k] = 1 i a[j][k] = 1, i ndeplinesc condiia a[i][k] = -1 i a[j][k] = 1, i

AG
semnific faptul c muchia k este incident cu semnific faptul c arcul k iese din nodul i i
nodurile i i j. intr n nodul j

1. Scriei matricea de inciden a grafului neorientat G4. Folosind infor-


Tem

ED
maiile din matricea de inciden, determinai: gradul nodului 5, nodurile
izolate i nodurile terminale.
2. Scriei matricea de inciden a grafului neorientat G14. Ce proprietate are acest graf?
3. Scriei matricea de inciden a grafului G8. Folosind informaiile din matricea de inci-

P
den, determinai: gradul intern al nodului 5, gradul extern al nodului 4, succesorii i
predecesorii nodului 2 i predecesorii nodului 3.
G
G
G111666
4. Scriei matricea de inciden a grafului orientat G16 din figura 11.
I
5. Scriei matricea de inciden a grafului G11. Folosind informa-
iile din matricea de inciden determinai: gradul intern al
nodului 5, gradul extern al nodului 2, nodurile adiacente
nodului 5, succesorii i predecesorii nodului 4, nodurile termi- Fig. 11

nale i nodurile izolate.


6. Scriei matricea de inciden a grafului G13. Cum identificai, n matricea de inciden,
IC

nodul surs al unui graf?


7. Scriei matricea de inciden a grafului G14. Cum identificai, n matricea de inciden,
CT

nodul destinaie al unui graf?


Implementarea algoritmilor pentru reprezentarea grafurilor cu matricea de inciden
1. Crearea matricei de inciden prin introducerea datelor de la tastatur. Deter-
DA

minarea gradului unui nod. Salvarea matricei de inciden ntr-un fiier text.
Se citesc de la tastatur muchiile (arcele) unui graf orientat (neorientat). Se creeaz
matricea de inciden a grafului. Se afieaz gradul nodului p a crui etichet se introduce
de la tastatur. Se salveaz matricea de inciden n fiierul text graf5.txt, pentru graful
DI

neorientat, i graf6.txt, pentru graful orientat. n fiierul text se scriu pe primul rnd ordinul
grafului i numrul de muchii, iar pe urmtoarele rnduri, liniile matricei de inciden.
Funcia scrie() se folosete pentru a scrie matricea de inciden n fiier. Pentru testarea
programelor se folosesc graful neorientat G1 i graful orientat G9.
RA

Graful neorientat. Funcia grad() se folosete pentru a determina gradul unui nod.
#include<fstream.h>
int a[10][10],n,m;
TU

fstream f("graf5.txt",ios::out);
void scrie()
{int i,j; f<<n<<" "<<m<<endl;
for(i=1;i<=n;i++)
{for(k=1;k<=m;k++) f<<a[i][k]<<" "; f<<endl;}
I
ED

f.close();}
178 Implementarea structurilor de date

C
int grad(int i)
{int g=0,k;
for(k=1;k<=m;k++) g+=a[i][k]; return g;}

I
void main()

OG
{int i,j,p,k;
cout<<"numar de noduri "; cin>>n; cout<<"numar de muchii "; cin>>m;
for(k=1;k<=m;k++)
{cout<<"primul nod al muchiei "<<k<<": "; cin>>i;
cout<<"al doilea nod al muchiei "<<k<<": "; cin>>j;

AG
a[i][k]=1; a[j][k]=1;}
cout<<"nodul= "; cin>>p;
cout<<"Gradul nodului "<<p<<" este "<<grad(p)<<endl;
scrie();}

ED
Graful orientat. Funcia grad_int() se folosete pentru a determina gradul intern al unui
nod, iar funcia grad_ext()se folosete pentru a determina gradul extern al unui nod.
#include<fstream.h>
int a[10][10],n,m;

P
fstream f("graf6.txt",ios::out);
int scrie() {//este identic cu cea de la graful neorientat }
int grad int(int i)
I
{int g=0,k;
for(k=1;k<=m;k++) if (a[i][k]==1) g++; return g;}
int grad ext(int i)
{int g=0,k;

for(k=1;k<=m;k++) if (a[i][k]==-1) g++; return g;}


void main()
IC

{int i,j,p,k;
cout<<"numar de noduri "; cin>>n; cout<<"numar de muchii "; cin>>m;
for(k=1;k<=m;k++)
CT

{cout<<"nodul initial al arcului "<<k<<": "; cin>>i;


cout<<"nodul final al arcului "<<k<<": "; cin>>j;
a[i][k]=-1; a[j][k]=1;}
cout<<"nodul= "; cin>>p;
DA

cout<<"Gradul intern al nodului "<<p<<" este "<<grad int(p)<<endl;


cout<<"Gradul extern al nodului "<<p<<" este "<<grad ext(p)<<endl;
scrie();}
2. Crearea matricei de inciden prin citirea datelor din fiier. Afiarea vecinilor
DI

unui nod.
Se citesc din fiierele create anterior (graf5.txt, respectiv graf6.txt) matricele de inciden
ale celor dou grafuri i se afieaz vecinii unui nod x a crui etichet se introduce de la
RA

tastatur. Funcia citeste() se folosete pentru a citi matricea de inciden din fiier.
Graful neorientat. Funcia vecini() se folosete pentru a determina vecinii unui nod.
#include<fstream.h>
int a[10][10],n;
TU

fstream f("graf5.txt",ios::in);
void citeste()
{int i,k; f>>n>>m;
for(i=1;i<=n;i++)
I

for (k=1;k<=m;k++) f>>a[i][k]; f.close();}


ED
Informatic 179

C
void vecini(int i)
{int k,j;
for(k=1;k<=m;k++)

I
if(a[i][k]==1) for(j=1;j<=n;j++)

OG
if(j!=i && a[j][k]==1) cout<<j<<" ";}
void main()
{int p; cout<<"nodul= "; cin>>x; citeste();
cout<<"Vecinii nodului "<<x<<" sunt nodurile "; vecini(x);}
Graful orientat. Vectorii binari s i p se folosesc pentru a memora succesorii, respectiv prede-

AG
cesorii nodului x. Elementul i are valoarea 1 dac nodul i este succesor, respectiv predecesor
al nodului x; altfel, are valoarea 0. Funciile succ() i pred() se folosesc pentru a determina
n vectorii s i p succesorii, respectiv predecesorii unui nod. Funcia vecini() se folosete
pentru a determina vecinii unui nod, prin reuniunea mulimii predecesorilor i a succesorilor.

ED
#include<fstream.h>
int a[10][10],n,m,s[10],p[10];
fstream f("graf6.txt",ios::in);
void citeste() {//este identic cu cea de la graful neorientat }

P
void succ(int i)
{for(int k=1;k<=m;k++)
if(a[i][k]==-1) for(int j=1;j<=n;j++)
I
if(j!=i && a[j][k]==1) s[j]=1;}
void pred(int i)
{for(int k=1;k<=m;k++)
if(a[i][k]==1) for(int j=1;j<=n;j++)

if(j!=i && a[j][k]==-1) p[j]=1;}


void vecini(int i)
IC

{int j; succ(i); pred(i);


for(j=1;j<=n;j++) if (j!=i && (s[j]==1 || p[j]==1)) cout<<j<<" ";}
void main()
CT

{int x; cout<<"nodul= "; cin>>x; citeste();


cout<<"Vecinii nodului "<<x<<" sunt nodurile "; vecini(x);}
3. Crearea matricei de inciden prin citirea muchiilor (arcelor) din fiier. Prelucrarea
informaiilor asociate muchiilor.
DA

Datele se citesc din fiierul text graf7.txt, pentru graful neorientat, i graf8.txt, pentru graful
orienatat. n fiier sunt scrise, pe primul rnd, desprite prin spaii, numrul de noduri i
numrul de muchii (arce) ale grafului, i apoi, pe cte un rnd, separate prin spaiu, cele dou
DI

noduri terminale ale fiecrei muchii (arc) i lungimea muchiei (arcului). Se afieaz muchiile
(arcele) care au lungimea mai mare dect lungimea medie a muchiilor (arcelor) din graf. Se
folosete vectorul d pentru a memora lungimea fiecrei muchii (arc). Funcia citeste() se
folosete pentru citi datele din fiier, funcia medie() pentru a determina lungimea medie a
RA

muchiilor (arceor) din graf iar funcia afisare() pentru a afia muchiile (arcele) care au
lungimea mai mare dect media. Fiierele text se creeaz cu ajutorul unui editor de texte.
Pentru testarea programelor se folosesc graful neorientat G1 i graful orientat G9. n aceste
grafuri se asociaz fiecrei muchii (arc) o valoare pentru lungime.
TU

Graful neorientat
#include<fstream.h>
int a[10][10],d[10],n,m;
I

fstream f("graf7.txt",ios::in);
ED
180 Implementarea structurilor de date

C
void citeste()
{int k,i,j,l; f>>n>>m;
for(k=1;k<=m;k++) {f>>i>>j>>l; a[i][k]=1; a[j][k]=1; d[k]=l;}

I
f.close();}

OG
float media()
{int i,s=0;
for(i=1;i<=m;i++) s+=d[i]; return (float)s/m;}
void afiseaza()
{int i,k; float dm=media();

AG
for(k=1;k<=m;k++)
if (d[k]>dm)
{for (i=1;i<=n;i++) if (a[i][k]==1) cout<<i<<" ";
cout<<" cu lungimea "<<d[k]<<endl;}}
void main()

ED
{citeste(); cout<<"Media lungimii este: "<<media()<<endl;
cout<<"Muchiile sunt: "<<endl; afiseaza();}
Graful orientat

P
#include<fstream.h>
int a[10][15],d[15],n,m;
fstream f("graf8.txt",ios::in);
I
void citeste()
{int k,i,j,l; f>>n>>m;
for(k=1;k<=m;k++) {f>>i>>j>>l; a[i][k]=-1; a[j][k]=1; d[k]=l;}
f.close(); }

float media() {//este identic cu cea de la graful neorientat }


void afiseaza()
IC

{int i,k,x,y; float dm=media();


for(k=1;k<=m;k++)
if (d[k]>dm)
CT

{for (i=1;i<=n;i++) {if (a[i][k]==-1) x=i;


if (a[i][k]==1) y=i;}
cout<<x<<"-"<<y<<" cu lungimea "<<d[k]<<endl;}}
void main()
{citeste(); cout<<"Media lungimii este: "<<media()<<endl;
DA

cout<<"Arcele sunt: "<<endl; afiseaza();}


4. Crearea matricei de inciden prin citirea datelor din matricea de adiacen.
Afiarea muchiilor i a nodurilor izolate.
DI

Matricele de adiacen se citesc din fiierele text create anterior: graf1.txt, pentru graful
neorientat, i graf2.txt, pentru graful orientat. Se creeaz matricele de inciden ale celor dou
grafuri, se afieaz muchiile (arcele) i nodurile izolate. Se salveaz n fiierul text graf9.txt,
respectiv graf10.txt, informaiile despre muchii, astfel: pe primul rnd, desprite prin spaii,
RA

numrul de noduri i numrul de muchii (arce) ale grafului, i apoi, pe cte un rnd, separate
prin spaiu, cele dou noduri terminale ale fiecrei muchii (arc). Se folosesc matricele a pentru
matricea de adiacen i b pentru matricea de inciden i funciile citeste() pentru a citi
matricea de adiacena din fiier, salveaza() pentru a salva n fiierul text informaiile despre
TU

muchiile (arcele) grafului, transforma() pentru a obine matricea de inciden din matricea
de adiacen, afiseaza_noduri_izolate() pentru a afia nodurile izolate, i
afiseaza_muchii() pentru a afia muchiile (arcele). Pentru testarea programelor se
folosesc graful neorientat G1 i graful orientat G9.
I
ED
Informatic 181

C
Graful neorientat
#include<fstream.h>
int a[10][10],b[10][20],n,m;

I
fstream f1("graf1.txt",ios::in),f2("graf9.txt",ios::out);

OG
void citeste()
{int i,j; f1>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {f1>>a[i][j]; if(a[i][j]==1) m++;}
m=m/2; f1.close();}

AG
void transforma()
{int i,j,k=1;
for (i=1;i<=n;i++)
for (j=1;j<i;j++) if (a[i][j]==1) {b[i][k]=1; b[j][k]=1; k++;}}

ED
void afiseaza muchii()
{for (int k=1; k<=m; k++)
{cout<<"Muchia "<<k<<": ";
for (int i=1;i<=n;i++) if (b[i][k]==1) cout<<i<<" "; cout<<endl;}}
void afiseaza noduri izolate()

P
{int i,k,x;
for (i=1;i<=n;i++)
{for (k=1,x=0;k<=m && x==0;k++) if (b[i][k]==1) x=1;
I
if (!x) cout<<i<<" ";}}
void salveaza()
{f2<<n<<" "<<m<<endl;

for (int k=1;k<=m;k++)


{for (int i=1;i<=n;i++) if (b[i][k]==1) f2<<i<<" "; f2<<endl;}
f2.close();}
IC

void main()
{citeste(); transforma(); afiseaza_muchii();
cout<<"Nodurile izolate sunt: "; afiseaza_noduri_izolate();
CT

salveaza();}
Graful orientat
#include<fstream.h>
DA

int a[10][10],b[10][20],n,m;
fstream f1("graf1.txt",ios::in),f2("graf9.txt",ios::out);
void citeste()
{int i,j; f1>>n;
DI

for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {f1>>a[i][j]; if(a[i][j]==1) m++;} f1.close();}
void transforma()
{int i,j,k=1;
RA

for (i=1;i<=n;i++)
for (j=1;j<=n;j++) if (a[i][j]==1) {b[i][k]=-1; b[j][k]=1; k++;}}
void afiseaza arce()
{int i,k,x,y;
for (k=1; k<=m; k++)
TU

{cout<<"Arcul "<<k<<": ";


for (i=1;i<=n;i++) {if (b[i][k]==-1) x=i; if (b[i][k]==1) y=i;}
cout<<x<<"-"<<y<<endl;}}
void afiseaza noduri izolate()
I

{int i,k,x;
ED
182 Implementarea structurilor de date

C
for (i=1;i<=n;i++)
{for (k=1,x=0;k<=m && x==0;k++) if (b[i][k]==1 || b[i][k]==-1) x=1;
if (!x) cout<<i<<" ";}}

I
void salveaza()

OG
{int i,k;
f2<<n<<" "<<m<<endl;
for (k=1;k<=m;k++)
{for (i=1;i<=n;i++) {if (b[i][k]==-1) x=i; if (b[i][k]==1) y=i;}
f2<<x<<" "<<y<<endl;}

AG
f2.close();}
void main()
{citeste(); transforma(); afiseaza arce();
cout<<"Nodurile izolate sunt: "; afiseaza noduri izolate();
salveaza();}

ED
1. ntr-un fiier text este scris o matrice, astfel: pe primul rnd dou
Tem numere separate prin spaiu, care reprezint numrul de linii i
numrul de coloane ale matricei, i, pe urmtoarele rnduri valori

P
numerice desprite prin spaiu, care reprezint elementele de pe cte o linie a matricei.
a. Scriei un program care s verifice dac aceast matrice poate fi matricea de
inciden a unui graf neorientat. n caz afirmativ, s se afieze cte noduri izolate are
I
graful (Indicaie. Se verific urmtoarele condiii: a) s fie o matrice binar; b) suma
elementelor de pe fiecare coloan s fie egal cu 2; c) s nu existe dou coloane
identice. Un nod este izolat dac suma elementelor de pe linia sa este egal cu 0).

b. Scriei un program care s verifice dac aceast matrice poate fi matricea de


inciden a unui graf orientat. n caz afirmativ, s se determine cte noduri care au
IC

gradul intern egal cu gradul extern exist (Indicaie. Se verific urmtoarele condiii:
a) pe fiecare coloan s nu existe dect o valoare egal cu 1, una egal cu -1 i
restul egale cu 0; b) s nu existe dou coloane identice. Un nod are gradul intern
CT

egal cu gradul extern dac suma elementelor de pe linia sa este egal cu 0).
2. Scriei un program care citete din fiierul text graf6.txt matricea de inciden a grafului
orientat i care:
a. afieaz numrul de vecini ai unui nod p a crui etichet se citete de la tastatur;
DA

b. genereaz matricea de adiacen a grafului din matricea de inciden i o salveaz


n fiierul graf6a.txt.

2.7.4.3. Reprezentarea prin lista muchiilor


DI

Lista muchiilor unui graf este format din m elemente care conin, fiecare,
cte o pereche de dou noduri, xi i xj, care formeaz o muchie,
adic pentru care [xi, xj]U.
RA

Implementarea acestui tip de reprezentare se poate face folosind una dintre urmtoarele
structuri de date:
Matricea muchiilor u cu dimensiune m2, n care fiecare linie corespunde unei
TU

muchii (arc) i n fiecare linie se nregistreaz n cele dou coloane etichetele nodu-
rilor care se gsesc la extremitile muchiei (arcului).
int u [<m>][2];
Referirea la nodurile adiacente muchiei (arcului) i se face prin u[i][0] extremitatea
I
ED

iniial a muchiei (arcului), respectiv u[i][1] extremitatea final a muchiei (arcului).


Informatic 183

C
Vectorul muchiilor u cu dimensiunea m ale crui elemente sunt nregistrri, fiecare
nregistrare fiind format din dou cmpuri x i y ce conin etichetele nodurilor care
se gsesc la extremitile muchiei (arcului). Pentru elementele vectorului se define-

I
te tipul de dat muchie, de tip nregistrare.

OG
struct muchie {int x,y;};
muchie u[<m>];
Referirea la o muchie (arc) i se face prin u[i], iar la unul dintre nodurile adiacente
muchiei (arcului) se face prin u[i].x extremitatea iniial a muchie (arcului),

AG
respectiv u[i].y extremitatea final a muchiei (arcului).

Implementarea cu matrice
0 1

ED
1 1 2
2 1 3
3 1 4
Graful neorientat G1
4 2 3

P
5 2 4
Implementarea cu vector de nregistrri
6 3 4
I
Muchiile
7 3 5
8 6 7 1 2 3 4 5 6 7 8 9
9 6 8 1 2 1 3 2 4 2 3 2 4 3 4 3 5 6 7 6 8

Implementarea cu matrice
IC

0 1
1 1 2
CT

2 2 1
3 2 4
Graful orientat G9
4 3 2
DA

5 3 5
Implementarea cu vector de nregistrri
6 4 2
Arcele
7 4 5
8 5 3 1 2 3 4 5 6 7 8 9 10
DI

9 5 6 1 2 2 1 2 4 3 2 3 5 4 2 4 5 5 3 5 6 6 5
10 6 5
RA

Exemple:
Dac implementarea se face folosind matricea, atunci pentru orice muchie (arc) i, u[i][0]
u[i][1]. Dac implementarea se face folosind vectorul de nregistrri, atunci pentru
orice muchie (arc) i, u[i].x u[i].y .
TU

Aceast reprezentare este recomandat pentru problemele n care se face


prelucrarea succesiv a muchiilor (arcelor). Are avantajul c permite adugarea la
tipul de dat muchie i a altor cmpuri (lungime, cost, timp etc.), corespunztor
unor mrimi care pot fi asociate muchiilor (arcelor).
I
ED
184 Implementarea structurilor de date

C
Algoritmi pentru reprezentarea grafurilor folosind lista muchiilor
Din lista muchiilor putei obine urmtoarele informaii:

I
Graf neorientat Graf orientat

OG
Gradul unui nod i este egal, n funcie de Gradul extern al nodului i este egal, n funcie
implementare, cu numrul de apariii ale de implementare, cu numrul de apariii ale eti-
etichetei nodului n matrice, respectiv n chetei nodului n coloana 0 a matricei, respec-
cmpurile vectorului de nregistrri. tiv n primul cmp, n vectorul de nregistrri.
Gradul intern al nodului i este egal, n funcie

AG
de implementare, cu numrul de apariii ale eti-
chetei nodului n coloana 1 a matricei, respec-
tiv n al doilea cmp, n vectorul de nregistrri.
Nodurile adiacente nodului i sunt, n funcie Succesorii nodului i sunt, n funcie de

ED
de implementare, etichetele j din coloana 1, implementare, etichetele j din coloana 1 pentru
pentru care u[k][0]=i, sau din coloana 0, pentru care u[k][0]=i, respectiv etichetele j din cmpul
care u[k][1]=i, respectiv etichetele j din cmpul u[k].y pentru care u[k].x=i (k=1,m).
u[k].y, pentru care u[k].x=i, sau din cmpul Predecesorii nodului i sunt, n funcie de
u[k].x, pentru care u[k].y=i (k=1,m). implementare, etichetele j din coloana 0 pentru

P
care u[k][1]=i, respectiv etichetele j din cmpul
u[k].x pentru care u[k].y=i (k=1,m).
Nodurile adiacente nodului i sunt date de
I
reuniunea dintre mulimea succesorilor i
mulimea predecesorilor nodului.
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
gradul nodului. cardinalul mulimii de noduri adiacente nodului i.

1. Scriei lista muchiilor a grafului G4. Folosind informaiile din lista mu-
IC

Tem chiilor, determinai: gradul nodului 5, nodurile izolate i nodurile termi-


nale.
2. Scriei lista muchiilor a grafului neorientat G14. Ce proprietate are acest graf?
CT

3. Scriei lista muchiilor a grafului G8. Folosind informaiile din lista muchiilor, determinai:
gradul intern al nodului 5, gradul extern al nodului 4, succesorii i predecesorii nodului 2
i predecesorii nodului 3.
DA

4. Scriei lista muchiilor a grafului G11. Folosind informaiile din lista muchiilor, determinai:
gradul intern al nodului 5, gradul extern al nodului 2, nodurile adiacente nodului 5,
succesorii i predecesorii nodului 4, nodurile terminale i nodurile izolate.
G
G
G111777 5. Scriei lista muchiilor a grafului orientat G17 din figura 12. Folo-
DI

sind informaiile din lista muchiilor, identificai nodurile izolate.


6. Scriei lista muchiilor a grafului G13. Cum identificai, n lista
muchiilor, nodul surs?
7. Scriei lista muchiilor a grafului G14. Cum identificai, n lista
RA

muchiilor, nodul destinaie? Fig. 12

Implementarea algoritmilor pentru reprezentarea grafurilor cu lista muchiilor


1. Crearea matricei cu lista muchiilor prin introducerea datelor de la tastatur. Deter-
TU

minarea gradului unui nod. Salvarea informaiilor despre muchii ntr-un fiier text.
Se citesc de la tastatur muchiile (arcele) unui graf orientat (neorientat). Se creeaz matri-
cea cu muchiile grafului. Se afieaz nodurile izolate i terminale. Se salveaz matricea cu
muchiile grafului n fiierul text graf11.txt, pentru graful neorientat, i graf12.txt, pentru graful
I

orientat. n fiierul text se vor scrie, pe primul rnd, ordinul grafului i numrul de muchii, iar
ED
Informatic 185

C
pe urmtoarele rnduri, nodurile de la extremitile unei muchii (arc). Funcia scrie() se
folosete pentru a scrie informaiile din matricea muchiilor n fiier. Pentru testarea progra-
melor se folosesc graful neorientat G1 i graful orientat G9.

I
Graful neorientat. Funcia grad() se folosete pentru a determina gradul unui nod.

OG
#include<fstream.h>
int a[10][2],n,m;
fstream f("graf11.txt",ios::out);
int grad(int i)

AG
{int k,g=0;
for (k=1;k<=m;k++) if (a[k][0]==i || a[k][1]==i) g++; return g;}
void scrie()
{int k; f<<n<<" "<<m<<endl;
for(k=1;k<=m;k++) f<<a[k][0]<<" "<<a[k][1]<<endl; f.close();}

ED
void main()
{int i,j,k;
cout<<"numar de noduri "; cin>>n; cout<<"numar de muchii "; cin>>m;
for(k=1;k<=m;k++)

P
{cout<<"primul nod al muchiei "<<k<<": "; cin>>i;
cout<<"al doilea nod al muchiei "<<k<<": "; cin>>j;
a[k][0]=i; a[k][1]=j;}
I
cout<<"Nodurile izolate sunt: ";
for(i=1;i<=n;i++) if (grad(i)==0) cout<<i<<" ";
cout<<endl<<"Nodurile terminale sunt: ";
for(i=1;i<=n;i++) if (grad(i)==1) cout<<i<<" ";

scrie();}
IC

Graful orientat. Funcia grad_int()se folosete pentru a determina gradul intern al unui
nod, iar funcia grad_ext()se folosete pentru a determina gradul extern al unui nod.
#include<fstream.h>
CT

int a[10][2],n,m;
fstream f("graf12.txt",ios::out);
int grad int(int i)
{int g=0,k;
DA

for(k=1;k<=m;k++) if (a[k][1]==i) g++; return g;}


int grad ext(int i)
{int g=0,k;
for(k=1;k<=m;k++) if (a[k][0]==i) g++; return g;}
void scrie() {//este identic cu cea de la graful neorientat }
DI

void main()
{int i,j,k;
cout<<"numar de noduri "; cin>>n; cout<<"numar de arce "; cin>>m;
for(k=1;k<=m;k++)
RA

{cout<<"nodul initial al arcului "<<k<<": "; cin>>i;


cout<<"nodul final al arcului "<<k<<": "; cin>>j;
a[k][0]=i; a[k][1]=j;}
cout<<"Nodurile izolate sunt: ";
TU

for(i=1;i<=n;i++) if (grad int(i)+grad ext(i)==0) cout<<i<<" ";


cout<<endl<<"Nodurile terminale sunt: ";
for(i=1;i<=n;i++) if (grad int(i)+grad ext(i)==1) cout<<i<<" ";
scrie();}
I
ED
186 Implementarea structurilor de date

C
2. Crearea vectorului de muchii prin citirea muchiilor (arcelor) din fiier. Prelucrarea
informaiilor asociate muchiilor.
Datele se citesc din fiierele text create anterior: graf7.txt, pentru graful neorientat, i

I
graf8.txt, pentru graful orientat. Pentru un nod p a crui etichet se citete de la tastatur,

OG
se afieaz cel mai apropiat vecin (sau cei mai apropiai vecini, dac exist mai muli) la
care se poate ajunge din nodul p. n cazul grafului neorientat, cel mai apropiat vecin este
nodul adiacent nodului p care formeaz cu acesta muchia care are lungimea cea mai mic
fa de muchiile incidente cu ceilali vecini. n cazul grafului orientat, cel mai apropiat vecin

AG
la care se poate ajunge din nodul p este nodul succesor nodului p care formeaz cu acesta
arcul care are lungimea cea mai mic fa de arcele incidente cu ceilali succesori. Funcia
citeste() se folosete pentru a citi datele din fiier. Pentru testarea programelor se
folosesc graful neorientat G1 i graful orientat G9.

ED
Graful neorientat. Funcia izolat() determin dac nodul este izolat.
#include<fstream.h>
struct muchie {int x,y,d;};
muchie u[20]; int n,m;

P
fstream f("graf7.txt",ios::in);
void citeste()
{int k; f>>n>>m;
I
for(k=1;k<=m;k++) f>>u[k].x>>u[k].y>>u[k].d; f.close();}
int izolat(int i)
{int k,g=0;
for (k=1;k<=m;k++) if (u[k].x==i || u[k].y==i) g++; return g==0;}

void main()
{int k,p,min;
IC

citeste(); cout<<"Nodul: "; cin>>p;


if (izolat(p)) cout<<"Nodul "<<p<<" nu are vecini";
else
CT

{k=1;
while (u[k].x!=p && u[k].y!=p) k++;
min=u[k].d;
for (k++;k<=m;k++)
DA

if (u[k].x==p || u[k].y==p)
if (u[k].d<min) min=u[k].d;
cout<<"Distanta minima este "<<min<<endl;
cout<<"Nodurile aflate la distanta minima sunt: ";
for (k=1;k<=m;k++)
DI

{if (u[k].x==p && u[k].d==min) cout<<u[k].y<<" ";


if (u[k].y==p && u[k].d==min) cout<<u[k].x<<" ";}}}
Graful orientat. Funcia succ()determin dac nodul are succesori.
RA

#include<fstream.h>
struct arc {int x,y,d;};
arc u[20];
int n,m;
TU

fstream f("graf8.txt",ios::in);
void citeste() {//este identic cu cea de la graful neorientat }
int succ(int i)
{int k,g=0;
I

for (k=1;k<=m;k++) if (u[k].x==i) g++; return g!=0;}


ED
Informatic 187

C
void main()
{int k,p,min; citeste(); cout<<"Nodul: "; cin>>p;
if (!succ(p))

I
cout<<"Nodul "<<p<<" nu are vecini la care sa se poata ajunge";

OG
else
{k=1;
while (u[k].x!=p) k++;
min=u[k].d;
for (k++;k<=m;k++) if (u[k].x==p && u[k].d<min) min=u[k].d;

AG
cout<<"Distanta minima este "<<min<<endl;
cout<<"Nodurile aflate la distanta minima sunt: ";
for (k=1;k<=m;k++)
if (u[k].x==p && u[k].d==min) cout<<u[k].y<<" ";}}

ED
1. Scriei un program care realizeaz urmtoarele:
Tem a. reface matricea cu muchiile grafului orientat din fiierul text graf12.txt;
b. determin cte noduri izolate are graful i afieaz aceste noduri;
c. genereaz matricea de adiacen din matricea muchiilor i o salveaz n fiierul text

P
graf12a.txt.
(Indicaie. Se numr nodurile distincte care apar n lista muchiilor n1, iar numrul de
noduri izolate va fi dat de diferena n-n1.)
I
2. Scriei un program care construiete vectorul de muchii din matricea de adiacen a
grafului orientat care se citete din fiierul text graf2.txt i care determin vecinii unui
nod p a crui etichet se citete de la tastatur.

3. Scriei un program care s genereze aleatoriu, ntr-un fiier, lista muchiilor unui graf
neorientat (orientat). Numrul de noduri i numrul de muchii se citesc de la tastatur.
IC

4. Scriei un program care s genereze aleatoriu, ntr-un fiier, lista muchiilor unui graf
neorientat (orientat) n care muchiile au asociate o mrime numit cost. Se citesc de la
tastatur: numrul de noduri, numrul de muchii i limitele intervalului n care mrimea
CT

cost poate lua valori.

2.7.4.4. Reprezentarea prin lista de adiacen


DA

Lista de adiacen este format din listele Li (1in) care conin toi vecini
unui nod xi la care se poate ajunge direct din nodul xi,
adic toate nodurile xj pentru care [xi,xj]U.
Observaie. n cazul grafului neorientat, lista Li a vecinilor unui nod xi al grafului este
DI

format din nodurile xj adiacente nodului xi. n cazul grafului orientat, lista Li a vecinilor
unui nod xi al grafului este format din nodurile xj care sunt succesorii nodului xi.
Implementarea acestui tip de reprezentare se poate face: Graful neorientat G1
RA

static, folosind una dintre urmtoarele structuri de date: Nod Lista de adiacen
A. Matricea listei de adiacen 1 2, 3, 4
B. Vectorii listei de adiacen 2 1, 3, 5
dinamic, cu ajutorul listelor nlnuite. 3 1, 2, 4, 5
TU

4 1, 3
Implementarea static 5 2, 3
A. Matricea listei de adiacen L cu 2 linii i n+2m 6 7, 8
coloane pentru graful neorientat, respectiv cu n+m co- 7 6
I

loane pentru graful orientat, definit astfel: 8 6


ED
188 Implementarea structurilor de date

C
Prima linie conine etichetele nodurilor i listele de adiacen ale fiecrui nod; este
format din dou seciuni: Graful orientat G9
a. Primele n coloane conin etichetele nodurilor: Nod List de adiacen

I
L[0][i]=i (1in). 1 2

OG
b. Urmtoarele m2 coloane, respectiv m coloa- 2 1, 3, 4
ne, conin n ordine cele n liste de adiacen 3 5
ale celor n noduri. 4 2, 5
A doua linie conine informaiile necesare pentru a 5 3, 6

AG
identifica n prima linie lista de adiacen a fiecrui 6 5
nod; este format din dou seciuni:
a. Primele n coloane conin, n ordine, pentru fiecare nod i (1in), indicele
coloanei din prima linie din care ncepe lista de adiacen a nodului:
L[1][i]=j, unde j este indicele coloanei de unde ncepe lista de adiacen

ED
a nodului i. Dac nodul este izolat, se va memora valoarea 0 L[1][i]=0
(nu exist list de adiacen pentru acel nod).
b. Urmtoarele m2 coloane, respectiv m coloane, conin n ordine informaii
despre modul n care se nlnuiesc elementele din list. Dac nodul

P
L[0][i] se gsete n interiorul listei, atunci L[1][i]=i+1 (indicele
urmtorului element din list). Dac nodul L[0][i] se gsete la sfritul
I
listei, atunci L[1][i]=0 (s-a terminat lista de adiacen a nodului i).
Matricea este definit astfel:
a) pentru graful neorientat: int L[2][<n>+2*<m>];
b) pentru graful orientat: int L[2][<n>+<m>];

Graful neorientat G1
IC

Nodurile L1 L2 L3 L4 L5 L6 L7 L8

1 2 3 4 5 6 7 8 2 3 4 1 3 5 1 2 4 5 1 3 2 3 7 8 6 6
CT

9 12 15 19 21 23 25 26 10 11 0 13 14 0 16 17 18 0 20 0 22 0 24 0 0 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
DA

Indicii coloanelor
Graful orientat G9
Nodurile L1 L2 L3 L4 L5 L6
1 2 3 4 5 6 2 1 3 4 5 2 5 3 6 8
DI

7 8 11 12 14 16 0 9 10 0 0 20 0 22 0 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
RA

Indicii coloanelor
B. Vectorii listei de adiacen: un vector L cu dimensiunea m2, pentru graful neorien-
tat, respectiv cu dimensiunea m, pentru graful orientat, care conine listele de adia-
cen ale fiecrui nod, i un vector cap, cu dimensiunea n, care conine indicii de la
TU

care ncepe lista vecinilor fiecrui nod n vectorul L. Indicii din vectorul cap corespund
etichetelor nodurilor. Cei doi vectori sunt definii astfel:
a) pentru graful neorientat: int cap[<n>],L[2*<m>];
b) pentru graful orientat: int cap[<n>],L[<m>];
I
ED
Informatic 189

C
Graful neorientat G1
1 2 3 4 5 6 7 8

I
cap 1 4 7 11 13 15 17 18

OG
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
L 2 3 4 1 3 5 1 2 4 5 1 3 2 3 7 8 6 6

AG
L1 L2 L3 L4 L5 L6 L7 L8
Graful orientat G9
1 2 3 4 5 6

ED
cap 1 2 5 6 8 10

1 2 3 4 5 6 7 8 9 10

P
L 2 1 3 4 5 2 5 3 6 5

L1 L2 L3 L4 L5 L6
I
Observaie. Fiecare list de vecini Li, conine indicii coloanelor j n care se gsesc valori
de 1 n matricea de adiacen (a[i][j]=1).

Implementarea dinamic
Lista de adicen a fiecrui nod se memoreaz ntr-o list simplu nlnuit, ale crei ele-
IC

mente sunt de tip nod (informaia util memoreaz eticheta unui nod din list), iar adresa
primului element din fiecare list se memoreaz ntr-un vector L, care are lungimea logic
CT

egal cu numrul de noduri n i ale crui elemente sunt de tip pointer ctre tipul nod:
struct nod {int info;
nod * urm;};
nod *L[<n>];
DA

L
2
1
DI

1 3 4
2
5
3
RA

2 5
4
3 6
5 Graful orientat G9
TU

5
6
I
ED
190 Implementarea structurilor de date

C
L

2 3 4
1

I
OG
1 3 5
2
1 2 4 5
3

AG
1 3
4
2 3
5 Graful neorientat G1
7 8

ED
6
6
7

P
8 6 I
Aceast reprezentare este recomandat pentru grafurile care au un numr mare de
noduri i un numr mic de muchii.

Algoritmi pentru reprezentarea grafurilor folosind listele de adiacen


Din lista de adiacen implementat static cu matrice putei obine urmtoarele informaii:
IC

Graf neorientat Graf orientat


Lungimea listei de adiacen a nodului i Lungimea listei de adiacen a nodului i
neizolat, cu eticheta mai mic dect n, este neizolat, cu eticheta mai mic dect n, se
CT

egal cu diferena dintre primul indice j (j=i+1,n- calculeaz la fel ca i n cazul grafului
1) diferit de 0, din prima seciune a liniei a doua neorientat. Pentru nodul n lungimea listei de
(L[1][j]0), i indicele coloanei din care ncepe adiacen este egal cu (n+m+1 - L[1][n]).
lista de adiacen a nodului i (L[1][j] - L[1][i]). Gradul extern al nodului i este egal cu
DA

Pentru nodul n, lungimea listei de adiacen lungimea listei de adiacen a nodului.


este egal cu diferena dintre numrul total de Gradul intern al nodului i este egal, cu
coloane, plus 1, i indicele coloanei din care numrul de apariii ale etichetei nodului n a
ncepe lista de adiacen a nodului n (n+2m+1 doua seciune a primei linii a matricei (L[0][j]=i,
DI

- L[1][n]). Lungimea listei de adiacen se mai cu j=n+1,n+m).


poate determina prin numrarea n linia a doua
a elementelor diferite de 0, ncepnd cu
elementul din coloana L[1][i]), la care se
RA

adaug 1.
Gradul unui nod i este egal cu lungimea listei
de adiacen a nodului sau cu numrul de
apariii ale etichetei nodului n a doua seciune a
primei linii a matricei (L[0][j]=i, cu
TU

j=n+1,n+2*m).
Nodurile adiacente nodului i sunt nodurile a Succesorii nodului i sunt nodurile a cror
cror etichet apare n lista de adiacen a etichet apare n lista de adiacen a nodului i.
nodului i. Predecesorii nodului i sunt nodurile j n a
I

cror list de adiacen apare nodul i.


ED
Informatic 191

C
Graf neorientat Graf orientat
Nodurile adiacente nodului i sunt date de
reuniunea dintre mulimea succesorilor i

I
mulimea predecesorilor nodului.

OG
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
gradul nodului. cardinalul mulimii de noduri adiacente nodului i.
Muchia [i,j] a grafului reprezint nodul i i un nod j Arcul [i,j] al grafului reprezint nodul i i un nod
din lista de adiacen a nodului i din prima linie a j din lista de adiacen a nodului i din vectorul L
matricei (L[0][j]Li). (L[0][j]Li)

AG
Din lista de adiacen implementat static cu doi vectori putei obine urmtoarele informaii:
Graf neorientat Graf orientat
Lungimea listei de adiacen a nodului i Lungimea listei de adiacen a nodului i

ED
neizolat, cu eticheta mai mic dect n, este neizolat, cu eticheta mai mic dect n, se
egal cu diferena dintre primul indice j (j=i+1,n-1) calculeaz la fel ca i n cazul grafului
diferit de 0, din vectorul cap (cap[j]0), i neorientat. Pentru nodul n, lungimea listei de
indicele elementului de la care ncepe lista de adiacen este egal cu (m+1 - cap[n]).

P
adiacen a nodului i (cap[j] - cap[i]). Pentru Gradul extern al nodului i este egal cu
nodul n, lungimea listei de adiacen este egal lungimea listei de adiacen a nodului.
cu diferena dintre numrul total de elemente Gradul intern al nodului i este egal cu
I
ale vectorul L, plus 1, i indicele elementului din numrul de apariii ale etichetei nodului n
care ncepe lista de adiacen a nodului n vectoul listei L (L[j]=i, cu j=1,m).
(2m+1 - cap[n]).

Gradul unui nod i este egal cu lungimea listei


de adiacen a nodului sau cu numrul de
IC

apariii ale etichetei nodului n vectorul listei L


(L[j]=i, cu j=1,2*m).
Nodurile adiacente nodului i sunt nodurile a Succesorii nodului i sunt nodurile a cror
CT

cror etichet apare n lista de adiacen a etichet apare n lista de adiacen a nodului i
nodului i din vectorul L. din vectorul L.
Predecesorii nodului i sunt nodurile j n a
cror list de adiacen din vectorul L apare
DA

nodul i.
Nodurile adiacente nodului i sunt date de
reuniunea dintre mulimea succesorilor i
mulimea predecesorilor nodului.
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
DI

gradul nodului. cardinalul mulimii de noduri adiacente nodului i.


Muchia [i,j] a grafului reprezint nodul i i un nod j Arcul [i,j] al grafului reprezint nodul i i un nod
din lista de adiacen a nodului i din vectorul L j din lista de adiacen a nodului i din vectorul L
(L[j]Li). (L[j]Li).
RA

Din lista de adiacen implementat dinamic putei obine urmtoarele informaii:


Graf neorientat Graf orientat
TU

Numrul de elemente din toate listele simplu Numrul de elemente din toate listele simplu
nlnuite este egal cu 2m (dublul numrului nlnuite este egal cu m (numrul de arce).
de muchii).
Lungimea listei de adiacen a nodului i este Lungimea listei de adiacen i este egal cu
egal cu numrul de noduri ale listei ce are numrul de noduri ale listei care are adresa
I
ED

adresa nodului prim egal cu L[i]. nodului prim egal cu L[i].


192 Implementarea structurilor de date

C
Graf neorientat Graf orientat
Gradul unui nod i este egal cu lungimea listei Gradul extern al nodului i este egal cu
de adiacen. lungimea listei de adiacen a nodului.

I
Gradul intern al nodului i este egal, cu

OG
numrul de apariii ale etichetei nodului n
toate listele simplu nlnuite.
Nodurile adiacente nodului i sunt nodurile a Succesorii nodului i sunt nodurile a cror
cror etichet apare n lista ce are adresa etichet apare n lista ce are adresa nodului
nodului prim egal cu L[i]. prim egal cu L[i].

AG
Predecesorii nodului i sunt nodurile j n ale
cror liste (ce au adresa nodului prim egal cu
L[j]) apare nodul i.
Nodurile adiacente nodului i sunt date de

ED
reuniunea dintre mulimea succesorilor i
mulimea predecesorilor nodului.
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
gradul nodului. cardinalul mulimii de noduri adiacente nodului i.

P
Muchia [i,j] a grafului reprezint nodul i i un nod j Arcul [i,j] al grafului reprezint nodul i i un nod j
din lista ce are adresa nodului prim egal cu L[i]. din lista ce are adresa nodului prim egal cu L[i].

1. Scriei lista de adiacen (folosind cele trei metode de implementare) a


I
Tem grafului neorientat G4. Folosind informaiile din lista de adiacen,
determinai: gradul nodului 5, nodurile izolate i nodurile terminale.
2. Scriei lista de adiacen a grafului orientat G14. Se vor folosi cele trei metode de

implementare. Ce proprietate are acest graf?


3. Scriei lista de adiacen a grafului orientat G8 (folosind cele trei metode de implemen-
IC

tare). Folosind informaiile din lista de adiacen, determinai: gradul intern al nodului 5,
gradul extern al nodului 4, succesorii i predecesorii nodului 2 i predecesorii nodului 3.
4. Scriei lista de adiacen a grafului orientat G11. Se vor folosi cele trei metode de imple-
CT

mentare. Din lista de adiacen, determinai: gradul intern al nodului 5, gradul extern al
nodului 2, nodurile adiacente nodului 5, succesorii i predecesorii nodului 4, nodurile
terminale i nodurile izolate.
G
G
G111888 5. Scriei lista de adiacen a grafului orientat G18 din figura 13.
DA

Se vor folosi cele trei metode de implementare.


6. Scriei lista de adiacen a grafului G13. Se vor folosi cele trei
metode de implementare. Cum identificai n fiecare imple-
mentare a listei de adiacen nodul surs al grafului? Fig 13
DI

7. Scriei lista de adiacen a grafului G14. Se vor folosi cele


trei metode de implementare. Cum identificai n fiecare implementare a listei de
adiacen nodul destinaie al grafului?
RA

Implementarea algoritmilor pentru reprezentarea grafurilor cu lista de adiacen


1. Crearea listei de adiacen n implementare static prin citirea listelor de vecini
din fiier. Determinarea gradului unui nod. Obinerea matricei de adiacen din
TU

matricea listei de adiacen.


ntr-un fiier text se gsesc urmtoarele informaii despre un graf neorientat (i varianta
orientat): pe prima linie, valorile pentru numrul de noduri n i numrul de muchii m,
desprite prin spaiu, iar pe urmtoarele n linii, desprite prin spaiu, numrul de vecini ai
I

unui nod i lista vecinilor (i varianta numrul de succesori ai unui nod i lista succesorilor).
ED
Informatic 193

C
Se citesc din fiierul text aceste informaii i se creeaz lista de adiacen implementat cu
matrice, respectiv cu vectori. Se afieaz nodurile cu gradul cel mai mare (i varianta cu
gradul extern cel mai mare). Se obine matricea de adiacen din lista de adiacen. Se

I
salveaz apoi matricea de adiacen ntr-un fiier text. n fiierul text se scriu: pe primul

OG
rnd ordinul grafului, iar pe urmtoarele rnduri liniile matricei de adiacen. Funcia
citeste() se folosete pentru a citi listele de adiacen din fiier, funcia grad() pentru
a determina gradul (i varianta gradul extern) al unui nod, funcia grad max() pentru a
determina gradul maxim (i varianta gradul extern maxim) al nodurilor din graf, funcia

AG
transpune() pentru a obine matricea de adiacen din lista de adiacen, iar funcia
scrie() pentru a scrie matricea de adiacen n fiier. Informaiile se citesc din fiierul text
graf13.txt, pentru graful neorientat, i graf14.txt, pentru graful orientat, i se salveaz n
fiierul text graf15.txt, pentru graful neorientat, i graf16.txt, pentru graful orientat. Fiierele
text graf13.txt i graf14.txt se creeaz cu un editor de texte. Pentru testarea programelor se

ED
folosesc graful neorientat G1 i graful orientat G9.
Graful neorientat i graful orientat implementarea cu matrice
#include<fstream.h>

P
int n,m,L[3][50],a[10][10];
//pentru graful neorientat
fstream f1("graf13.txt",ios::in),f2("graf15.txt",ios::out);
I
//pentru graful orientat
//fstream f1("graf14.txt",ios::in),f2("graf16.txt",ios::out);
void citeste()
{int i,j,x,k; f1>>n>>m;

for(i=1;i<=n;i++) L[1][i]=i; j=n+1;


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

{f1>>x;
if (x==0) L[2][i]=0;
else {L[2][i]=j;
CT

for (k=1;k<=x;k++) {f1>>L[1][j];


if(k!=x) L[2][j]=j+1;
else L[2][j]=0;
j++;}}}
DA

f1.close();}
int grad(int i)
{int g,j=L[2][i];
if (L[2][i]==0) g=0;
else {g=1;
DI

while (L[2][j]!=0) {g++;j++;}}


return g;}
int grad max()
{int i,max=0;
RA

for (i=1; i<=n; i++) if (grad(i)>max) max=grad(i);


return max;}
void transpune()
{int i,j;
TU

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


{j=L[2][i];
if (L[2][i]!=0)
{while (L[2][j]!=0) {a[i][L[1][j]]=1; j++;}
I

a[i][L[1][j]]=1;}}}
ED
194 Implementarea structurilor de date

C
void scrie()
{int i,j; f2<<n<<endl;
for (i=1; i<=n; i++)

I
{for (j=1; j<=n; j++) f2<<a[i][j]<<" "; f2<<endl;}

OG
f2.close();}
void main()
{int i; citeste();
cout<<"Gradul cel mai mare este "<<grad max()<<endl;
cout<<"Nodurile cu gradul cel mai mare sunt: ";

AG
for (i=1; i<=n; i++) if (grad(i)==grad_max()) cout<<i<<" ";
transpune(); scrie();}
Graful neorientat i graful orientat implementarea cu vectori.
#include<fstream.h>

ED
int n,m, L[50],a[10][10],cap[10];
//pentru graful neorienat
fstream f1("graf13.txt",ios::in),f2("graf15.txt",ios::out);
//pentru graful orienat

P
//fstream f1("graf14.txt",ios::in),f2("graf16.txt",ios::out);
void citeste()
{int i,j=1,x,k; f1>>n>>m;
I
for(i=1;i<=n;i++)
{f1>>x;
if (x==0) cap[i]=0;
else {cap[i]=j;

for (k=1;k<=x;k++) {f1>>L[j]; j++;}}}


f1.close();}
IC

int grad(int i)
{int g,j;
if (cap[i]==0) g=0;
CT

else
{if (i<n) {j=i+1;
while (cap[j]==0 && j<=n) j++;
if (j==n+1) g=2*m+1-cap[i];
DA

// g=m+1-cap[i]; pentru graful orientat


else g=cap[j]-cap[i];}
else g=2*m+1-cap[i];}
return g;}
int grad max() {//este identic cu cea de la implementarea cu matrice}
DI

void transpune()
{int i,j;
for (i=1; i<=n; i++)
for (j=0;j<grad(i);j++) a[i][L[cap[i]+j]]=1;}
RA

void scrie() {//este identic cu cea de la implementarea cu matrice}


void main() {//este identic cu cea de la implementarea cu matrice}
2. Crearea listei de adiacen n implementare static din matricea de adiacen.
TU

Salvarea listelor de adiacen ntr-un fiier.


Se citete din fiierul creat anterior (graf15.txt, respectiv graf16.txt) matricea de adiacen a
grafului i se obine din ea lista de adiacen implementat cu matrice, respectiv cu vectori.
Se salveaz listele de adiacen ntr-un fiier text (graf17.txt, respectiv graf18.txt), astfel: pe
I

prima linie, valorile pentru numrul de noduri n i numrul de muchii m, desprite prin
ED
Informatic 195

C
spaiu, iar apoi, pe urmtoarele n linii, desprite prin spaiu, numrul de vecini ai unui nod
i lista vecinilor pentru graful neorientat, respectiv numrul de succesori ai unui nod i lista
succesorilor pentru graful orientat. Funcia citeste() se folosete pentru a citi matricea

I
de adiacen din fiier, funcia transpune() pentru a obine lista de adiacen din

OG
matricea de adiacen, iar funcia scrie() pentru a scrie listele de adiacen n fiier.
Pentru testarea programelor se folosesc graful neorientat G1 i graful orientat G9.
Graful neorientat i graful orientat implementarea cu matrice
#include<fstream.h>

AG
int n,m,L[3][50],a[10][10];
//pentru graful neorientat
fstream f1("graf15",ios::in),f2("graf17.txt",ios::out);
//pentru graful orientat

ED
//fstream f1("graf16.txt",ios::in),f2("graf18.txt",ios::out);
void citeste()
{int i,j; f1>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {f1>>a[i][j]; if(a[i][j]==1) m++;} f1.close();

P
m=m/2;} //numai pentru graful neorientat
void transpune()
{int i,j,k,g;
I
for(i=1;i<=n;i++) L[1][i]=i; k=n+1;
for(i=1;i<=n;i++)
{for(j=1,g=0;j<=n;j++)
if (a[i][j]==1) {L[1][k]=j; L[2][k]=k+1; k++; g++;}

if (g==0) L[2][i]=0;
else {L[2][i]=k-g; L[2][k-1]=0;}}}
IC

int grad(int i) {//identic cu cea de la implementarea cu matrice}


void scrie()
{int i,j=1,k; f2<<n<<" "<<m<<endl;
CT

for (i=1;i<=n;i++)
if (L[2][i]==0) f2<<0<<endl;
else {f2<<grad(i)<<" ";
for (k=1;k<=grad(i);k++,j++) f2<<L[1][j]<<" ";
DA

f2<<endl;} f2.close();}
void main()
{citeste(); transpune(); scrie();}
Graful neorientat i graful orientat implementarea cu vectori
DI

#include<fstream.h>
int n,m,L[50],cap[10],a[10][10];
//pentru graful neorientat
fstream f1("graf13.txt",ios::in),f2("graf15.txt",ios::out);
RA

//pentru graful orientat


//fstream f1("graf14.txt",ios::in),f2("graf16.txt",ios::out);
void citeste() {//este identic cu cea de la implementarea cu matrice}
void transpune()
TU

{int i,j,k=1,g;
for(i=1;i<=n;i++)
{for(j=1,g=0;j<=n;j++) if (a[i][j]==1) {L[k]=j; k++; g++;}
if(g==0) cap[i]=0; else cap[i]=k-g;}}
I

int grad(int i) {//identic cu cea de la implementarea cu vectori}


ED
196 Implementarea structurilor de date

C
void scrie()
{int i,j; f2<<n<<" "<<m<<endl;
for(i=1;i<=n;i++)

I
{f2<<grad(i)<<" ";

OG
for(j=0;j<grad(i);j++) f2<<L[cap[i]+j]<<" ";
f2<<endl;}
f2.close();}
void main() {//este identic cu cea de la implementarea cu matrice}
3. Crearea listei de adiacen n implementare dinamic prin citirea listei muchiilor

AG
din fiier. Determinarea vecinilor i a gradului unui nod.
ntr-un fiier text se gsesc urmtoarele informaii despre un graf neorientat (i varianta
orientat): pe prima linie, valorile pentru numrul de noduri n i numrul de muchii m, iar de pe

ED
urmtoarele m linii, cte o pereche de numere desprite prin spaiu, care reprezint etiche-
tele nodurilor ce formeaz o muchie (arc). Se citesc din fiierul text aceste informaii i se
creeaz lista de adiacen implementat dinamic. Se afieaz vecinii i gradul fiecrui nod.
Funcia init() se folosete pentru a iniializa cu valoarea NULL elementele vectorului L

P
(pointerii nodului prim al listei de adiacen a fiecrui nod din graf), funcia adauga nod()
pentru a aduga un nod naintea nodului prim la lista simplu nlnuit a unui nod din graf,
funcia creare() pentru a crea lista de adiacen, funcia grad() pentru a determina
I
gradul (i varianta, gradul extern) al unui nod, funcia afisare_vecini() pentru a afia
vecinii fiecrui nod, iar funcia afisare_grad() pentru a afia gradul fiecrui nod. Infor-
maiile se citesc din fiierul text graf11.txt pentru graful neorientat i graf12.txt pentru graful
orientat. Pentru testarea programelor se folosesc graful neorientat G1 i graful orientat G9.

#include<fstream.h>
struct nod {int info;
IC

nod * urm;};
nod *L[20];
int n,m;
CT

fstream f1("graf11.txt",ios::in);
void init()
{f>>n>>m; for (int i=1;i<=n;i++) L[i]=NULL;}
void adauga nod(nod *&prim, int y)
DA

{nod *p=new nod; p->info=y; p->urm=prim; prim=p;}


void creare()
{int x,y;
while (f>>x>>y) {adauga nod(L[x],y);adauga nod(L[y],x);}
DI

f.close();}
void afisare vecini()
{for (int i=1;i<=n;i++)
{cout<<"Vecinii nodului "<<i<<": ";
RA

for (nod *p=L[i];p!=NULL;p=p->urm) cout<<p->info<<" ";


cout<<endl;}}
int grad(int i)
{int g=0;
for (nod *p=L[i];p!=NULL; p=p->urm) g++; return g;}
TU

void afisare grade()


{for (int i=1;i<=n;i++)
cout<<"Gradul nodului "<<i<<": "<<grad(i)<<endl;}
void main()
I

{init(); creare(); afisare vecini(); afisare grade();}


ED
Informatic 197

C
1. Scriei un program care citete listele de adiacen ale grafului din
Tem fiierul text graf13.txt, pentru graful neorientat, respectiv din fiierul
graf14.txt, pentru graful orientat, i care afieaz nodurile izolate.

I
Listele de adiacen se implementeaz dinamic i static, n cele dou variante.

OG
2. Scriei un program care citete listele de adiacen ale grafului din fiierul text graf13.txt,
pentru graful neorientat, respectiv din fiierul graf14.txt, pentru graful orientat, i care
afieaz muchiile (arcele) grafului. Listele de adiacen se implementeaz dinamic i
static n cele dou variante.

AG
3. Scriei un program care citete din dou fiiere text, respectiv din g5.txt un graf orientat,
reprezentat prin lista muchiilor, i din fiierul g6.txt un graf orientat, reprezentat prin lista
vecinilor, i care verific dac cele dou grafuri sunt identice (Indicaie. Se reprezint
ambele grafuri prin matricea de adiacen i se compar cele dou matrice de adiacen).

ED
2.7.4.5. Aplicaii practice
1. ntr-un grup de n persoane s-au stabilit dou tipuri de relaii: de prietenie i de vecin-
tate. Scriei un program care s citeasc matricele de adiacen ale celor dou grafuri

P
dintr-un fiier text (pe primul rnd, numrul de persoane, i pe urmtoarele rnduri, n
ordine, liniile fiecrei matrice de adiacen) i care s afieze:
a. persoanele care sunt i prietene i vecini (Indicaie. Se determin muchiile din
I
graful intersecie a celor dou grafuri neorientate);
b. cel mai mare numr de persoane care se gsesc ntr-un grup de vecini prieteni
(Indicaie. Se determin gradul maxim n graful intersecie a celor dou grafuri.)

Pentru testarea programului formai un grup cu 10 dintre colegii votri i descriei cu


ajutorul a dou grafuri cele dou tipuri de relaii.
IC

2. ntr-un grup de n persoane s-a stabilit o relaie de cunotin: persoana x este n


relaie cu persoana y dac o cunoate pe aceasta. Relaia de cunotin nu este
CT

reciproc. O celebritate este o persoan care este cunoscut de toate persoanele din
grup, dar care nu cunoate nici o persoan (este un nod destinaie al grafului). Un
necunoscut este o persoan care cunoate toate persoanele din grup dar nu este
cunoscut de nici o persoan din grup (este un nod surs al grafului). Un singuratic
DA

este o persoan care cunoate o singur persoan din grup sau este cunoscut de o
singur persoan din grup (este un nod terminal al grafului). Un strin de grup este o
persoan care nu cunoate nici o persoan din grup i nu este cunoscut de nici o
persoan din grup (este un nod izolat al grafului). Demonstrai c n grup nu poate
DI

exista dect o singur celebritate i un singur necunoscut. Scriei un program care s


citeasc dintr-un fiier matricea de adiacen a grafului i care s afieze:
a. dac exist o celebritate, s se precizeze persoana, iar dac nu exist, s se
precizeze: persoana care cunoate cele mai puine persoane i persoana care este
RA

cunoscut de cele mai multe persoane;


b. dac exist un necunoscut, s se precizeze persoana, iar dac nu exist, s se
precizeze: persoana care este cunoscut de cele mai puine persoane i per-
soana care cunoate cele mai multe persoane;
TU

c. dac exist singuratici, s se precizeze persoanele;


d. dac exist strini de grup, s se precizeze persoanele;
e. cte persoane cunosc doar dou persoane din grup i sunt cunoscute la rndul
lor de trei persoane din grup (nodurile care au gradul intern egal cu 3, iar gradul
I
ED

extern egal cu 2);


198 Implementarea structurilor de date

C
f. cte persoane sunt cunoscute de un numr de membri egal cu numrul de
membri pe care i cunosc (nodurile care au gradul intern egal cu gradul extern);
g. care sunt persoanele care se cunosc reciproc (perechile de noduri ntre care

I
exist arce duble).

OG
3. La graful judeelor, adugai un nod cu eticheta 0, care reprezint exteriorul rii, i
muchiile corespunztoare, care evideniaz judeele limitrofe. Creai cu un editor de
texte fiierul judete.txt care s conin urmtoarele informaii: pe primul rnd, numrul de
judee, pe urmtoarele rnduri matricea de adiacen, pe urmtorul rnd, n ordinea

AG
etichetelor nodurilor, denumirile judeelor separate prin spaiu (pentru judeele care au
un nume format din mai multe cuvinte folosii ca separator linia de subliniere), pe
urmtorul rnd numele vecinilor Romniei separate prin spaiu, i apoi, cte un rnd
pentru fiecare jude limitrof, n care scriei separate prin spaiu urmtoarele informaii:

ED
eticheta nodului i ara (rile) cu care se nvecineaz, precizate prin numrul de ordine
din lista numelor. Scriei un program care s citeasc aceste informaii din fiier i s le
transpun ntr-o implementare a grafului, adecvat problemei, i care s afieze:
a. judeele care au cele mai multe judee vecine se va preciza numrul maxim de vecini

P
i numele judeelor care au aceast proprietate;
b. judeele care au cele mai puine judee vecine se va preciza numrul minim de vecini
i numele judeelor care au aceast proprietate;
I
c. judeele de la grani pentru fiecare jude se va preciza numele su i numele rilor
cu care se nvecineaz.
4. ntr-o zon turistic exist n localiti. ntre unele localiti exist legturi directe, fie

prin osele naionale, fie prin osele judeene. Legturile directe sunt caracterizate de
lungimea drumului, msurat n kilometri. Se vor folosi dou grafuri: Gn=(X,Un) pentru
IC

legturile prin osele naionale i Gj=(X,Uj) pentru legturile prin osele judeene. Cele
dou grafuri se vor citi din dou fiiere text, care conin pentru fiecare legtur direct,
pe cte un rnd, separate prin spaiu, cele dou etichete ale nodurilor asociate
CT

localitilor i distana dintre localiti. Scriei un program care s citeasc aceste


informaii din fiier i s le transpun ntr-o implementare a grafului, adecvat proble-
mei, i care s afieze:
DA

a. localitile la care nu ajung drumuri naionale (nodurile izolate, n primul graf);


b. cea mai scurt legtur direct dintre dou localiti se va preciza eticheta
nodurilor asociate localitilor, distana dintre localiti i tipul oselei prin care se
asigur legtura;
DI

c. pentru dou localiti precizate, a i b (etichetele nodurilor a i b se citesc de la


tastatur), s se precizeze dac exist legtur direct; dac exist, s se mai
precizeze tipul oselei i distana dintre localiti;
d. pentru o localitate p (eticheta p a nodului se citete de la tastatur), s se afieze
RA

toate localitile cu care are legturi directe i distana pn la aceste localiti


(Indicaie. Se determin graful reuniune a celor dou grafuri.);
e. localitatea care are cele mai multe legturi directe cu alte localiti i s se
afieze localitile cu care are legturi (nodul cu gradul maxim n graful reuniune).
TU

5. ntr-un munte exist n grote. Fiecare grot i se gsete la nlimea hi fa de baza


muntelui. ntre unele grote exist comunicare direct, prin intermediul unor tuneluri.
Exist i grote care comunic cu exteriorul. Desenai o reea ipotetic de grote i con-
I

struii matricea de adiacen a grafului neorientat asociat (grotele sunt nodurile, iar
ED
Informatic 199

C
tunelurile sunt muchiile). nlimile grotelor se vor memora ntr-un vector. Gsii o
modalitate de a evidenia grotele care comunic cu exteriorul. (Indicaie. Adugai la
graf nodul 0, care reprezint exteriorul muntelui.) Scriei matricea de adiacen i

I
vectorul cu nlimile grotelor, n fiierul text grote.txt. Scriei un program care s

OG
citeasc matricea de adiacen i vectorul din fiier i care s afieze:
a. numrul de tuneluri de comunicare (numrul de muchii ale grafului);
b. grotele care au legtur cu exteriorul (nodurile i pentru care exist muchie cu
nodul 0);

AG
c. grotele care comunic direct cu cele mai multe grote (nodurile cu cel mai mare grad);
d. grotele care nu comunic prin tuneluri cu alte grote (nodurile izolate);
e. cea mai nalt grot i cea mai joas grot care comunic cu exteriorul;
f. pentru o grot a crei etichet se citete de la tastatur, s se afieze grotele cu
care comunic direct, preciznd pentru fiecare tunel dac suie, coboar sau este

ED
la acelai nivel cu grota.
6. Reeaua de strzi dintr-un ora este format din strzi cu dou sensuri i strzi cu sens
unic de circulaie. Ea poate fi reprezentat printr-un graf orientat, n care interseciile sunt

P
nodurile, iar arcele sensul de circulaie pe strzile care leag dou intersecii (traficul
auto). Nodurile sunt intersecii de cel puin 3 strzi. Pentru a stabili prioritatea n intersecii
i pentru a fluidiza traficul interseciile vor fi modernizate. Pentru modernizare se vor folosi
I
panouri cu semne de circulaie, semafoare i se vor amenaja sensuri giratorii. Pentru
fiecare strad din care se poate intra n intersecie, se monteaz n intersecie un panou
cu semn pentru prioritate. Pentru fiecare strad pe care nu se poate intra din intersecie se
monteaz n intersecie un panou cu semnul de interzicere a circulaiei. n toate

interseciile vor fi montate panouri cu semne de circulaie, corespunztor strzilor incidente


IC

cu intersecia. Fiecare dintre aceste mijloace de modernizare are un cost: panoul cu semn
de circulaie costul c1, semaforul costul c2, i sensul giratoriu costul c3. Pentru a
stabili modul n care este modernizat fiecare intersecie, interseciile au fost clasificate n
CT

intersecii mici (intersecii cu 3 strzi, n care vor fi montate numai panouri cu semne de
circulaie), intersecii mari (intersecii cu 4 strzi, care vor fi semaforizate) i intersecii
foarte mari (intersecii cu peste 4 strzi, n care se vor amenaja sensuri giratorii). Desenai
o reea ipotetic de strzi i construii matricea de adiacen a grafului orientat asociat.
DA

Scriei matricea de adiacen n fiierul text strazi.txt. Scriei un program care s citeasc
matricea de adiacen din fiier i care s afieze:
a. interseciile la care nu se poate ajunge din nici o alt intersecie (nodurile care nu
au predecesori);
DI

b. interseciile de la care nu se poate ajunge la o nici o alt intersecie (nodurile care


nu au succesori);
c. dac exist intersecii fr nici o intersecie succesor sau fr nici o intersecie prede-
cesor, s se corecteze desenul reelei (prin adugarea unui numr minim de arce),
RA

astfel nct s nu existe asemenea intersecii i s se actualizeze i fiierul strazi.txt.


d. interseciile la care se poate ajunge direct din cele mai multe intersecii (nodurile
care au cel mai mare grad intern);
e. interseciile de la care se poate ajunge direct la cele mai multe intersecii
TU

(nodurile care au cel mai mare grad extern);


f. numrul de strzi pe care se circul n ambele sensuri (numrul de perechi de
noduri i i j pentru care, n matricea de adiacen, elementele a[i][j] i a[j][i] sunt
egale cu 1);
I
ED
200 Implementarea structurilor de date

C
g. numrul de intersecii mici, mari i foarte mari (clasificarea nodurilor n funcie de
numrul de noduri adiacente: noduri cu 3 noduri adiacente, cu 4 noduri adiacente
i cu cel puin 5 noduri adiacente);

I
h. numrul de panouri cu semne pentru prioritate care se vor folosi (suma gradelor

OG
interne ale nodurilor);
i. numrul de panouri cu semne pentru interzicerea circulaiei care se vor folosi
(diferena dintre suma gradelor externe ale nodurilor i numrul de strzi cu sens
dublu de circulaie);

AG
j. numrul de semafoare care se vor monta (suma gradelor interne ale nodurilor
care au 4 noduri adiacente);
k. costul de modernizare necesar pentru fiecare intersecie i costul total al moder-
nizrii.

ED
7. Pe un munte exist mai multe parcele cu fnee ale stenilor. Unele fnee au acces
direct la drumul stesc, altele nu. ntre proprietarii parcelelor vecine exist relaie de
prietenie sau nu. Dac doi proprietari vecini sunt prieteni, i permit unul altuia
accesul pe propria parcel. Pentru a transporta fnul, stenii care nu au acces la

P
drumul stesc, trebuie s treac peste parcelele altor steni, ca s ajung la el. Un
proprietar este considerat izolat dac nu are acces direct la drumul stesc i nici nu
este n relaie de prietenie cu vreunul dintre vecinii lui. Se vor folosi dou grafuri: unul
I
pentru a reprezenta relaia de vecintate a fneelor, iar altul pentru a reprezenta
relaia de prietenie dintre proprietari. Desenai o hart ipotetic a fneelor i stabilii
relaii ipotetice de prietenie ntre vecini. Construii matricele de adiacen ale celor

dou grafuri asociate. Scriei matricele de adiacen n fiierele text fanete.txt i


prieteni.txt. Scriei un program care s citeasc matricele de adiacen din fiiere i
IC

care s furnizeze urmtoarele informaii:


a. dac exist proprietari izolai, s se afieze lista proprietarilor vecini cu care
trebuie s stabileasc relaii de prietenie, pentru a ajunge la drumul stesc, i s
CT

se identifice vecinii care au acces direct la drumul stesc;


b. care este proprietarul cel mai neprietenos (care are cel mai mare procent de
vecini cu care nu este prieten).
DA

8. Se analizeaz migraia unei specii de psri cltoare pe perioada unui an. Migraia are
dou etape: migraia de toamn, cnd psrile migreaz din zonele reci ctre zonele
calde (migraia de la rece la cald), i migraia de primvar, cnd psrile migreaz din
zonele calde ctre zonele reci (migraia de la cald la rece). Fiecare etap a migraiei va
DI

fi reprezentat printr-un graf orientat. n graful migraiei de la rece la cald, nodurile care
aparin zonei reci au numai succesori, iar nodurile care aparin zonei calde au numai
predecesori. n graful migraiei de la cald la rece nodurile care aparin zonei calde au
numai succesori, iar nodurile care aparin zonei reci au numai predecesori. Fiecrui nod
RA

i se asociaz coordonatele geografice. Desenai cte o hart ipotetic pentru fiecare


etap de migraie. Construii, cu un editor de texte, fiierul migratie1.txt, care va conine
pe prima linie n1, numrul de noduri ale primului graf, pe urmtoarele n1 linii, matricea
de adiacen a grafului, i apoi, pe urmtoarele n1 linii, coordonatele geografice ale
TU

fiecrui nod de pe hart (sunt 6 entiti de informaie, separate prin spaiu: dou valori
numerice ntregi pentru latitudine, n grade i minute, i un caracter pentru emisfer,
dou valori numerice ntregi pentru longitudine, n grade i minute, i un caracter pentru
meridian). Construii cu un editor de texte fiierul migratie2.txt, care va conine acelai
I

tip de informaii, pentru cel de al doilea graf al migraiei. Scriei un program care s
ED
Informatic 201

C
citeasc aceste informaii din fiier, s le transpun ntr-o implementare a grafului
adecvat problemei (recomandare implementare prin matrice de adiacen i vector
de structuri pentru coordonatele geografice) i care s afieze urmtoarele informaii:

I
a. dac cele dou grafuri sunt corecte (dac a[i][j]=1, atunci a[j][i]=0 i produsul

OG
dintre gradul in