Sunteți pe pagina 1din 34

Curs SDA (PC2)

Liste (continuare)
Iulian Nstac
2
Prin definiie, o mulime dinamic de
structuri recursive de acelai tip,
pentru care sunt definite una sau mai
multe relaii de ordine cu ajutorul
unor pointeri din compunerea
structurilor respective, se numete
list nlnuit.
Recapitulare
3
Elementele unei liste se numesc noduri.
Dac ntre nodurile unei liste exist o singur
relaie de ordine, atunci lista se numete
simplu nlnuit. n mod analog, lista este
dublu nlnuit daca ntre nodurile ei sunt
definite dou relaii de ordine.
O list este n-nlnuit dac ntre nodurile ei
sunt definite n relaii de ordine.
Recapitulare
4
Recapitulare
Operaii ce in de o list nlnuit:
a) crearea listei nlnuite;
b) accesul la un nod oarecare al listei;
c) inserarea unui nod ntr-o list
nlnuit;
d) tergerea unui nod dintr-o list
nlnuit;
e) tergerea unei liste nlnuite.
5
2. Lista simplu nlnuit
(Recapitulare)
ntre nodurile listei simplu nlnuite avem o singur
relaie de ordonare. Exist un singur nod care nu mai are
succesor i un singur nod care nu mai are predecesor.
Aceste noduri formeaz capetele listei.
Vom utiliza doi pointeri spre cele dou capete pe care i
notm cu:
prim - pointerul spre nodul care nu are predecesor
ultim - pointerul spre nodul care nu are succesor.
6
Pointerul urm definete
relaia de succesor
pentru nodurile listei.
Pentru fiecare nod, el
are ca valoare adresa
nodului urmtor din list.
Excepie face nodul spre
care pointeaz variabila
ultim (pentru care urm
ia valoarea zero).
7
2.1. Crearea unei liste simplu nlnuite
(Recapitulare)
La crearea unei liste simplu nlnuite se
realizeaz urmtoarele operaii:
1) Se iniializeaz pointerii prim i ultim cu
valoarea zero, deoarece la nceput lista este vid.
2) Se rezerv zona de memorie n memoria heap
pentru nodul curent.
3) Se ncarc nodul curent p cu datele curente,
dac exist i apoi se trece la pasul 4). Altfel lista
este creat i se revine din funcie.
8
4) Se atribuie adresa din memoria heap a
nodului curent pointerului:
ultim -> urm = p, dac lista nu este vid;
prim = ultim = p, dac lista este vid.
5) Se atribuie lui ultim adresa nodului curent.
6) ultim -> urm = 0
7) Procesul se reia de la punctul 2) de mai sus
pentru a aduga un nod nou la list.
9
Observaii:
Se consider tipul utilizator:
typedef struct nod
{ declaraii;
struct nod *urm;
} NOD;
La punctul 3) se ncarc datele printr-o funcie
pe care o vom denumi incnod care ncarc
datele curente ntr-un nod de tip NOD.
10
Funcia incnod returneaz:
1 la ncrcarea corect a datelor n nodul curent
-1 cnd nu mai sunt de ncrcat date
0 la apariia unei erori (ex: memorie insuficient)
Funcia incnod are prototipul:
int incnod(NOD *p)
O alt funcie necesar este cea care
elibereaz zona de memorie rezervat
unui nod:
void elibnod(NOD *p)
11
2.2. Accesul la un nod ntr-o list simplu
nlnuit
Putem avea acces la nodurile unei liste simplu nlnuite
ncepnd cu nodul spre care pointeaz variabila global
prim i trecnd apoi pe rnd de la un nod la altul,
folosind pointerul urm.
O alt metod, mai bun, este aceea de a avea o dat,
component a nodurilor, care s aib valori diferite,
pentru noduri diferite. n acest caz se poate defini
accesul la nodul din list pentru care data respectiv are
o valoare fixat. O astfel de dat se numete cheie i
este de un tip oarecare (uzual se folosete char i int).
Funcia returneaz pointerul spre nodul cutat sau zero
n cazul n care lista nu conine un nod a crui cheie s
aib valoarea indicat de parametrul ei.
12
O cheie se insereaz n tipul utilizator:
typedef struct nod
{ declaraii;
tip cheie;
struct nod *urm;
} NOD;
Cheia poate fi int, long, double, char, etc.
13
Exemplu:
Se consider tipul utilizator:
typedef struct nod
{ char *cuvant; /*aceasta este cheia */
int frecventa;
struct nod *urm;
} NOD;
Considernd o list simplu nlnuit ale crei noduri au
tipul NOD se scrie o funcie care caut, n lista
respectiv, nodul pentru care pointerul cuvant are ca
valoare adresa unui cuvnt dat.
Pointerul cuvant joac rol de cheie i se cere s se
gseasc nodul a crui cheie pointeaz spre un cuvnt
dat.
14
NOD *cncs(char *c) /*caut nod comun n ir*/
/* - cauta un nod al listei pentru care cuvantul spre care
pointeaza cuvant este identic cu cel spre care pointeaza c;
- returneaza pointerul spre nodul determinat sau zero
daca nu exista un astfel de nod. */
{
extern NOD *prim;
NOD *p;
for(p = prim; p; p = p->urm) /* cautarea incepe cu nodul spre
care pointeaza variabila prim
si se baleiaza toata lista */
if(strcmp(p->cuvant,c) == 0)
return p; /* s-a gasit un nod cu cheia c */
return 0; /* nu exista nici un nod in lista cu cheia c */
}
15
2.3. Inserarea unui nod ntr-o list simplu
nlnuit
ntr-o list simplu nlnuit se pot face
inserri de noduri n diferite poziii:
a) inserare naintea primului nod;
b) inserarea naintea unui nod precizat
printr-o cheie;
c) inserarea dup un nod precizat printr-o
cheie;
d) inserarea dup ultimul nod al listei.
16
Exemplu:
inserarea dup ultimul nod al listei
NOD *adauga()
/* - adauga un nod la o lista simplu nlnuita;
- returneaza pointerul spre nodul adaugat sau
zero daca nu s-a realizat adaugarea. */
{
extern NOD *prim, *ultim;
NOD *p;
int n;
/* se rezerva zona de memorie pentru un nod si se incarca
datele din zona respectiva */
n = sizeof(NOD);

17

if(((p = (NOD *)malloc(n)) != 0) && (incnod(p) == 1))


{
if(prim == 0) /* lista este vida */
prim = ultim = p;
else
{
ultim -> urm=p; /* succesorul nodului spre care
pointeaza ultim devine nodul
spre care pointeaza p */
ultim = p; /* acesta devine nodul spre
care pointeaza p */
}
p -> urm=0;
return p;
}

18

if(p == 0) /* nu s-a reusit inserarea nodului in lista */
{
printf("memorie insuficienta\n");
exit(1);
}
elibnod(p);
return 0;
}
19
2.4. tergerea unui nod dintr-o list
simplu nlnuit
Sunt avute n vedere urmtoarele cazuri:
a) tergerea primului nod al listei simplu
nlnuite;
b) tergerea unui nod precizat printr-o cheie;
c) tergerea ultimului nod al listei simplu
nlnuite.
20
Observaii:
Funciile de tergere utilizeaz funcia elibnod.
Aceast funcie elibereaz zona de memorie
alocat nodului care se terge, precum i
eventualele zone de memorie alocate
suplimentar prin intermediul funciei incnod
pentru a pstra diferite componente ale unui nod
(de exemplu componente de tip ir de
caractere).
Codurile funciilor incnod i elibnod depind de
aplicaia concret n care sunt utilizate.
21
tergerea primului nod
void spn()
{
extern NOD *prim, *ultim;
NOD *p;
if (prim == 0) return;
p = prim;
prim = prim -> urm;
elibnod(p);
if (prim == 0) /* lista este vida */
ultim = 0;
}
22
Observaie:
Exist o mare diferen, n complexitate,
dac comparm ntre ele o funcie care
terge primul nod cu o funcie care
terge ultimul nod al listei.
23
2.5. tergerea unei liste simplu nlnuite
void sterge_l()
{
extern NOD *prim, *ultim;
NOD *p;
while(prim)
{
p = prim;
prim = prim -> urm;
elibnod (p);
}
ultim = 0;
}
24
Stiva
O stiv este o list simplu nlnuit
gestionat conform principiului LIFO
(Last In First Out).
Conform acestui principiu, ultimul nod
pus n stiv este primul nod care este scos
din stiv. Stiva, ca i lista obinuit, are
dou capete:
baza stivei
vrful stivei
25
Asupra unei stive se definesc
cteva operaii, dintre care cele mai
importante sunt:
1. pune un element pe stiv (PUSH);
2. scoate un element din stiv (POP);
3. terge (videaz) stiva (CLEAR).
26
Primele dou operaii se realizeaz n
vrful stivei. Astfel, dac se scoate un
element din stiv, atunci acesta este cel
din vrful stivei i n continuare, cel pus
anterior lui pe stiv ajunge n vrful stivei.
Dac un element intr pe stiv, atunci
acesta se pune n vrful stivei i n
continuare el desemneaz vrful stivei.
27
Pentru a implementa o stiv printr-o list
simplu nlnuit va trebui s identificm
baza i vrful stivei cu capetele listei simplu
nlnuite. Exist dou posibiliti:
a. nodul spre care pointeaz variabila prim
este baza stivei, iar nodul spre care
pointeaz variabila ultim este vrful stivei;
b. nodul spre care pointeaz variabila prim este
vrful stivei, iar nodul spre care pointeaz
variabila ultim este baza stivei.
28
Observaii:
n cazul a, funciile PUSH i POP se identific
prin funciile adauga i respectiv sun, definite n
edina anterioar de laborator. Dac funcia
adauga este eficient, n schimb funcia sun nu
este eficient.
n cazul b, funciile PUSH i POP se identific
prin funciile iniprim i respectiv spn, ce vor fi
definite n aceast lucrare de laborator. n acest
caz, ambele funcii sunt eficiente. De aceea, se
recomand implementarea stivei printr-o list
simplu nlnuit conform cazului b indicat mai
sus.
29
Coada
Un alt principiu de gestionare a listelor simplu
nlnuite este principiul FIFO (First In First
Out). Conform acestui principiu, primul element
introdus n list este i primul care este scos din
list.
Despre o list gestionat n acest fel se spune
c formeaz o coad. Cele doua capete ale
listei simplu nlnuite care implementeaz o
coad sunt i capetele cozii.
30
Asupra cozilor (ca i asupra stivelor) se
definesc trei operaii:
a. pune un element n coad;
b. scoate un element din coad;
c. tergerea (vidarea) unei cozi.
31
Pentru a respecta principiul FIFO,
vom pune un element n coad
folosind funcia adauga i vom
scoate un element din coad
folosind funcia spn.
Deci, la un capt al cozii se pun
elementele n coad, iar la celalalt
capt se scot elementele din coad.
32
33
34
Lista circular simplu nlnuit
Lista simplu nlnuit conine:
- un nod care nu are succesor (pointeaz ultim);
- un nod care nu are predecesor (pointeaz prim).
Se tie c ntr-o list obinuit: ultim -> urm = 0;
Dac facem ultim -> urm = prim , atunci rezult o
list circular simplu nlnuit.