Sunteți pe pagina 1din 25

4.

3 Structuri de date alocate dinamic


Structurile de date alocate dinamic sunt structuri ale cror componente se aloc n
cursul execuiei programului (dinamic).
Exist mai multe tipuri de structuri dinamice: liniare, arborescente i reea.
Structurile liniare se mai numesc i liste.
Pentru alocarea dinamic a acestor structuri se utilizeaz variabilele dinamicce.
Variabile dinamice (pointeri)
Prin variabil dinamic (pointer) se nelege o variabil care reine la un moment
dat adresa de memorie a unei alte variabile.
Declararea unei variabile ponter se face astfel:
Pascal
C/C++
var <nume_variabil> : ^<tip>;

<tip> * <nume_variabil>;

Se mai spune c ^<tip> (n Pascal), respectiv, <tip>* (n C/C++) reprezint un nou


tip de date, numit tipul ponter.
De exemplu, declararea unei variabile p de tip pointer care reine adresa unei alte
variabile de tip ntreg, se face astfel:
Pascal
C/C++
var p : ^Integer;

int *p;

Pointerii sunt date care se memoreaz ntr-o zon special din memoria intern,
numit heap.
n Pascal este definit constanta NIL iar n C/C++ constanta NULL avnd ca
valoare pointerul care nu conine nici o adresa, adic ponterul nul.
Ca operatori specifici privind pointerii amintim:
- operatorul de refereniere (@ n Pascal, respectiv, & n C/C++), astfel c @x n
Pascal, respectiv, &x n C/C++ conine adresa variabilei statice x;
- operatorul de adresare (^ n Pascal, respectiv, * n C/C++), astfel c p^ n Pascal,
respectiv, *p n C/C++ conine valoarea pe care o adreseaz pointerul p.
Iat un exemplu de utilizare a variabilelor dinamice i a operatorilor specifici:
Pascal
C/C++
var x: Integer;
p: ^Integer;
Begin
x:=10;
p:=@x;
WriteLn;
Write('p^ este chiar x: ', p^);
End.

#include <iostream.h>
void main(void)
{
int x=10, *p;
cout<<"\nVar. x e la adr: "<<&x;
cout<<" si are valoarea: "<<x;
cout<<"\nVar. p are val.: "<<p;
p=&x;
cout<<" adresand obiectul: "<<*p;
*p=20;
cout<<"\nSi acum x are val.: "<<x;
}

n continuare utilizm cteva funcii specifice tipului pointer (cu precizarea c n


C++ sunt operatori i nu funcii):
- funcia de alocare a spaiului de memorie pentru o variabil pointer p
Pascal
C
C++
new(p);

