Documente Academic
Documente Profesional
Documente Cultură
Există două metode de alocare (construire a nodurilor ) a unei liste liniare: alocarea secvenţială şi
alocarea înlănţuită. Cea mai bună metodă este cea înlănţuită.
Nodurile listei ocupă poziţii succesive în memorie. Acest tip de alocare l-am întâlnit des, de
câte ori am utilizat vectori.
Exemplu: un vector are n componente de tip real. Se cere să se sorteze vectorul crescător.
Algoritmul are ca dată de intrare o listă liniară, cu n noduri de tip real. Ieşirea este tot o listă liniară,
care are aceleaşi noduri, dar în altă ordine.
Avantajul alocării secvenţiale este dat de faptul că programatorul are acces direct la oricare
din nodurile listei, la fel ca la componentele unui vector.
Dezavantajul alocării secvenţiale este dat de faptul că operaţiile de adăugare, eliminare sau
schimbare de poziţie ale unui nod necesită un efort mare de calcul, ca în exemplul următor,
în care se elimină un nod:
Fie lista alocată secvential:
7 3 1 2 8 9 5 8 3 2 6
7 1 2 8 9 5 8 3 2 6
7 1 2 8 9 5 8 3 2 6
Este obligatoriu ca nodurile următoare să fie deplasate catre stânga. Nu le mai studiem.
2. Liste alocate înlănţuit
Există două feluri de alocare înlănţuită: alocare simplu înlănţuită şi alocare dublu
înlănţuită. 1. O listă liniară simplu înlănţuită este o structură de forma:
Alocarea dublu înlănţuită. Alocarea simplu înlănţuită permite parcurgerea listei într-un singur sens
{de la stânga la dreapta}- în cazul în care se doreşte ca lista să poată fi parcursă în ambele sensuri se
utilizează alocarea dublu înlănţuită. Aici fiecare nod reţine adresele predecesorului şi succesorului
său, aşa cum se vede în figura următoare:
1. Accesul la un nod al listei se face prin parcurgerea nodurilor care îl preced. Aceasta necesită un
efort de calcul.
Fie lista:
adrt
Se completează informaţiile pentru nodul creat –adresa acestuia va trebui să conţină adresa
nodului care trebuie să-i urmeze în listă:
5 adr2
adrt
Se modifică adresa nodului care precede nodul nou creat. Adresa trebuie să fie a nodului
nou creat:
in2 adr2
adr2 adr2
De acum, putem “privi” lista aşa cum am fost obişnuiţi:
Pentru a exemplifica operaţiile efectuate în acest caz vom folosi lista de mai sus, la care
ştergem al doilea nod (cel cu informaţia 5). Iată etapele:
Observaţii:
În cazul alocării înlăntuite, adresele de memorare ale nodurilor consecutive nu sunt
neapărat consecutive. Pentru a realiza acest lucru este suficient să analizati cazul stergerii
unui nod {sau acela al adăugării unui nod}.
Prin alocarea memoriei pentru un nod înţelegem rezervarea spaţiului necesar memorării
informatiilor conţinute de acesta. Evident, se poate aloca memorie doar dacă există memorie
disponibilă, adică nu este ocupată de alte variabile.
Prin eliberarea memoriei ocupate de un nod înţelegem că spaţiul ocupat de acesta devine
disponibil-este pus la dispoziţia programatorului, pentru ca, eventual, acesta să fie din nou
alocat.
Este important să folosim termenii corect. De exemplu, nu putem folosi în loc de ”alocarea
memoriei” termenul ”crearea memoriei”, tot aşa cum nu este corect să folosim în loc de
”eliberarea memoriei” termenul ”ştergere a memoriei”.
Iată cum se descrie informaţia dintr-un nod, în cazul listelor simplu înlănţuite, atunci când
acesta reţine un număr întreg.
Type Adresa=Integer;
info adresa nodului următor
Nod=record
info:integer;
adr_urm:Adresa;
end;
Pentru a nu face confuzie între informatia de adresă, care este tot de tip integer, şi restul
informaţiei memorate, am ”rebotezat” tipul integer.
Pentru memorarea listei folosim un vector care are componentele de tip Nod, descris mai
jos:
Lista=array[1..1000] of Nod;
Var L:lista;
Din descriere rezultă că lista poate avea cel mult 1000 de noduri. Acesta este spaţiul
disponibil. Spaţiul disponibil se gestionează prin următoarele variabile:
L 7 3 5 4 1 5 4 0
1 2 3 4 5 6
ocupat 1 0 1 1 1 0
1 2 3 4 5 6
Figura anterioară prezintă modul în care este memorată o listă cu 4 noduri, într-un vector cu 6
componente. Lista este: 7, 5, 1, 4
Funcţia următoare testează dacă există spaţiu disponibil pentru alocarea unui nou nod:
function Exista_spatiu:boolean;
begin
Exista_spatiu:=nr_elem<l000;
end;
procedure elibereaza(x:adresa);
begin
ocupat[x]:=0;
nr_elem:=nr_elem-1;
end;
Procedura adaugare are rolul de a adăuga la sfârsitul listei un nod, care reţine valoarea
transmisă de variabila val. Programul lucrează cu lista pornind de la adresa primului nod
memorat, adresă care se găseşte în v. De asemenea, pentru uşurinţa prelucrării se reţine şi
adresa ultimului nod sf.
Procedura tratează diferit cazurile în care lista este vidă, deci se creează primul nod al ei şi
cazul în care adăugarea se face la o listă nevidă,
În primul caz se alocă nodul, se completează cu informatia numerică, iar câmpul de adresă
va reţine 0.
În al doilea caz, se testează existenţa spaţiului, iar în caz că acesta există se alocă spaţiul
pentru nod. Nodul reţine 0, pentru adresa nodului următor (pentru că este ultimul în listă).
Ultimul nod al listei (cu adresa sf) va reţine adresa nodului nou creat, iar variabila sf va
reţine adresa nodului nou creat.
Procedura inserare_dupa inserează un nod după un altul, care reţine valoarea numerică val.
Noul nod retine valoarea numerică val1.
Procedura inserare_inainte inserează un nod înaintea altuia care reţine o valoare dată,
transmisă prin val:
Observaţii:
Alocarea înlănţuită prin utilizarea vectorilor tine deja de istoria informaticii. Cu adevărat,
pentru alocarea înlănţuită a unei structuri se utilizează o zonă de memorie, special rezervată
în limbajele de programare actuale, numită HEAP. VOM PREZENTA, MAI DEPARTE, SOLUTIA
DINAMICĂ .
3. Implementarea alocării înlănţuite dinamic. Structuri dinamice de
date. -cea mai buna variantă.
Variabilele pot fi statice sau dinamice. Cele statice sunt alocate în timpul compilării, în zone
bine definite de memorie. Structura, tipul şi locul lor din memorie nu se pot modifica în timpul
execuţiei programului. Statice sunt toate variabilele folosite până acum.
Variabila de tip referinţă poate conţine referiri numai la variabila dinamică care i-a fost
pusă în corespondenţă. Referirea se realizează prin memorarea în variabila de tip referinţă a adresei
unde este stocată variabila dinamică. Corespondenţa între variabila dinamică şi tipul de referinţă
permite cunoaşterea structurii variabilei dinamice.
Pentru variabilele de tip referinţă se va aloca, în timpul compilării, un spaţiu de memorie de
4 octeţi, care va conţine adresa de memorie a variabilei dinamice referite.
Variabilele dinamice se alocă într-o zonă de memorie numită heap, diferită de zona fixă a
programului, unde se memoreză variabilele statice.
O variabilă dinamică referită va ocupa un spaţiu de memorie corespunzător tipului ei: 2
octeţi pentru Integer, 6 octeţi pentru Real, 10 octeţi pentru un şir de 9 caractere (String[9]) etc.
Defirea unui tip referinţă
MEMORIA
Zona Heap
2500
programul
zona variabilelor varibila dinamică referită
pr pr^
Procedura New alocă spaţiu în HEAP pentru o variabilă dinamică. După alocare, adresa
variabilei se găseste în p
procedure New(var P: Pointer)
Procedura Dispose eliberează spaţiul rezervat pentru variabila a cărei adresă este reţinută în
p. După eliberare, conţinutul variabilei p este nedefinit.
Exemplu:
program TestPointer;
type complex = record
re, im: Real
end;
pComplex =^complex;
var pz: pComplex; sau
pz : ^complex;
begin
New(pz); pz^.re: =l .2; pz^. im:=5 . 6;
WriteLn ('Nr. complex: ',pz^.re, ^ ' ', pz^.im);
Dispose(pz); ReadLn
end.
Cu variabilele dinamice se pot executa toate operaţiile posibile având datele de respectivul tip.
Următorul program creează o listă liniară simplu înlănţuită cu 3 noduri care reţin 1 2 3.
program exemplu;
type Adresa=^Nod;
Nod=record
info:integer;
adr_urm:Adresa;
end;
var c,d,v:Adresa;
begin
New(v); v^.info:=l;
New(c); c^.info:=2;
v^ .adr_urm: =c ;
New(d);
d^.info:=3;
d^.adr_urm:=nil;
c ^.adr_urm:=d;
{listare}
c: =v;
while c<>nil do
begin
write(c^.info,’ ‘);
c:=c ^.adr_urm;
end;
writeln;
end.
New(v); v^.info: =2
v 1
c 2
v 1
v^.adr_urm: =c;
c 2
Adresa următoare, pentru primul nod alocat va reţine adresa următorului nod alocat.
v 1
New(d);
d^.info:=3;d^.adr_urm:=nil;
c^.adr_urm: =d;
c 2
d 3 0
Am alocat spaţiu pentru al treilea nod. Acesta va reţine 3 în info şi nil (nici o adresă) pentru
adr_urm. De fapt, pentru nil se reţine 0, dar nu se poate lucra cu această valoare.
v 1
Din acest moment, se poate lucra cu
lista cunoscând doar adresa sa de
2 început (a primului nod) v.
3 0
Programul următor, prezintă modul de lucru cu o listă liniară simplu înlăntuită. Este identic
cu cel prezentat în paragraful anterior, singura diferentă este dată de faptul că lista este memorată în
HEAP.
program Lista_liniara;
Type Adresa=^Nod;
Nod=record
info:integer;
adr_urm:Adresa;
end;
var prim,ultim:Adresa;
i:integer;
procedure inserare_dupa(prim:adresa;val,val1:integer);
var p,q:adresa;
begin
p:=prim;
while p^.info<>val do p:=p^.adr_urm;
new(q); q^.info:=val1; q^ .adr_urm:=p^.adr_urm; p^.adr_urm:=q;
if q^.adr_urm=nil then ultim:=q;
end;
procedure listare(prim:Adresa) ;
Var p:Adresa;
begin
p:=prim;
while p<>nil do
begin
write(p^.info, ' ');
p:=p^.adr_urm;
end;
writeln;
end;
begin
{se construieste lista}
for i:=1 to 10 do Adaugare(prim,i);
writeln('lista asa cum a fost creata');
listare(prim);
writeln('inserez dupa 5 11');
inserare_dupa(prim,5,11);
listare(prim);
end.
Observaţii:
Alocarea dinamică a memoriei prezintă avantajul că programul utilizează o zonă de memorie
oricum rezervată, numită HEAP. În acest fel,programul are ”la dispozitie” mai multă
memorie.
{Adaugarea unui nou nod intr-o pozitie oarecare cunoscand informatia X a nodului
dupa care se face inserarea}
begin
clrscr;
repeat
WriteLn('1.CREARE');
WriteLn('2.PARCURGERE');
WriteLn('3.ORDONARE');
WriteLn('4.INSERARE FATA');
WriteLn('5.INSERARE OAREC');
WriteLn('6.Stergere');
WriteLn('7.IESIRE');
Write('Alege optiunea ');
ReadLn(Optiune);
case Optiune of
1:Creare(Prim);
2:Parcurgere(Prim);
3:Ordonare(Prim);
4:Inserare_Cap_Lista(Prim);
5:begin
Write('dati informatia nodului dupa care inserati :');
ReadLn(X);
Inserare_Poz_Oarecare(Prim,X);
end;
6:begin
Write('dati informatia nodului care se sterge :');
ReadLn(X);
Stergere(Prim,X);
end;
end;
until Optiune=7;
end.
Aplicaţii.
1. Creati o lista s.i. care sa contina datele despre studentii unei grupe: nume, prenume, grupa, medie.
Se va crea lista si se va afisa.