(<tip*)malloc(<tip>
p= new <tip>;
// <tip> este tipul variabilei spre care indic pointerul p

- funcia de eliberare a spaiului de memorie ocupat de o variabil pointer p


Pascal
C
C++
dispose(p);

free(p);

delete p;

- funcia ce verific dac exist spaiu disponibil n HEAP pentru a fi alocat variabilei
pointer p
Pascal
C/C++
maxavail();

void malloc(unsigned nr_octei);

Funcia maxavail din Pascal ntoarce dimensiunea celei mai mari zone de memorie
din heap, iar funcia malloc din C/C++ ntoarce un pointer care conine adresa primului
octet al zonei alocate, ns, dac spaiul disponibil este insuficient, funcia ntoarce
valoarea NULL (=0). Exemplu:
Pascal
C/C++
if sizeof(int)<=maxavail() then
p=new()
else
WriteLn(Zona HEAP plina!);

if (malloc(sizeof(int))
p=new int;
else
cout<<Zona HEAP plina!;

Pentru uurina expunerii, n continuare nu vom face verificri de alocare de spaiu


n heap (dar vom utiliza funciile i operatorii att pentru C ct i pentru C++).

4. 3. 1 Liste simplu nlnuite (definiie, operaii specifice descrise n


limbaj de programare)
Prin list (sau list liniar) nelegem un ir finit (eventual vid) de elemente (numite
i noduri sau componente) aparinnd unei mulimi date E={e1, e2, , en} care au
urmtoarele proprieti:
- exist o relaie de ordine ntre elementele listei n aa fel nct orice element ei
are ca predecesor pe ei-1 i ca successor pe ei+1;
- exist un element n list, i anume e1 (primul element), care nu are nici un
predecesor i care este numit capul listei sau baza listei;
- exist un element n list, i anume en (ultimul element), care nu are succesor i
care este numit element terminal al listei sau vrful listei.
Prin urmare, lista este o structur de date ntre ale carei componente exist o relaie
de ordine (fiecare element al listei are un singur succesor, cu excepia ultimului
element din list care nu are nici un succesor i un singur predecesor, cu execpia
primului element din list care nu are nici un predecesor).
Exemple de liste: elementele unui vector, irul format din numele din cartea de
telefon (lista abonailor), elementele unui tablou oarecare pentru care exist o ordine de
memorare etc.
Componentele (elementele) unei liste pot fi date elementare (ntregi, caractere, etc.)
sau date structurate.
Memorarea listelor se poate face n mai multe moduri, n continuare prezentndu-se
dou dintre ele.
Alocarea secvenial const n a memora elementele listei n locaii succesive de
memorie, conform ordinei acestor elemente n list i n acelai timp se memoreaz
adresa de baz (adresa primului element al listei). Un exemplu tipic este cel n care
elementele listei sunt memorate ntr-un vector, adresa de baz fiind adresa primului
element al vectorului.
2

Alocarea nlnuit presupune c fiecare element al listei este nlocuit cu o celul


format din dou pri: o parte de informaie corespunztoare elementului i o parte de
legtur ce conine adresa celulei corespunztoare urmtorului element (adres numit
obinuit pointer). Ca i la alocarea secvenial, mai trebuie memorat o adres de baz
i, n plus, partea de legtur a ultimei celule primete o valoare ce nu poate desemna o
legtur (o valoare special, numit NIL n Pascal, respectiv NULL n C/C++ ce nu
reprezint nici o adres de memorie). Celulele vor fi reprezentate sub forma
inf urm
cu semnificaii evidente. Legturile vor fi precizate cu ajutorul unor sgei, ca n figura
urmtoare:


baza
vrful
O list definit astfel mai poart numele de list liniar simpl sau list liniar
asimetric, deoarece parcurgerea ei nu se poate face dect ntr-un singur sens, plecnd
de la capul listei spre vrful ei.
Pentru simplificarea expunerii, presupunem n continuare c informaia este o dat
de tip ntreg. n acest caz, implementarea unui nod al listei liniare simple se face astfel:
Pascal
C/C++
type pnod = ^nod;
nod = record
info :Integer;
urm: pnod;
end;

struct nod
{ int inf;
nod *urm;
}
typedef struct nod NOD;

Operaiile cele mai importante care se efectueaz cu listele sunt:


- crearea unei liste;
- parcurgerea i prelucrarea unei liste;
- adugarea unui nou element n list;
- tergerea unui element din list;
- ntoarcerea numrului de elemente ale listei (cardinalul su).
La adugarea unui nou nod n list sunt posibile urmtoarele situaii:
1. lista este vid i se adaug primul ei element:
2. lista nu e vid, caz n care nodul se poate aduga:
a. naintea nodului indicat de pointerul p, fiind posible dou situaii:
i. p indic primul element al listei;
ii. p nu indic primul element al listei;
b. dup nodul indicat de pointerul p, fiind posibile dou situaii:
i. p indic ultimul element din list;
ii. p nu indic ultimul element din list.
Pentru a evita aceste situaii, se poate recurge la un mic artificiu crend lista de la
nceput cu dou noduri fictive (n care nu se memoreaz nici o informaie) i astfel nu
mai apar attea cazuri pentru adugarea unui nou nod. Cele dou noduri fictive se mai
numesc santinele. n acest fel, la adugarea unui nou nod, nu mai este necesar
verificarea cazurilor particulare n care lista e vid sau n care dorim s adugam un
nou nod naintea primului nod din list sau dup ultimul nod din list.
Adugarea unui nou element dup un nod oarecare din list indicat de pointerul p
se face astfel:
3

INF

3.
4.

(2)

(3)

1.
2.

INF
INF

noul_nod
(1)
se aloc zona de memorie pentru noul_nod;
se copiaz n urm din noul_nod adresa urm din nodul indicat de p (adic
adresa nodului urmtor lui p, deci se face legtura cu succesorul noului nod);
se memoreaz adresa noul_nod n urm din p (deci legtura predecesorului
noului nod)
se memoreaz informaia n cmpul inf din noul_nod.
Varianta Pascal
Varianta C/C++

new(noul_nod);
noul_nod^.urm:=p^.urm;
p^.urm:=noul_nod;
ReadLn(noul_nod^.inf);

{1}
{2}
{3}
{4}

noul_nod=new NOD;
noul_nod->urm=p->urm;
p->urm=noul_nod;
cin<<noul_nod->inf;

//
//
//
//

1
2
3
4

Facem observaia c trebuie respectat cu strictee ordinea operaiilor deoarece, de


exemplu, dac s-ar efectua operaia 3 naintea operairei 2, s-ar pierde adresa nodului
care urma iniial dup p (n mod iremediabil). Doar operaia 4 poate fi efectuat
oriunde dup operaia 1 (adic, oricnd, dup ce s-a alocat spaiu pentru noul nod).
ntr-o list simplu nlnuit putem aduga un nou nod i naintea unui nod indicat
de un pointer p, ns printr-un mic artificiu. De fapt crem noul nod tot dup cel indicat
de p, mutm n el informaia din nodul indicat de p (aflat n faa noului nod) dup care
noua informaie o depunem n nodul din fa, momentan indicat de p (dup care p va
memora adresa nodului introdus n list).
Varianta Pascal
Varianta C/C++
new(noul_nod);
noul_nod^.urm:=p^.urm;
p^.urm:=noul_nod;
noul_nod^.inf:=p^.inf;
ReadLn(p^.inf);
p:=noul_nod;

{1}
{2}
{3}
{4}
{5}
{6}

noul_nod=new NOD;
noul_nod->urm=p->urm;
p->urm=noul_nod;
noul_nod->inf=p->inf;
cin<<p->inf;
p=noul_nod;

//
//
//
//
//
//

1
2
3
4
5
6

tergerea unui element n list, aflat dup un nod indicat de pointerul p se face
astfel:
(2)
INF
INF
p

INF
(1) nod_el

1. se memoreaz n pointerul nod_el adresa succesorului lui p (adic adresa


nodului ce urmeaz a fi eliminat);
4

2. se copiaz n urm din nodul indicat de p adresa nodului ce urmeaz dup nodul
ce se va elimina (adic se face legtura cu succesorul nodului ce se va elimina);
3. se elibereaz zona de memorie ocupat de nodul ce se elimin.
Pascal
C
C++
nod_el:=p^.urm;
{1}
p^.urm:=p^.urm^.urm;{2}
dispose(nod_el);
{3}

nod_el=p->urm;
//1
p->urm=p->urm->urm;//2
free(nod_el);
//3

nod_el=p->urm; // 1
p->urm=p->urm>urm;//2
delete nod_el; // 3

Ca i la adugarea unui nou nod n list, i la tergerea unui nod din list sunt
posibile mai multe situaii. Listele create cu santinele elimin verificarea unor cazuri
particulare ca, de exemplu, cel n care dorim s eliminm ultimul nod din list sau cel
n care dorim eliminarea unui nod aflat dup cel indicat de p i pointerul p l indic
chiar pe ultimul (deci, dup el nu mai exist nici un nod care sa poat fi eliminat).
Un caz particular este i eliminarea nodului din capul listei:
Pascal
C
C++
nod_el:=cap;
{1}
cap:=cap^.urm;
{2}
dispose(nod_el); {3}

nod_el=cap;
// 1
cap=cap->urm; // 2
free(nod_el
// 3

nod_el=cap;
// 1
cap=cap->urm; // 2
delete nod_el; // 3

Implementarea crerii listei liniare simplu nlnuite se face astfel:


Pascal
C/C++
Program creare;
type pnod = ^nod;
nod = record
inf :Integer;
urm: pnod;
end;
var cap, p,noulnod: pnod;
n, i: Integer;
Begin
readln(n);
new(p); cap:=p;
readln(p^.inf); p^.urm:=NIL;
for i:=2 to n do
begin
new(noulnod);
readln(noulnod^.inf);
p^.urm:=noulnod;
p:=noulnod;
end;
p^.urm:=NIL;
End.

#include <iostream.h>
struct nod
{ int inf;
nod *urm;
};
typedef struct nod NOD;
NOD *cap, *p, *noulnod;
int n, i;
void main()
{
cin>>n;
p=new NOD; cap=p;
cin>>p->inf; p->urm=NULL;
for (i=2;i<=n;i++) {
noulnod=new NOD;
cin>>noulnod->inf;
p->urm=noulnod;
p=noulnod; };
noulnod->urm=NULL;
}

Pentru a parcurge lista creat, utilizm o structur repetitiv astfel:


Varianta Pascal
Varianta C/C++
p=cap;
while (p<>NIL)do
begin
Write(p->inf, " "); p=p^.urm
End

p=cap;
while (p!=NULL)
{
cout<<p->inf<<" "; p=p->urm;
}

adc iniializm pointerul p cu adresa capului listei, dup care, n mod repetat, afim
informaia (sau o prelucrm, n funcie de necesiti) iar prin instruciunea p:=p^urm
n Pascal, respectiv p=p->urm n C/C++, ne poziionm pe urmtoarea nregistrare
pn cnd ajungem la ultimul nod unde urmtoarea adres este NIL n Pacal, respectiv
5

NULL n C/C++. Adugai aceste instruciuni la sfritul programului anterior pentru a


afia lista creat.
Este evident c alocarea nlnuit necesit mai mult memorie dect cea
secvenial. Trebuie menionat ns c n aplicaii partea de informaie este mult mai
mare dect cea de legtur. Pe de alt parte, alocarea nlnuit elimin necesitatea
deplasrii de elemente pentru operaiile de introducere i de scoatere de elemente din
list. Un alt avantaj al alocrii nlnuite este acela c permite folosirea unui spaiu de
memorare comun pentru mai multe liste, ceea ce implic o economie de memorie,
avnd n vedere numeroasele operaii de introducere i de scoatere a elementelor din
list (liste).
n cazul n care se impun anumite restricii asupra operaiilor de inserare, tergere
sau consultare a elementelor unei liste liniare, se obin cteva cazuri perticulare de liste
mult folosite n practic: stiva, coada i lista cu dou capete.
Stiva
O list liniar n care inserrile, tergerile i regsirea elementelor se fac la un
singur capt al listei se numete stiv, pil, stack sau list LIFO (Last-IN, First-Out,
adic ultimul intrat va fi primul ieit).
Astfel de liste se utilizeaz mult n cadrul compilatoarelor i pentru scrierea de
programe reentrante (programe ce nu sunt modificate de propria execuie). Stiva este
utilizat la apelul subprogramelor i mai ales n recursivitate.
Coada
O list liniar n care inserrile elementelor se fac la un capt al listei (sfritul
listei), iar consultrile i tergerile de elemente se fac la cellalt capt al listei (capul
listei) se numete coad, fir de ateptare sau list FIFO (First-IN, First-Out, adic
primul intrat va fi primul ieit sau, mai bine spus, "primul venit - primul servit").
Astfel de liste se utilizeaz mult n sistemele de operare (n rutinele de alocare a
resurselor) sau n programe de simulare.
Lista cu dou capete
O list liniar n care inserrile, tergerile i regsirea elementelor se fac la ambele
capete ale listei.

4. 3. 2 Liste dublu nlnuite (definiie, operaii specifice descrise n


limbaj de programare)
Dac elementele unei liste liniare sunt formate din triplete de forma
ant inf urm
unde inf reprezinta informatia nodului, ant este adresa ctre predecesor (nodul
anterior), iar urm este adresa catre succesor (nodul urmtor), atunci se obine o list
liniar dublu nlnuit sau list liniar simetric, care se reprezint grafic astfel:

O astfel de list poate fi parcurs n ambele sensuri, deci prezint dou grade de
libertate.
Operaiile specifice listelor dublu nlnuite se bazeaz pe aceeai logic aa cum
am vzut la listele simplu nlnuite, doar c trebuie s inem seama c mai exist i
legtura spre elementul anterior i s dm mare atenie ordinii n care ralizm legturile
pentru a nu pierde informaii.
6

4. 3. 3 Liste circulare (definiie, operaii specifice descrise n limbaj


de programare)
Dac relaia de ordine dintre elementele unei liste liniare este n aa fel definit
nct ultimul element al listei are ca succesor primul element al listei, atunci se obine
un nou tip de list, i anume o list circular sau un inel. Reprezentarea grafic pentru
o list circular simplu nlnuit este urmtoarea:
INF
INF

INF

INF

INF
INF

INF
INF

O list circular poate fi asimetric sau simetric dup cum elementele listei sunt
dublete, respectiv triplete, adic conin un pointer sau doi pointeri.
Listele circulare se mai numesc i liste nchise, celelalte purtnd numelre de liste
deschise.
La operaiile specifice listelor circulare trebuie s inem cont, n plus, i de
legturile existente ntre ultimul nod i primul nod.
Atragem atenia asupra greelilor frecvente n utilizarea alocrii dinamice pentru
liste:
- nerespectarea succesiunii corecte a operaiilor;
- prelucrarea (citirea, atribuirea) informaiilor naintea alocrii dinamice;
- stabilirea incorect a legturilor (de exemplu, pentru listele circulare la capete se uit
s se nchid cercul de legturi, iar pentru cele necirculare se uit s se stabileasc
legtura nul);
- n momentul tergerii sau inseriei unui nod nu se actualizeaz corect legturile;
- pierderea poziiei capului listei;
- tergerea unui nod naintea prelurii (memorrii) legturii urmtoare;
- inseria unui nod naintea gsirii nodului anterior.

4. 3. 4 Teste gril (de la Bac)


1. Structura de date la care se aplic principiul primul venit, primul ieit: (first in,
first out) este:
a. lista nlnuit
b. stiva
c. Coada
d. Graf orientat
Bacalaureat 2009 (varianta 25, II. 1)
2. Nodurile unei liste dublu nlnuite rein n cmpurile info, adp i adu o informaie
numeric, adresa nodului precedent i respectiv adresa nodului urmtor din list.
tiind c lista este corect construit i c dou noduri p i q ale acesteia se
nvecineaz, atunci:
Varianta Pascal
7

a. p^.adp=q^.adu b. p^.adu=q^.adu

c. p^.adp=q

Varianta C/C++
a. p->adp==q->adu b. p->adu==q->adu c. p->adp==q
3.

a.

a.
4.

a.

a.
5.

d. p^.adp=q^.adp
d. p->adp==q->adp

Bacalaureat 2006 (Simulare - subiectul I.6)


Varianta Pascal
Se consider o list simplu nlnuit ale crei noduri rein n cmpul urm adresa
nodului urmtor al listei sau nil dac nu exist un element urmtor. Pentru
inserarea unui nod aflat la adresa p imediat dup un nod al listei aflat la adresa q
se utilizeaz unele dintre urmtoarele atribuiri: 1) p^.urm:=q 2) q^.urm:=p 3)
p:=q^.urm 4) q:=p^.urm 5) p^.urm:=q^.urm 6) q^.urm:=p^.urm
Stabilii care dintre acestea se utilizeaz i n ce ordine:
36
b. 2 4
c. 5 2
d. 2 3
Varianta C/C++
Se consider o list simplu nlnuit ale crei noduri rein n cmpul urm adresa
nodului urmtor al listei sau NULL dac nu exist un element urmtor. Pentru
inserarea unui nod aflat la adresa p imediat dup un nod al listei aflat la adresa q,
se utilizeaz unele dintre urmtoarele atribuiri: 1) p->urm=q; 2) q->urm=p; 3)
p=q->urm; 4) q=p->urm; 5) p->urm=q->urm; 6) q->urm=p->urm; .
Stabilii care dintre acestea se utilizeaz i n ce ordine:
36
b. 2 4
c. 5 2
d. 2 3
Bacalaureat 2006 (Simulare - subiectul I.7)
Varianta Pascal
ntr-o list simplu nlnuita, cu cel puin patru elemente, fiecare element reine n
cmpul urm adresa elementului urmtor din list. Dac p, q i r sunt adresele a
trei elemente din list astfel nct p^.urm=q^.urm^.urm i r^.urm=q atunci
ordinea logic a elementelor n list (elementele fiind identificate prin adrese)
este:
q. r, p
b. p, r. q
c. r, q, p
d. P, q, r
Varianta C/C++
Lntr-o list simplu nlnuit, cu cel puin patru elemente, fiecare element reine
n cmpul urm adresa elementului urmtor din list. Dac p, q i r sunt adresele a
trei elemente din list astfel nct p->urm==q->urm->urm i r->urm==q atunci
ordinea logic a elementelor n list (elementele fund identificate prin adrese)
este:
q. r, p
b. p, r. q
c. r, q, p
d. P, q, r
Bacalaureat 2007 (Varianta 1. subiectul I.4)
lntr-o list simplu nlnuit, cu cel puin patru elemente, fiecare element reine
n cmpul adr adresa elementului urmtor din list, iar q este adresa ultimului
element din list. Atunci p este adresa antepenultimului element din list dac
i numai dac este satisfcut condiia:
Varianta Pascal

a. q^.adr^.adr=p
c. p^.adr^.adr=q

b. p^.adr=q
d. q^.adr=p^.adr^.adr
8

Varianta C/C++
a. q->adr->adr==p
c. p->adr->adr==q

b. p->adr==q
d. q->adr==p->adr->adr
Bacalaureat 2007 (Varianta 3, subiectul I.4)
6. Lntr-o list simplu nlnuit, cu cel puin patru elemente, fiecare element reine
n cmpul urm adresa elementului urmtor din list, iar p memoreaz adresa
celui de-al treilea element din list. Atunci q reine adresa primului element din
list dac i numai dac este satisfcut condiia:
Varianta Pascal
a. p^.urm^.urm=q^.urm
c. q^.urm^.urm^.urm=p^.urm
a.
c.
7.

a.
c.

a.
c.
8.

b. p^.urm^.urm=q
d. q^.urm^.urm=p^.urm
Varianta C/C++
p->urm->urm==q->urm
b. p->urm->urm==q
q->urm->urm->urm==p->urm
d. q->urm->urm==p->urm
Bacalaureat 2007 (Varianta 4, subiectul I.5)
Varianta Pascal
lntr-o list simplu nlnuit, cu cel puin dou elemente, fiecare element reine n
cmpul urm adresa elementului urmtor din list, iar q memoreaz adresa
penultimului element din list. Dac p reine adresa unui element ce urmeaz a fi
adugat la sfritul listei i p^.urm are valoarea nil, stabilii care din urmtoarele
este o operaie corect de adugare:
p^.urm=:q
b. q^.urm=:p
q^.urm^.urm =:p
d. p^.urm^.urm=:q
Varianta C/C++
lntr-o list simplu nlnuit, cu cel puin dou elemente, fiecare element reine n
cmpul urm adresa elementului urmtor din list, iar q memoreaz adresa
penultimului element din list. Dac p reine adresa unui element ce urmeaz a fi
adugat la sfritul listei i p->urm are valoarea NULL, stabilii care din
urmtoarele este o operaie corect de adugare:
p->urm=q
b. q->urm=p
q->urm->urm=p
d. p->urm->urm=q
Bacalaureat 2007 (Varianta 5, subiectul I.7)
lntr-o list simplu nlnuit, cu cel puin trei elemente, fiecare element reine n
cmpul nr un numr ntreg i n cmpul urm adresa urmtorului element din
list. Dac variabila prim reine adresa primului element din list, stabilii care
dintre urmtoarele secvene afieaz suma tuturor numerelor memorate n list
mai puin cele reinute de primul i ultimul element:
Varianta Pascal

a. s:=0; p:=prim;
while (p^.urm<>nil) do begin p:=p.^urm; s:=s+p^.nr end;
write(s)
b. s:=0; p:=prim;
while (p^.urm<>nil) do begin s:=s+p^.nr; p:=p.^urm end;
write(s)
9

c. s:=0; p:=prim^.urm;
while (p^.urm<>nil) do begin s:=s+p^.nr; p:=p.^urm end;
write(s)
d. s:=0; p:=prim;
while (p^.urm<>nil) do begin p:=p^.urm; s:=s+p^.nr end;
write(s-p^.nr)
Varianta C/C++
a. s=0; p=prim;
while (p->urm!=NULL) do { p=p->urm; s=s+p->nr ;}
cout<<s; / printf(%d,s);
b. s=0; p=prim;
while (p->urm!=NULL) do {s=s+p->nr ; p=p->urm;}
cout<<s; / printf(%d,s);
c. s=0; p=prim->urm;
while (p->urm!=NULL) do { s=s+p->nr ; p=p->urm;}
cout<<s; / printf(%d,s);
d. s=0; p=prim;
while (p->urm!=NULL) do { p=p->urm; s=s+p->nr ; }
cout<<s-p->nr; / printf(%d,s-p->nr);
Bacalaureat 2007 (Varianta 8, subiectul I.5)
9. ntr-o list circular simplu nlnuit alocat dinamic cu cel puin un element,
fiecare element reine n cmpul nr un numr ntreg i n cmpul urm adresa
urmtorului element din list. tiind c variabila p reine adresa unui element
din list i variabila t este de acelai tip cu variabila p, stabilii care dintre
urmtoarele secvene afieaz toate valorile memorate n elementel listei, fiecare
valoare fiind afiat exact o dat:
Varianta Pascal
a. t:=p;
b. t:=p;
while (t^ .urm<>p) do begin
repeat
write(t^.nr, ); t:=t^.urm
write(t^.nr, ); t:=t^.urm
end
until (t=p)
c. t:=p;
d. t:=p^.urm;
while (t<>p) do begin
repeat
write(t^.nr, ); t:=t^.urm
write(t^.nr, ); t:=t^.urm
end
until (t=p)
Varianta C/C++
a. t=p;
while(t->urm!=p){
cout<<t->nr<<" "; / printf("%d",t->nr);
t=t->urm; }
b. t=p;
do{
cout<<t->nr<<" "; / printf("%d ",t->nr)
t=t->urm;
}while(t!=p) ;
c. t=p;
10

while(t!=p){
cout<<t->nr<<","; / printf("%d",t->nr);
t=t->urm; }
d. t=p->urm;
do{
cout<<t->nr","; / printf <"%d", t->nr) ;
t=t->urm;
}while{t!=p) ;
Bacalaureat 2007 (Varianta 9, subiectul I.1)

4. 3. 5 Probleme rezolvate
1. ntr-o list liniar simplu nlnuit, alocat dinamic, cu cel puin 4 elemente,
fiecare element reine n cmpul urm adresa elementului urmtor sau NIL (n Pascal),
respectiv NULL (n C/C++) dac nu exist un element urmtor, iar n cmpul info o
valoare ntreag. tiind c variabila p reine adresa primului element din list, nlocuii
punctele de suspensie cu expresiile corespunztoare, astfel nct secvena urmtoare s
calculeze n variabila s suma tuturor valorilor elementelor listei.
Varianta Pascal
Varianta C/C++
s:=.....;
while ..... do
begin
p:=p^.urm;
s:=s+p^.info
end;
write(s);

s=...;
while ( ... )
{
p=p->urm;
s=s+p->info;
}
cout<<s; | printf(%d,s);

Bacalaureat 2009 (varianta 8, II. 4)


Rezolvare:
Varianta Pascal

Varianta C/C++

s:=p^info;
s=p->info;
while p^urm <> NIL do
while ( p->urm )
begin
{
p:=p^.urm;
p=p->urm;
s:=s+p^.info
s=s+p->info;
end;
}
write(s);
cout<<s; | printf(%d,s);
2. O list liniar simplu nlnuit, alocat dinamic, reine n cmpul info al
fiecrui element cte un numr natural din intervalul [1,10000], iar n cmpul adr,
adresa elementului urmtor din list sau NIL (n Pascal), respectiv NULL (n C/C++),
dac nu exist un element urmtor. Considernd c lista este creat i c adresa
primului element este reinut n variabila prim, s se scrie declarrile de tipuri i date
necesare i secvena de program PASCAL (respectiv C/C++) care afieaz pe ecran
numerele memorate n list, care sunt ptrate perfecte.
Exemplu: pentru lista

se vor afia numerele 25 i 16.

Bacalaureat 2009 (varianta 85, II. 5)


11

Rezolvare. Parcurgem lista element cu element, vom verifica dac elementul curent este ptrat
perfect, n caz afirmativ l vom afia
Varianta PASCAL
Varianta C/C++
type pnod=^nod;
nod=record
info:integer;
adr:pnod;
end;
var prim,q:pnod;
k:integer;
.....
q:=prim;
while(q<>Nil)do
begin
k:=q^.info;
if sqrt(k)=int(sqrt(k))
write(q^.info, );
q:=q^.adr;
end;

struct nod
{int info;
nod * adr;
};
nod * prim, *q;
int k;
...
q=prim;
while(q)
{k= q->info;
if(sqrt(k)==(int) sqrt(k))
cout<<q->info<< ;
q=q->adr;
}

3. S se scrie un program care s realizeze crearea, parcurgerea n sens direct i


n sens invers i tergerea unei liste simplu nlnuite n mod recursiv (informaia din
noduri este un numr ntreg).
Rezolvare. Vom aplica recursivitatea astfel:
pentru creare este definit subprogramul recursiv creare care ntoarce adresa
nodului cap i nu are nici un parametru. Mai nti se va aloca spaiu pentru nodul
carent. Se va introduce informaia acestuia i se va interoga utilizatorul dac dorete
introducerea altor noduri. Dac rspunsul este afirmativ se continu introducerea
apelnd recursiv subprogramul creare.
pentru parcurgerea direct se va defini subprogramul parcurgere care are ca
parametru adresa la nodul cap i nu ntoarce nici o valoare. Mai nti se va tipri
informaia nodului curent i apoi se vor parcurge celelalte noduri, apelnd recursiv
subprogramul parcurgere avnd ca parametru nodul urmtor.
pentru parcurgerea invers se definete subprogramul parcurg_inv care are ca
parametru adresa nodului cap i nu ntoarce nici o valoare. Se va parcurge mai nti
restul listei apelnd n mod recursiv subprogramul parcurg_inv avnd ca parametru
nodul urmtor i apoi se va tipri nodul curent, nemaifiind astfel nevoie de folosirea
unui cmp care s conin referina la nodul anterior. Observai cum schimbarea ordinii
dintre tiprire i apel n cele dou funcii furnizeaz cele dou moduri de parcurgere:
direct i invers (iar recursivitatea ne ajut s parcurgem n sens invers chiar i liste
simplu nlnuite).
pentru tergerea listei se va defini subprogramul tergere. Se va apela mai nti
tergerea restului listei, apelnd recursiv subprogramul tergere i apoi se va elimina
nodul curent.
Varianta Pascal
Varianta C/C++
Program parcurgere_recursiva;
uses Crt;
type nod = ^adr;
adr = record
inf:Integer;
leg:nod;
end;
var cap: nod;

#include <stdio.h>
#include <stdlib.h>
struct nod {int inf;
struct nod* leg;};
struct nod* creare();
void parcurgere(struct nod*);
void parcurgere_inv(struct nod*);
void stergere(struct nod*);

12

c: Char;
function creare:nod;
var inf:Integer;
p:nod;
begin
WriteLn('Informatia: ');
ReadLn(inf);
if sizeof(nod)<=maxavail then
begin
new(p);
p^.inf:=inf;
WriteLn('Continuati
introducerea? (y/n) ');
flush(input); c:=ReadKey;
if c<>'n' then
p^.leg:=creare
else p^.leg:=NIL;
creare:=p
end
else
WriteLn('Depasire heap!')
end;
procedure parcurgere(var p:nod);
begin
if(p<>NIL) then begin
Write(p^.inf,' ');
parcurgere(p^.leg)
end
end;
procedure parcurg_inv(var p: nod);
begin
if (p<>NIL) then
begin
parcurg_inv(p^.leg);
Write(p^.inf, ' ');
end
end;
procedure stergere(var p:nod);
begin
if (p<>NIL) then
begin stergere(p^.leg);
dispose(p); end
end;
Begin
cap:=creare;
WriteLn('Parcurgere cap-coada:');
parcurgere(cap); WriteLn;
WriteLn('Parcurgere inversa:');
parcurg_inv(cap);
stergere(cap);
End.

void main()
{struct nod* cap;
cap=creare();
puts("Parcurgere cap-coada ");
parcurgere(cap);
puts("Parcurgere inversa: ");
parcurgere_inv(cap);
stergere (cap);
}
struct nod *creare()
{int inf;
struct nod *p;
printf("Informatia: ");
scanf("%d",&inf);
p= (struct nod*)
malloc(sizeof(struct nod));
p->inf=inf; fflush(stdin);
printf("Continuati introducerea?
(y/n) ");
if (getchar()=='y')
p->leg=creare();
else p->leg=NULL;
return(p);
}
void parcurgere(struct nod *p)
{ if(p!=NULL) {
printf("%d ", p->inf);
parcurgere(p->leg);}
}
void parcurgere_inv(struct nod *p)
{ if (p!=NULL) {
parcurgere_inv(p->leg);
printf("%d ", p->inf);}
}
void stergere(struct nod *p)
{
if (p!=NULL){ stergere(p->leg);
free(p); }
}

4. S se efectueze suma i produsul a dou polinoame folosind liste simplu


nlnuite.
Rezolvare. Pentru aceasta vom face crearea unei liste corespunztoare coeficienilor
unui polinom. Lista va avea ca informaie gradul i coeficientul fiecruitermen de
13

coeficient nenul. Vom defini o funcie canonic care va elimina nodurile redundante
din lista de termeni ai unui polinom prin pstrarea fiecrui grad o singur dat: dac
exist dou noduri cu acelai grad, unul din ele va fi eliminat iar coeficientul celuilalt
va lua valoarea sumei coeficienilor celor doi termeni.
Pentru a calcula suma a dou polinoame este suficient s concatenm listele celor
dou polinoame ntr-o a treia list i s apelm subprogramul canonic pentru aceast
list.
Calculul produsului se va face prin procesarea tuturor perechilor de termeni (unul
din fiecare polinom) astfel:
- fiecare pereche va genera un nod n polinomul rezultat;
- gradul noului nod va fi egal cu suma gradelor nodurilor din pereche;
- coeficientul noului nod va fi egal cu produsul coeficienilor termenilor din pereche.
Dup parcurgerea tuturor perechilor se va apela subprogramul canonic.
Varianta Pascal
Varianta C/C++
Program
Suma_si_produs_polinoame;
Uses Crt;
type nod = ^adr;
adr= record
gr, cf: Integer;
urm: nod;
end;
var cap1,cap2,cap: nod;
i: Integer;
function creare:nod;
var cap,p,q: nod;
c:Char;
begin
new(cap); { aici }
Write; Write('Priumul coef. si
gr: ');
ReadLn(cap^.cf, cap^.gr);
cap^.urm:=NIL;
p:=cap; c:='y';
repeat
WriteLn('Continuati?');
flush(input);c:=ReadKey;
if (c='n') then break;
Write('Urm. coef. si gr: ');
new(q); { aici}
ReadLn(q^.cf, q^.gr);
q^.urm:=NIL;
p^.urm:=q; p:=q;
until False;
creare:=cap;
end;
procedure parcurgere(var p:nod);
var q: nod;
begin
if(p=NIL) then
begin
WriteLn('Lista vida!');
exit

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
typedef struct nod
{
int gr;int cf;
struct nod* urm;
}
NOD;
NOD * cap1,*cap2,*cap;
int i;
void parcurgere(NOD* p);
NOD* creare(void);
NOD* suma (NOD* cap1,NOD*
cap2) ;
NOD* produs(NOD* cap1,NOD*
cap2);
NOD *creare(void)
{ NOD *cap,*p,*q;
cap=(NOD*)malloc(sizeof(NOD));
printf("\nPriumul coef. si
gr: ");
scanf (" %d %d", &cap->cf,
&cap->gr);
cap->urm=NULL;
p=cap;
do { printf("Continuati?" );
if (getch()=='n') break;
printf("\nUrm. coef. si
gr: ");
q=(NOD*)malloc(sizeof(NOD));
scanf("%d %d", &q->cf, &q>gr);
q->urm=NULL;
p->urm=q; p=q;
}
while(1);

14

end;
q:=p;
while q<>NIL do
begin
Write(q^.cf,'x^', q^.gr,'+');
q:=q^.urm;
end;
WriteLn(#8, ' ');
end;
procedure canonic(var cap:nod);
var p,q,r: nod;
begin
p:=cap;
while p<>NIL do
begin
q:=p^.urm;
r:=p;
while q<>NIL do
begin
if (p^.gr=q^.gr) then
begin
p^.cf:=p^.cf+q^.cf;
r^.urm:=q^.urm; r:=q;
dispose(q);
end
else r:=q;
q:=q^.urm
end;
p:=p^.urm
end
end;
function suma(var
cap1,cap2:nod):nod;
var p,q,cap,r:nod;
begin
if(cap1<>NIL) then new(cap);
cap^.cf:=cap1^.cf;
cap^.gr:=cap1^.gr;
cap^.urm:=NIL; r:=cap;
p:=cap1^.urm;
while p<>NIL do
begin
new(q);
q^.cf:=p^.cf
;q^.gr:=p^.gr;q^.urm:=NIL;
r^.urm:=q;r:=q;
p:=p^.urm
end;
p:=cap2;
while p<>NIL do
begin
new(q);
q^.cf:=p^.cf;
q^.gr:=p^.gr;q^.urm:=NIL;
if r<>NIL then r^.urm:=q;
r:=q;

return(cap);
}
void parcurgere(NOD *p)
{ NOD *q;
if(!p){ printf("\nLista
vida!"); return;}
for (q=p;q;q=q->urm)
printf ("\n%2d x^%d+", q>cf, q->gr);
printf ("\b " ) ;
}
void canonic(NOD *cap)
{ NOD *p,*q,*r;
for(p=cap;p;p=p->urm)
for(q=p->urm;q;r=q,q=q->urm)
if (p->gr==q->gr)
{ p->cf+=q->cf;
r->urm=q->urm;free(q);
}
}
NOD* suma (NOD* cap1, NOD* cap2)
{ NOD *p,*q,*cap,*r;
if(cap1)
cap=(NOD*)malloc(sizeof(NOD));
cap->cf=cap1->cf; cap>gr=cap1->gr;
cap->urm=NULL; r=cap;
for (p=cap1->urm;p;p=p->urm)
{ q=(NOD*)malloc(sizeof(NOD));
q->cf=p->cf ;q->gr=p->gr;q>urm=NULL;
r->urm=q;r=q;
}
for (p=cap2;p;p=p->urm)
{ q=(NOD*)malloc
(sizeof(NOD));
q->cf=p->cf; q->gr=p->gr;
q->urm=NULL;
if(r) r->urm=q;r=q;
}
canonic(cap);
return cap;
}
NOD* produs (NOD* cap1, NOD*
cap2)
{ NOD *p,*q,*ult,*r,*cap; int
este_cap=0;
este_cap=0;
for (p=cap1;p;p=p->urm)
for (q=cap2;q;q=q->urm)
{if (!este_cap)
{ este_cap=1;
cap=(NOD*)
malloc(sizeof(NOD));
cap->cf=p->cf*q->cf;

15

p:=p^.urm
end;
canonic(cap);
suma:=cap;
end;
function produs (var
cap1,cap2:nod):nod;
var p,q,ult,r,cap:nod;
este_cap:Boolean;
begin
este_cap:=False;
p:=cap1;
while p<>NIL do
begin
q:=cap2;
while q<>NIL do
begin
if (NOT este_cap) then
begin
este_cap:=True;
new(cap);
cap^.cf:=p^.cf*q^.cf;
cap^.gr:=p^.gr+q^.gr;
cap^.urm:=NIL;ult:=cap;
end
else begin
new(r);
r^.cf:=p^.cf*q^.cf;
r^.gr:=p^.gr+q^.gr;
r^.urm:=NIL;
ult^.urm:=r;ult:=r;
end;
q:=q^.urm
end;
p:=p^.urm
end;
canonic(cap);
produs:=cap
end;
Begin
cap1:=creare;canonic(cap1);
WriteLn('Polinomul 1:');
parcurgere(cap1);
cap2:=creare; canonic(cap2);
WriteLn('Polinomul 2:');
parcurgere(cap2);
cap:=suma(cap1,cap2);
WriteLn('Polinomul suma:');
canonic(cap); parcurgere(cap);
cap:=produs(cap1,cap2);
WriteLn('Poiinomul produs:');
canonic(cap);parcurgere(cap);
End.

cap->gr=p->gr+q->gr;
cap->urm=NULL;ult=cap;
}
else {
r=(NOD*)malloc(sizeof(NOD));
r->cf=p->cf*q->cf;
r->gr=p->gr+q->gr;
r->urm=NULL;
ult->urm=r;ult=r;
}
}
canonic(cap);
return cap;
}
void main()
{ clrscr();
cap1=creare();canonic(cap1);
printf("\nPolinomul 1:" );
parcurgere(cap1);
cap2=creare(); canonic(cap2);
printf("\nPolinomul 2:");
parcurgere(cap2);
cap=suma(cap1,cap2);
printf("\nPolinomul suma:");
canonic(cap); parcurgere(cap);
cap=produs(cap1,cap2);
printf("\nPoiinomul produs:");
canonic(cap);parcurgere(cap);
}

16

5. S se creeze o list dublu nlnuit cu nodurile memornd numere intregi, s


se parcurg att n sens direct ct i-n sens invers, dupa care s se tearg lista. Pentru
fiecare operaie se va scrie cte un subprogram.
Varianta Pascal

Varianta C/C++

Type nod=^adr;
adr=record
inf:Integer;
ant, urm:nod;
end;
var nr:Integer;
cap1, cap2: nod;
procedure creare(nr:Integer;
var cap1, cap2:nod);
var i:Integer;
p:nod;
begin
new(cap1);
Write('Informatia capului: ');
ReadLn(cap1^.inf);
cap1^.urm:=NIL;
cap1^.ant:=NIL;
cap2:=cap1;
for i:=2 to nr do
begin
new(p);
Write('Informatia nr.',i,' :');
ReadLn(p^.inf);
p^.ant:=cap2;cap2^.urm:=p;
p^.urm:=NIL;cap2:=p
end
end;
procedure parc(p:nod;tp:Integer);
begin
if p<>NIL then
if tp=1 then
begin
Write(p^.inf, ' ');
parc(p^.urm, tp)
end
else
begin
Write(p^.inf, ' ') ;
parc(p^.ant, tp)
end
end;
procedure sterg(p:nod);
begin
if p<> NIL then
begin
sterg(p^.urm);
dispose(p)
end
end;

17

#include <stdio.h>
#include <stdlib.h> ,
struct nod {int inf;
struct nod *urm,*ant;
};
void creare(int nf,struct
nod**,struct nod**);
void parc(struct nod*,int tp);
void sterg(struct nod*);
void main()
{int nr;
struct nod * cap1,*cap2;
printf("Numarul de elemente: ");
scanf("%d",&nr);
creare (nr, &cap1, &cap2);
puts("\nParcurgere directa");
parc(cap1,1);
puts("\nParcurgere inversa");
parc(cap2,2);
sterg(cap1);
}
void creare(int nr,struct nod
**cap1,
struct nod **cap2)
{int inf, i;
struct nod *p;
*cap1=(struct nod*)
malloc(sizeof(struct nod));
printf ("Informatia capului: ");
scanf (" %d", &inf);
(*cap1)->inf=inf;
(*cap1)->urm=(*cap1)->ant=NULL;
*cap2=*cap1;
for(i=2;i<=nr;i++)
{p=(struct nod*)
malloc(sizeof(struct nod));
printf("Informatia nr.%d: ",i);
scanf(" %d", &inf);
p->inf=inf;
p->ant=*cap2;
(*cap2)->urm=p;
p->urm=NULL;*cap2=p;
}
}
void parc(struct nod *p,int tp)
{if(p)
if(tp==1)
{printf (" %d ", p->inf);
parc(p->urm, tp);
}

Begin
Write('Numarul de elemente: ');
ReadLn(nr);
creare (nr, cap1, cap2);
WriteLn('Parcurgere directa');
parc(cap1,1); WriteLn;
WriteLn('Parcurgere inversa');
parc(cap2,2);
sterg(cap1)
End.

else {printf ("%d ",p->inf);


parc(p->ant, tp);
}
}
void sterg(struct nod *p)
{if (p)
{sterg(p->urm); free(p);}
}

6. S se foloseasc o stiv alocat dinamic pentru a face conversia unui numr n


din baza 10 ntr-o baz b mai mic dect 16.
Rezolvare. Se memoreaz ntr-un vector resturile modulo 16 ale unui numr natural
oarecare (adic toate cifrele posibile). Se vor depune n zona de informaie util a
fiecrui nod al stivei acel caracter care se gsete n poziia n modulo b. Apoi,
traversnd stiva i afind resturile, obinem numrul n baza b.
Varianta Pascal
Varianta C/C++
uses Crt;
type nr = ^adr;
adr=record
inf: Char;
urm:nr
end;
const a: array[0..15] of Char=
('O','1','2','3','4','5',
'6','7','8','9','A','B',
'C','D','E','F');
var varf:nr; {varf stiva}
{stiva resturi modulo baza}
function cifre:nr;
var n,b:Integer;
varf,p:nr;
begin
Write('Nr. de convertit: ');
ReadLn(n);
Write('Baza noua: ');ReadLn(b);
new(varf);
varf^.inf:=a[n mod b];
varf^.urm:=NIL;
n:=n div b;
while (n<>0) do
begin
new(p);
p^.inf:=a[n mod b];
p^.urm:=varf;varf:=p;
n:=n div b
end;
cifre:=varf
end;
procedure scrie_cifre(p:nr);
var q:nr;
begin
q:=p;
while q<>NIL do

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<iostream.h>
struct nod{int cod;
struct nod *urm;};
typedef nod NOD;
NOD *prim,*ultim,*p;
void intrare()
{int codul;
printf("Intra clientul= ");
scanf("%d",&codul);
if(prim==NULL)
{prim=(NOD*)malloc(sizeof(NOD));
prim->cod=codul;
prim->urm=NULL;
ultim=prim;}
else
{p=(NOD*)malloc(sizeof(NOD));
p->cod=codul;
p->urm=NULL;
ultim->urm=p;
ultim=p;}
}
void iesire()
{if(prim==NULL)
{printf("Nu mai sunt clienti\n");
getch();}
else
{printf("Iese clientul %d \n",
prim->cod);
p=prim;
prim=prim->urm;
free(p);
}getch();
}
void afisare()

18

begin
Write(q^.inf);
q:=q^.urm
end
end;
Begin
clrscr;
varf:=cifre;
scrie_cifre(varf);
ReadLn
End.

{if (prim==NULL)
printf("Nu e nimeni la coada\n");
else
{printf("Clientii de la coada:
\n");
p=prim;
do
{printf("%d \n",p->cod);
p=p->urm;}
while (p!=NULL) ;
} getch();}
void main(void)
{char comanda;
prim=NULL;
do {clrscr ();
printf("Comanda: ");
scanf("%c",&comanda);
switch (comanda)
{case 'i':intrare();break;
case 'e' : iesire();break;
case 'l':afisare();break;}}
while(comanda!='s');
}

7. Se consider un ghieu la care se ateapt la coad pentru a fi servii mai


muli clieni. S se scrie un program care prelucreaz comenzi de forma: I (intrarea la
coad), E (ieirea de la coad n urma servirii de la ghieu), L (listarea persoanelor ce
se afl la coad) i S (sfritul programului). Clienii sunt codificai numeric.
Rezolvare. Vom folosi o list de tip coad.
Varianta Pascal
Varianta C/C++
uses Crt;
type nod=^adr;
adr=record
cod:Integer;
urm:nod;
end;
var prim,ultim,p:nod;
comanda:Char;
procedure intrare;
var codul:Integer;
begin
Write('Intra clientul=');
ReadLn(codul);
if prim=NIL then
begin
new(prim);
prim^.cod:=codul;
prim^.urm:=NIL;
ultim:=prim end
else
begin
new(p);
p^.cod:=codul;
p^.urm:=NIL;
ultim^.urm:=p;
ultim:=p

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<iostream.h>
struct nod{int cod_loc;
struct nod *urm;};
typedef nod NOD;
NOD *prim,*ultim,*p;
void intrare()
{int codul;
printf("Codul loc care intra=");
scanf("%d",&codul);
if(prim==NULL)
//coada vida, se adauga primul el.
{prim=(NOD*)malloc(sizeof(NOD));
prim->cod_loc=codul;
prim->urm=NULL;
ultim=prim;}
else
{p=(NOD*)malloc(sizeof(NOD));
p->cod_loc=codul;
p->urm=NULL;
ultim->urm=p;
ultim=p;}
}
void iesire()//sterg primul el.

19

end;
end;
procedure iesire;
begin
if prim=NIL then
begin
WriteLn('Nu mai sunt clienti');
ReadLn end
else
begin
Write('Iese clientul ',
prim^.cod);
p:=prim;
prim:=prim^.urm;
dispose(p);
ReadLn
end;
ReadLn
end;
procedure afisare;
begin
if prim=NIL then
WriteLn('Nu e nimeni la coada')
else
begin
Write('Clientii de la coada: ');
p:=prim;
repeat
Write(p^.cod, ' ');
p:=p^.urm
until p=NIL
end;
ReadLn; ReadLn
end;
Begin
prim:=NIL;
repeat
clrscr;
Write('Comanda: ');
Read(comanda);
case comanda of
'i':intrare;
'e':iesire;
'l':afisare
end;
until comanda='s'
End.

{if(prim==NULL)
{printf("Depou gol\n");
getch();}
else
{printf("Iese locom. %d \n",
prim->cod_loc);
p=prim;//salvez adr. primului
prim=prim->urm;
free(p);
}getch();
}
void afisare()
{if (prim==NULL)
printf("Depoul este gol\n");
else
{printf("Locom. din depou: \n");
p=prim;
do
{printf("%d \n",p->cod_loc);
p=p->urm;}
while (p!=NULL) ;
} getch();}
void main(void)
{char comanda;
prim=NULL;
do {clrscr ();
printf("Comanda: ");
scanf("%c",&comanda);
switch (comanda)
{case 'i':intrare();break;
case 'e' : iesire();break;
case 'l':afisare();break;}}
while(comanda!='s');
}

4. 3. 6 Probleme propuse
1. S se scrie un subprogram care s realizeze inversarea legturilor ntr-o list
liniar simplu nlnuit.
Indicaii. Pentru a avea sens inversarea, lista trebuie s aib cel puin dou noduri. Vom
utiliza doi pointeri p i q care rein adresa a cte dou noduri succesive i vom parcurge
lista realiznd inversarea legturilor.
20

2. S se realizeze urmtoarele funcii pentru: crearea unei liste cu cifrele unui


numr pe care-l primete ca paramtru, adunarea, scderea, nmulirea i mprirea
numerelor memorate astfel n dou liste.
3. S se scrie un subprogram care citete pe rnd cifrele unui numr ntreg foarte
mare. S se utilizeze aceast funcie ntr-un program care citete numere foarte mari i
realizeaz operaiile de baz cu ele (adunarea, scderea, nmulirea, mprirea).
4. Fiind dat o list simplu nlnuit avnd ca informaii numere reale, s se
afieze cte numere negative, cte numere egale cu 0 i cte numere pozitive conine
lista.
5. S se creeze o list prin inserri succesive, astfel nct la fiecare pas lista s fie
ordonat cresctor.
Indicaie. Pntru a crea lista ordonat cresctor va trebui ca nainte de a insera o nou valoare n
list s cutm poziia sa corect, apoi s inserm valoarea pe poziia corect, astfel nct la
fiecare moment lista s fie sortat. Astfel, dac lista este vid sau valoarea care trebuie inserat
este mai mic dect informaia primului nod din list, atunci inserarea se face la nceputul listei.
Altfel, vom lua un pointer p pe care-l deplasm de la nceputul listei spre vrful su pn cnd
nodul care urmeaz dup cel indicat de p are o informaie mai mare dect valoarea de inserat
sau p este ultimul nod din list, inserarea noii valori fcndu-se dup nodul indicat de p.

6. Un polinom cu coeficieni reali P(x) =anxn+an-1xn-1+...+a1x+a0 poate fi


memorat ntr-o list simplu nlnuit n care fiecare nod va reine coeficientul i gradul
unui monom de forma akxk al polinomului. Definii i creai structurile de date
necesare, apoi scriei cte un subprogram pentru:
a) calculul valorii unui polinom dat P(x), pentru o valoare dat a argumentului x.;
b) afiarea polinomului ce reprezint suma a dou polinoame date, P(x)+Q(x).
Indicaii: Pentru a putea aduna ntr-o manier foarte simpl dou polinoame este
recomandabil ca lista aferent polinomului P(x) s conin n noduri, ce vor memora
coeficienii i gradele monoamelor. Fie coef i grad cele dou cmpuri ale fiecrui nod.
Dac un monom lipsete i va reveni n list un nod cu valoarea 0 n cmpul coef.
1) Fie v variabila n care vom calcula valoarea polinomului. Parcurgem lista ntr-un
ciclu cu ajutorul unui pointer q i la fiecare pas adugm la v valoarea unui monom
akxk, care se poate exprima sub forma coef*putere(x, grad). Funcia putere(b,m)
returneaz bm.
2) Folosind reprezentarea indicat, parcurgem "n paralel" cele dou liste cu ajutorul
unor pointeri q i r. La fiecare pas al parcurgerii cei doi pointeri vor adresa noduri
corespunztoare unor monoame de acelai grad n cele dou polinoame i nsumm
coeficienii monoamelor corespunztoare aceluiai grad.
7. Fie dou polinoame rare (n care majoritatea coeficienilor sunt nuli). De
exemplu, P(x)=5x16+3x2-2 este un polinom rar. Astfel de polinoame pot fi memorate ca
o list simplu nlnuit n care sunt reinute monoamele n ordinea cresctoare a
gradelor, pentru fiecare monom reinndu-se n partea de informaii coeficientul i
gradul su. Spunem n acest caz c polinoamele sunt memorate n forma condensat
(adic nu sunt memorate i monoamele cu coeficieni nuli, ceea ce ar duce la un
consum inutil de memorie). S se scrie un program care s realizeze suma celor dou
polinoame memorate n forma condensat.
8. Scriei un subprogram care, primind ca parametri dou liste liniare simplu
nlnuite de numere ntregi, afieaz reuniunea celor do liste, fr a folosi tablouri sau
21

alte structuri de date alocate static. Reuniunea a dou liste este alctuit din cheile lor
comune i necomune, luate o singur dat.
9. Scriei un subprogram care, primind ca parametri dou liste liniare simplu
nlnuite de numere ntregi, afieaz intersecia celor do liste, fr a folosi tablouri
sau alte structuri de date alocate static. Intersecia a dou liste este alctuit din cheile
lor comune, luate o singur dat.
10. Scriei un subprogram care, primind ca parametri dou liste liniare simplu
nlnuite de numere ntregi, afieaz diferena celor do liste, fr a folosi tablouri sau
alte structuri de date alocate static. Diferena a dou liste este alctuit din cheile primei
liste care nu se afl i-n a doua list.
11. Scriei un program care s creeze o list liniar dublu nlnuit n care nodurile
conin ca informaie numere ntregi i s realizeze principalele operaii cu aceast list
(adugarea unui nou nod, tergerea unui nod, cutarea unui nod care conine ca
informaie o anumit valoare ntreag, etc.).
12. Scriei un program care s creeze o list liniar simplu nlnuit circular n
care nodurile conin ca informaie numere ntregi i s realizeze principalele operaii cu
aceast list (adugarea unui nou nod, tergerea unui nod, cutarea unui nod care
conine ca informaie o anumit valoare ntreag, etc.).
13. Scriei un program care s creeze o list liniar dublu nlnuit circular n care
nodurile conin ca informaie numere ntregi i s realizeze principalele operaii cu
aceast list (adugarea unui nou nod, tergerea unui nod, cutarea unui nod care
conine ca informaie o anumit valoare ntreag, etc.).
14. Scriei un subprogram care, primind ca parametru o list de numere naturale,
afieaz ptratele perfecte aflate n noduri cu numr de ordin impar (primul, al treilea,
al cincilea, etc.) n lista dat.
Exemplu: pentru lista L=(49,45,172,36,169), se vor afia numerele 49 i 169.
15. Construii o list de numere naturale citite din fiierul "nr.txt" (n care fiecare
nod va conine drept informaie un numr din fiier), apoi scriei un subprogram care
afieaz cheile listei a cror sum a cifrelor este egal cu o valoare dat s. Numerele
sunt scrise n fiier unul sub altul, fiecare pe cte un rnd, i nu se cunoate cte astfel
de numere conine fiierul.
Exemplu: Pentru fiierul ce conine numerele 5, 123, 14, 85, 1121, 16 i s=5, se vor
afia numerele 5,14 i 1121.
16. Se citesc de la tastatur numere ntregi, pn la introducerea valorii 0 (care nu
va face parte din irul citit). S se creeze o list liniar simplu nlnuit care s conin
drept chei numerele prime dintre cele citite. Nu se vor folosi vectori sau alte structuri
de date alocate static.
17. Se citete de la tastatur un cuvnt de lungime maxim 80 de caractere.
Memornd caracterele cuvntului ntr-o list simplu nlnuit (n care fiecare nod va
conine n cmpul de informaie un caracter), s se verifice dac respectivul cuvnt este
palindrom. Reamintim: un cuvnt este palindrom dac, citind caracterele sale n ordine
invesr, de la dreapta la stnga, obinem acelai cuvnt. De exemplu, cuvntul "cojoc"
este palindrom.
18. S se construiasc o list liniar simplu nlnuit cu primele n numere naturale
impare. Numerele se vor memora n ordine cresctoare n cmpurile de informaie ale
nodurilor, cte unul n fiecare nod.
22

Exemplu: pentru n=8, lista va fi (l->3->5->7->9->11->13->15).


19. Scriei un subprogram care verific dac dou liste liniare simplu nlnuite sunt
identice sau nu, returnnd rezultatul logic al testrii. Subprogramul va primi drept
parametri adresele de nceput ale celor dou liste. Spunem c dou liste se consider
identice, dac au acelai numr de noduri i nodurile cu acelai numr de ordine n cele
dou liste conin aceeai informaie.
20. Realizai un subprogram care concateneaz dou liste liniare simplu nlnuite
de numere ntregi (prin concatenarea a dou liste se nelege "lipirea" celei de-a doua la
sfritul primeia). Subprogramul va primi ca parametri pointerii ctre primul nod al
celor dou liste ce trebuie concatenate, i va returna un pointer ctre nceputul listei
rezultate prin concatenare.
21. Se citete de la tastatur un numr ntreg cu maxim opt cifre. S se afieze
oglinditul numrului folosind o list simplu nlnuit n nodurile creia se memoreaz
cifrele numrului. Prin oglinditul unui numr ntreg nelegem numrul obinut prin
citirea cifrelor numrului dat n ordine invers de la dreapta la stnga (palindrom
numeric).
Exemplu: Dac se citete numrul 742881, se va construi lista L=(l->8->8->2->4->7).
22. Scriei o funcie care, primind ca parametri un ntreg k i un pointer p ctre
primul nod al unei liste liniare simplu nlnuite de numere ntregi, terge primele k
noduri din list, i returneaz lista rmas. Algoritmul se va baza pe tergerea repetat a
primului nod. Nu se vor folosi alte subprograme i nici structuri de date alocate static.
Exemplu: Pentru lista L=(2->5->8->11->4->11->11->7) i k=3, dup tergere va
rmne lista L2= (11->4->11->11->7).
23. Scriei un program care, pentru o list dat de n numere ntregi, determin cea
mai mare diferen n modul dintre dou chei consecutive ale listei. Prima dintre cele
dou chei care alctuiesc diferena localizat va fi mutat la nceputul listei, iar a doua
la sfritul listei.
Exemplu: Pentru lista L=(-3->-1->8>2>12>9>14), va rezulta lista L2= (2->-3
-1->8->9->14->12).
24. Scriei un subprogram care, primind ca parametru un pointer p ctre nceputul
unei liste liniare simplu nlnuite de numere ntregi, creaz alte dou liste astfel: n
prima list se vor introduce numerele pozitive ale listei date, iar n cea de-a doua se vor
memora numerele negative din lista dat.
25. Se citete un text caracter cu caracter din fiierul "fraza.txt". Textul este scris
pe un singur rnd n fiier, i poate conine orice caractere. S se construiasc o list
liniar dublu nlnuit care s conin caracterele distincte din text mpreun cu
frecvenele lor de apariie n cadrul textului, apoi s se afieze coninutul listei pe ecran
(pe fiecare rnd se va scrie cte un caracter distinct i frecvena sa de apariie, separate
printr-un spaiu.
26. Se d un ir de numere ntregi citite de la tastatur. S se introduc aceste
numere n ordine cresctoare ntr-o list liniar simplu nlnuit. Lista se va crea de la
nceput ordonat, i nu se va aplica nici un algoritm de sortare.
Indicaii: Introducem separat n list primul numr. Pentru fiecare din restul numerelor
trebuie s cutm poziia pe care ar ocupa-o noul nod n list, astfel nct numerele din
noduri s fie tot timpul n ordine cresctoare:
23

- dac numrul pe care-l introducem este mai mic dect cel din primul nod, atunci noul
nod se va aduga la nceputul listei, modificndu-se captul acesteia;
- n caz contrar, parcurgem lista pn la identificarea poziiei pe care ar ocupa-o noul
nod pentru ca lista s rmn sortat cresctor dup care inserm nodul cu numrul citit
i corectm legturile;
- mai exist i posibilitatea ca numrul pe care-l adugm n list s fie mai mare dect
numrul din ultimul nod, situaie n care adugm noul nod la sfritul listei.
27. Se citesc de la tastatur n numere naturale, care se memoreaz ntr-o list
(fiecare nod va conine drept informaie unul din cele n numere). Scriei un program
care, pentru fiecare dintre numerele date, construiete lista divizorilor si mai mari ca 1,
apoi, folosind cele n liste de divizori, determin i afieaz divizorii comuni ai celor n
numere.
Exemplu: pentru n=4 i lista iniial L=(15->60->210->90), se vor construi listele Ll=
(3-->5), L2= (3->4->5), L3= (2->3->5->7) i L4= (3->5->6), iar divizorii comuni
memorai n cele patru liste de divizori sunt 3 i 5.
28. Fiierul "fraza.txt" conine pe un singur rnd o fraz, alctuit din cuvinte, ntre
care apar ca separatori spaiul i virgula, fraza ncheindu-se cu caracterul "punct". S se
creeze o list liniar simplu nlnuita cu cuvintele frazei (cmpul de informaie al
fiecrui nod va fi de tip ir de caractere i va memora un cuvnt al frazei), apoi,
parcurgnd lista, s se afieze cuvntul (cuvintele) de lungime maxim. Nu se vor
folosi vectori sau alte structuri alocate static.
Exemplu: Dac n fiier se gsete fraza "mie mi plac caii, sunt mort dup ei", atunci
lista va fi: ('mie"->"mi"->"plac"->"caii"->"sunt"->"mort"->"dup"->"ei"), iar cuvintele
de lungime maxim ce trebuie afiate sunt: "plac", "caii", "sunt", "mort" i "dup".
29. Se citete de la tastatur un ir de caractere alctuit din cel mult 100 de litere ale
alfabetului latin. irul se citete caracter cu caracter, citirea ncheindu-se prin tastarea
caracterului '#', care nu face parte din el. Folosind o list liniar simplu nlnuit, n
care flecare nod va memora n cmpul su de informaie cte un caracter al irului, s
se afieze cea mai lung secven de litere din ir care, luat individual, constituie un
palindrom. Nu se vor utiliza tipul ir de caractere, vectori, sau alte structuri de date
alocate static.
Exemplu: Pentru irul "vbanacmamxmamt", secvenele ce constituie palindroame sunt:
"ana" i "mamxmam", iar cea mai lung dintre acestea este "mamxmam".
Indicaii. Problema se bazeaz pe un algoritm de determinare a unui subir de lungime
maxim cu o anumit proprietate dintr-un ir dat. Pentru testarea proprietii de
palindrom a unui subir putei folosi algoritmul clasic de extragere a cifrelor.
30. Pentru evidena rezultatelor la Bacalaureat obinute de ctre elevii unei coli se
folosete fiierul "bac.txt" care conine:
- pe primul rnd numrul n de elevi;
- pe fiecare din urmtoarele n rnduri media i apoi numele unui elev, separate printrun spaiu.
Folosind o list liniar simplu nlnuit, se cere:
a) s se afieze numele elevului (elevilor) care au obinut media cea mai mare;
b) s se determine media general a colii.
Indicaii: Din fiier se citete mai nti valoarea lui n. apoi ntr-un ciclu, la fiecare pas:
se citesc numele i media unui elev de pe un rnd al fiierului i se creeaz un nod al
24

listei simplu nlnuite, avnd drept informaii numele i media citite. Pentru
determinarea celei mai mari medii, aplicm algoritmul clasic de maxim n list, dar
pentru c pot fi mai muli elevi cu media maxim determinat parcurgem nc o dat
lista i afim acei elevi a cror medie este egal cu maximul. n sfrit, media general
a colii este media aritmetic a mediilor elevilor din list (suma mediilor mprit la
numrul acestora).
31. Un astrolog dorete s efectueze un studiu statistic privitor la influenele astrelor
asupra persoanelor care locuiesc n oraul su. Pentru aceasta are nevoie de un eantion
de n persoane. El va ntocmi o list care s cuprind, pentru fiecare dintre aceste
persoane, numele, ziua i luna naterii, simulat cu ajutorul unei liste liniare alocat
dinamic. Pornind de la aceast list, astrologul nostru trebuie s poat stabili zodiile n
care s-au nscut persoanele, i apoi s determine cte persoane sunt nscute n fiecare
zodie. In acest scop, el va construi cte o list alocat dinamic pentru fiecare zodie n
parte, coninnd persoanele nscute n acea zodie. Realizai un program care s rezolve
problema astrologului nostru. Pentru ca astrologul s fie pe deplin mulumit, v
propunem s-i oferii un program care s afieze i listele tuturor persoanelor nscute n
fiecare zodie, pe lng numrul acestora. Datele de intrare se citesc din fiierul "pers.
txt", care conine:
- pe primul rnd numrul n al persoanelor din eantion;
- pe fiecare din urmtoarele n rnduri, ziua naterii, luna naterii (n cifre) i numele
unei persoane, n aceast ordine, separate prin spaii.
32. La ora de educaie fizic, profesorul a cerut elevilor unei clase s se alinieze n
ce ordine doresc ei. Fiind un mare iubitor al informaticii, el a observat imediat c n
irul de elevi exist situaii n care un elev de nlime maxim este aezat lng unul de
nlime minim. Scriei un program care afieaz perechile de elevi alturai n ir care
ndeplinesc condiia de mai sus, precum i numrul acestor perechi, apoi rearanjeaz
copiii n ir, astfel nct s se obin un numr maxim de perechi cu proprietatea
respectiv. irul de elevi va fi simulat cu ajutorul unei liste n care fiecare nod va
memora numele i nlimea unui elev, i nu se vor folosi nici un fel de structuri de date
alocate static (tablouri, nregistrri, etc). Numrul de elevi, precum i numele i
nlimile elevilor, se citesc de la tastatur.
Rspunsuri la testele gril:
1. c) 2. c) 3. c) 4. c) 5. c) 6. c) 7. c) 8. d) 9. d)
Bibliografie
1. Emanuela Cerchez, Marinel erban - Programarea n limbajul C/C++ pentru
liceu, Editura Polirom, 2006 (trei volume);
2. Dumitru Fanache Informatic, manual pentru clasa a XI-a, varianta C++,
Editura Gimnasium, 2002;
3. George Daniel Mateescu, Pavel Florin Moraru Informatica pentru liceu i
bacalaureat, materia din clasa a XI-a, Editura Donaris, Sibiu, 2006;
4. Daniela Oprescu, Liana Bejan Ienulescu, Viorica Ptracu Informatic,
manual pentru clasa a XI-a, Editura Niculescu, 2002;
5. Dorian Stoilescu Culegere de C/C++, Editura Radial, Galai, 1998;
6. Dorian Stoilescu - Manual de C/C++ pentru licee, Editura Radial, Galai, 1998;
7. Colectiv autori - Bac 2009: subiecte posibile, Editura Cygnus, 2009;
8. *** - Subiecte bacalaureat 2006, 2007, 2008, 2009.
25

S-ar putea să vă placă și