Sunteți pe pagina 1din 12

CAP.11 Atribuirea adr1:=adr2 e corecta.

Atribuirile adr1:=adr3, sau adr1:=adr4 sunt gresite.


STRUCTURI DINAMICE DE DATE
11.2 NoŃiunea de variabilă dinamică
11.1 Tipul referinŃă(pointer)
O variabila dinamica este o variabila care poate fi alocata dinamic.
Pointerii sunt variabile care conŃin ( sunt capabile să conŃină) Astfel spaŃiul necesar alocării este rezervat intr-un segment special
adresele unor alte variabile sau obiecte, deci practic adrese de destinat acestui scop, numit HEAP.
memorie. Rezervarea spaŃiului se face in timpul executării programului,
Variabilele de tip pointer nu pot fi citite, nu pot fi tipărite în atunci cand se executa o anumita procedura, scrisa special in acest
mod direct şi, cu o singură excepŃie, conŃinutul lor nu poate fi scop. In Borland Pascal se foloseşte procedura New pentru alocarea
modificat în urma unor operaŃii aritmetice. spaŃiului in HEAP. După alocare adresa variabilei se găseşte in p:
Tipul unei varibile pointer se declară astfel: type nume= ^tip; procedure New(var p:pointer).
Fiecare tip de data are alt tip de adresa, astfel exista „pointer catre SpaŃiul din memorie poate fi eliberat când variabila nu mai este
variabila de tip integer” (ex. type pint=^integer), pointer catre utila, pentru aceasta se foloseşte procedura Dispose:
variabila de tip real” (ex. type preal=^real), pointer catre variabila procedure Dispose(var p:pointer). După eliberare conŃinutul din
de tip string”, (ex. type pstring=^string), pointer catre variabila de variabila p este nedefinit.
tip inregistrare”
(ex. type inreg=record Mecanismul alocării dinamice:
nume,prenume:string[10];
varsta:byte; Fie p o variabila de tip pointer care permite memorarea unei adrese.
end, Prin apelarea procedurii new se va aloca o variabila dinamica a cărei
type pinreg=^inreg), adresa va fi retinuta in p. Orice acces la variabila alocata dinamic se
deci tipul pointer este diferit. face prin intermediul variabilei p in felul urmator: se utilizeaza
Intre variabile de tip pointer sunt permise atribuiri doar daca numele variabilei de tip pointer urmat de operatorul „^”.
variabilele au acelasi tip pointer si sunt descrise la fel.
Exemplu:
Type pint=^integer;
Var adr1,adr2:^integer;
adr3:pint;
adr4:^real,

46
11.3 Structuri de date înlănŃuite
O lista dublu inlantuita este tot o lista liniara , avand proprietatea ca
11.3.1 Liste liniare poate fi parcursa in ambele sensuri , deci si spre nodul anterior:

Aspecte teoretice. DefiniŃie. OperaŃii asupra listelor Adr1 Adr2 Adr n


Nil inf1 adr1 Adr1 inf2 Adr3 Adr n-1 inf n Nil
DefiniŃie. O listă L e o secvenŃă de zero sau mai multe
elemente, numite noduri, toate fiind de acelaşi tip de baza T.
L=a1,a2,...,an (n>=0)
Dacă n>=1, a1 se spune că este primul nod al listei, iar an, ultimul Implementarea listelor liniare simplu înlănŃuite. Structuri recursive de
nod. Daca n=0, lista este vida. tip listă
O proprietate importantă a unei liste este aceea că nodurile sale
pot fi ordonate liniar funcŃie de poziŃia lor în cadrul listei. Se Cu ajutorul tipului pointer, se defineşte structura unui nod al listei
spune că ai precede pe ai+1 (i=1,2,...,n-1), iar ai succede pe ai-1 liniare care apare ca o structură recursivă, având o componentă de tip
(i=2,3,...,n), ai aflându-se pe poziŃia i. identic cu al structurii complete.
Se postulează(presupune) existenŃa poziŃiei următoare ultimului
element al listei şi se introduce funcŃia FIN(L) ce va returna poziŃia type PointerNod=^Nod;
următoare poziŃiei n din lista L de n elemente. Nod=record
Folosind notaŃiile anterioare şi notând x(de tip T) un nod al listei, cheie:TipCheie;
iar p fiind de tip poziŃie, se introduce următorul set reprezentativ de urmator, anterior:PointerNod;
operatori aplicabili obiectelor de tip lista: info:TipInfo
INSEREAZA(L,x,p)- inserează în lista L nodul x, în poziŃia p; end;
dacă L=a1,a2,...,an, în urma inserŃiei: var început:PointerNod;
p<FIN(L),L=a1,...,ap-1,x,a p+1,...,an
p=FIN(L),L=a1,...,an,x Caracteristica unei astfel de structuri constă în prezenta unei
p>FIN(L),rezultatul inserŃiei este imprevizibil. singure înlănŃuiri. Câmpul cheie serveşte la identificarea nodului(
acest câmp poate face parte din informaŃia utilă, el este utilizat în
O lista simplu inlantuita este de forma : cazul căutărilor, sortării…), câmpul următor e pointer de înlănŃuire la
Adr1 Adr2 Adr n nodul următor, iar cel info conŃine informaŃia utilă.
Variabila început indica spre primul nod al listei; în unele situaŃii
Inf1 Adr2 Inf2 Adr3 Inf n nil
în locul lui început se utilizează un nod fictiv, adică o variabila de tip

47
nod cu câmpurile cheie şi info neprecizate, dar câmpul următor q^.anterior:=sfarsit;
indicând spre primul nod al listei. {asignarea câmpurilor cheie şi info}
De asemenea uneori e util a se păstra pointerul spre ultimul nod al sfirsit:=q;
listei.
O varianta este a listelor circulare la care dispare noŃiunea de Pentru inserŃia la sfârşitul listei e necesara existenŃa a cel puŃin un
prim, ultim nod. nod, care se creează prin procedura de la paragraful anterior.

Tehnici de inserŃie a nodurilor şi de creare a listelor înlănŃuite


c)inserŃia unui nod după unul indicat (p)

a)inserŃia unui nod la începutul listei E simplă pentru că se cunoaşte pointerul spre nodul anterior şi
spre cel următor celui ce se inserează (pointerul spre nodul următor e
Dacă început e variabila pointer ce indica spre primul nod al valoarea câmpului următor al nodului indicat).
listei, iar q o variabila auxiliara de tip pointer, secvenŃa următoare new(q);
realizează inserŃia la începutul listei şi actualizează pointerul început: q^.urmator:=p^.urmator; {legăm nodul de nodul anterior}
new(q); {creează spaŃiu pentru un nou nod} q^anterior:=p;
q^.urmator:=inceput; p^.urmator:=q; {legăm nodul anterior de q}
q^.anterior:=nil; p^.urmator^.anterior:=q
{asignarea câmpurilor cheie şi info}
inceput:=q; d)inserŃia unui nod în faŃa unui nod indicat
SecvenŃa e corectă şi pentru inserŃia într-o listă vidă, caz în care
inceput=nil (nil fiind pointerul vid, care nu se refera la nici o variabilă Printr-un artificiu, se reduce acest caz la cel anterior: se inserează
indicată). un nod după cel indicat, cheia şi informaŃia din nodul indicat fiind
atribuite noului nod inserat şi fiind înlocuite cu valorile nodului ce
trebuia inserat.
b)inserŃia unui nod la sfârşitul listei

Devine mai simplă dacă se păstrează o variabilă sfârşit indicând Tehnici de suprimare
spre ultimul nod al listei:
new(q); {creează spatiu pentru noul nod ultim al listei} a) Suprimarea nodului următor celui indicat de o variabila
sfirsit^.urmator:=q; pointer q se face astfel:
q^.urmator:=nil;

48
begin
p:=q^.urmator; {punem un indicator către nodul care urmează a fi write(q^.inf);
şters} q:=q^.urm;
p^.urmator^.anerior:= q; end;
q^.urmator:=p^.urmator;{nodul anterior celui ce urmează a fi şters end.
pointează către nodul următor acestuia}
dispose(p);{ eliberăm memoria ocupată de nod} Programe cu liste:
program liste_simplu_inlantuite;
Pentru a elibera memoria ocupată de nodul care va fi şters mai avem uses crt;
type pnod=^nod;
nevoie de un pointer spre acest nod. După ce s-a făcut ruperea nod=record
legăturilor se eliberează memoria cu dispose. d:integer;
urm:pnod;
end;
var cap,sfir,y:pnod;
b) Suprimarea nodului indicata de o variabilă pointer q (pentru liste op:char;
simplu inlantuite)se face astfel: x:integer;
procedure inserare_inceput(x:integer);
p:=q^.urmator;{se memorează legătura către nodul următor} var q:pnod;
q^:=q^.urm^;{se copiază conŃinutul nodului următor peste cel curent} begin
new(q);
dispose(p);{se dezalocă memoria} q^.d:=x;
Această metodă nu poate fi utilizată pentru ultimul nod din listă. q^.urm:=cap;
if cap=nil then sfir:=q;
cap:=q;
end;
Traversarea unei liste înlănŃuite (Listarea) procedure inserare_sfirsit(x:integer);
var q:pnod;
Dacă nodul de început al listei e indicat de variabila început, o begin
variabila auxiliara q, care parcurge toate nodurile listei până când if sfir=nil then inserare_inceput(x)
valoarea ei devine nil, permite accesul la fiecare nod şi efectuarea else
begin
operaŃiei specifice traversării. new(q);
q^.d:=x;
procedure listare (q:PointerNod); q^.urm:=nil;
begin sfir^.urm:=q;
sfir:=q;
while q<>nil do
end;

49
end; y:=y^.urm;
procedure sterge_nod_urmator(p:pnod); end;
var q:pnod; function palindrom(x:pnod):boolean;
begin var f:boolean;
q:=p^.urm; begin
p^.urm:=p^.urm^.urm; f:=true;
dispose(q); y:=cap;
end; pal(x,f);
procedure sterge_nod_curent(var p:pnod); palindrom:=f;
var q:pnod; end;}
begin function palindrom(x:pnod):boolean;
if q<>nil then var f:boolean;
begin begin
q:=p^.urm; if x^.urm<>nil then palindrom:=palindrom(x^.urm)
p^:=p^.urm^; else palindrom:=true;
dispose(q); if x^.d<>y^.d then palindrom:=false;
end; y:=y^.urm;
end;
function cauta(x:integer):pnod; end;
var q:pnod; BEGIN
begin cap:=nil;sfir:=nil;
q:=cap; repeat
while (q<>nil)and(q^.d<>x)do q:=q^.urm; clrscr;
cauta:=q; writeln('1..Adaugare');
end; writeln('2..Afisare');
procedure afisare; writeln('3..Sterge dupa');
var q:pnod; writeln('4..Sterge');
begin writeln('5..Palindrom');
q:=cap; write('Dati optiunea:');readln(op);
while q<>nil do case op of
begin '1':begin write('Dati
writeln(q^.d); x:');readln(x);inserare_sfirsit(x);readln;end;
q:=q^.urm; '2':begin afisare;readln;end;
end; '3':begin write('Dati
end; x:');readln(x);y:=cauta(x);sterge_nod_urmator(y);readln;
end;
{procedure pal(x:pnod;var f:boolean); '4':begin write('Dati
begin x:');readln(x);y:=cauta(x);sterge_nod_curent(y);readln;e
if x^.urm<>nil then pal(x^.urm,f); nd;
if x^.d<>y^.d then f:=false;

50
'5':begin sf^.urm:=q;{ultimul din lista indica catre nodul nou
y:=cap;writeln('Palindrom=',palindrom(cap));readln;end; introdus}
end; sf:=q;{nodul nou introdus devine ultimul din lista}
until op='e'; end;
END. end;

program liste_dublu_inlantuite; procedure adaug_dupa(x:integer;p:pnod);{adauga dupa


uses crt; nodul p}
type pnod=^nod; var q:pnod;
nod=record begin
data:integer; if p<>nil then
ant,urm:pnod;{legaturile catre nodul anterior, begin
urmator} new(q);{alocam memorie}
end; q^.data:=x;{memoram informatia}
var cap, sf:pnod; q^.ant:=p;{legam nodul nostru de nodul p(va fi
o:char;k,du:integer; anterior)}
procedure adaug_la_inceput(x:integer); q^.urm:=p^.urm;{legam nodul de nodul urmator}
var q:pnod; p^.urm:=q;{nodul p indica catre q}
begin if q^.urm=nil then sf:=q{daca dupa q nu e nimic atunci e
new(q);{alocam memorie} ultimul din lista}
q^.data:=x;{memoram informatia} else q^.urm^.ant:=q;{nodul de dupa q va indica catre
q^.ant:=nil;{inainte de primul nu este nimic} acesta}
q^.urm:=cap;{dupa el este primul din lista}
if cap=nil then sf:=q{daca nu era numic in lista atunci end;
acest nod este si ultimul} end;
else cap^.ant:=q;{legam primul nod din lista de nodul
nou introdus} procedure adaug_inainte(x:integer;p:pnod);
cap:=q;{devine primul nod din lista} var q:pnod;
end; begin
new(q);{alocam memorie}
procedure adaug_la_sfirsit(x:integer); q^.data:=x;{memoram informatia}
var q:pnod; q^.urm:=p;{legam nodul q de nodul p }
begin q^.ant:=p^.ant;{legam pe q de nodul anterior lui p}
if cap=nil then adaug_la_inceput(x){daca nu e nimic in p^.ant:=q;{legam pe p de q}
lista adaugarea se face la inceput} if q^.ant=nil then cap:=q{daca nodul anterior nu exista
else begin{daca este ceva in lista} atunci q e primul nod}
new(q);{alocam memorie} else q^.ant^.urm:=q;{nodul anterior lui q indica
q^.data:=x;{memoram informatia} catre q}
q^.urm:=nil;{dupa ultimul nu se afla nimic}
q^.ant:=sf;{il legam de ultimul nod in lista} end;

51
end;
procedure sterge_curent(p:pnod);
begin procedure afisare_coada_cap;
if p<>nil then {daca avem ce sterge} var q:pnod;
begin begin
if p^.ant<>nil then {daca nodul anterior exista q:=sf;
atunci} while q<>nil do
p^.ant^.urm:=p^.urm{acesta indica catre nodul begin
urmator} writeln(q^.data);
else cap:=p^.urm;{daca nu exista atunci p e q:=q^.ant;
primul nod, deci cap va indica catre nodul urmator} end;
if p^.urm<>nil then {daca nodul urmator exista end;
atunci}
p^.urm^.ant:=p^.ant {acesta va indica catre begin
nodul anterior} repeat
else sf:=p^.ant; {daca nu exista atunci p e clrscr;
ultimul din lista, deci sf va indica catre nodul writeln('1..Adaugare la inceput');
anterior lui p} writeln('2..Adaugare la sfirsit');
dispose(p);{dezalocam memoria} writeln('3..Stergere');
end; writeln('4..Afisare');
end; writeln('5..Adaugare inaintea unui nod');
function cauta(x:integer):pnod; writeln('6..Adaugare dupa un nod');
var q:pnod;f:boolean; writeln('7..Exit');
begin readln(o);
q:=cap;f:=false; case o of
while (q<>nil)and (not f) do '1':begin
if q^.data=x then f:=true write('Dati elem. de introdus:');readln(k);
else q:=q^.urm; adaug_la_inceput(k);
cauta:=q; end;
end; '2':begin
write('Dati elem. de introdus:');readln(k);
procedure afisare_cap_coada; adaug_la_sfirsit(k);
var q:pnod; end;
begin '3':begin
q:=cap; write('Dati elem. de sters:');readln(k);
while q<>nil do sterge_curent(cauta(k));
begin end;
writeln(q^.data); '4':begin
q:=q^.urm; afisare_cap_coada;readln;afisare_coada_cap;readln;end;
end; '5':begin

52
write('Dati elem. de introdus:');readln(k); procedure citire;
write('Dati elem. inaintea caruia se face var f:text;x,y:integer;
adaugarea:');readln(du); begin
adaug_inainte(k,cauta(du)); assign(f,'date.in');reset(f);
readln(f,n);
end; while not seekeof(f) do
'6':begin begin
write('Dati elem. de introdus:');readln(k); readln(f,x,y);
write('Dati elem. dupa care se face add(x,y);
adaugarea:');readln(du); end;
adaug_dupa(k,cauta(du)); close(f);
end;
end; function grad(v:integer):integer;
end; var p:pnod;g:integer;
until o='7'; begin
end. p:=a[v];g:=0;{gradul lui v este egal cu nr de noduri
din lista a[v]}
program vector_de_liste; while p<>nil do
type pnod=^nod; begin
nod=record{nodul istei} inc(g);p:=p^.urm;
x:integer; end;
urm:pnod; grad:=g;
end; end;
var a:array[1..100] of pnod;{vectorul de capete ale
listei} BEGIN
n,i:integer; citire;
procedure ad(x:integer; var c:pnod);{adauga elementul x writeln('Gradele varfurilor sunt:');
in lista cu capul c} for i:=1 to n do
var p:pnod; writeln('varful ',i,' are gradul ',grad(i));
begin
new(p); END.
p^.x:=x;
p^.urm:=c;
c:=p;
end;
procedure add(x,y:integer);{adauga muchia x-y}
begin
ad(x,a[y]);
ad(y,a[x]);
end;

53
11.3.2 Liste particulare procedure push(x:integer);{introducere in stiva}
var a:pnod;
begin
Stiva new(a);{alocam memorie}
a^.d:=x;{memoram informatia}
Functioneaza dupa principiul LIFO (Last In First Out) - „Ultimul a^.urm:=cap;{punem valoarea pe prima pozitie}
intrat primul iesit” cap:=a;
end;
Atat inserarea cat si adaugarea de elemente in stiva se face de la un function pop:integer;{scoate elementul din virful
singur capat: stivei,daca e goala returneaza -maxint}
Ultimul nod introdus a fost 3. Varful stivei retine adresa ultimului var a:pnod;
nod, iar daca stiva e vida retine nil. begin
pop:=-maxint;
if cap<> nil then
V begin
a:=cap;{punem un pointer catre cap}
pop:=cap^.d;{memoram valoarea din virful stivei}
3 cap:=cap^.urm;{cap "coboara" cu o pozitie}
dispose(a);{dezalocam memoria}
end;
2 end;
procedure afisare;
var a:pnod;
1 begin
a:=cap;
while a<>NIL do
Operatiile permise sunt: begin
- adăugarea unui element in stiva (operatia push); writeln(a^.d);
- eliminarea unui element din stiva(operatia pop); a:=a^.urm;
end;
- verificarea daca stiva e goala (is_empty); writeln;
end;
program stiva; begin
type pnod=^nod;{pnod=pointer la nodul listei} repeat
nod=record write('Dati valoarea ce se introduce:');readln(x);
d:integer;{data ce se intoduce in stiva} push(x);
urm:pnod;{legatura catre urmatorul nod} until x=0;{citim valori pina cind se introduce 0}
end; repeat
var cap:pnod;{cap=capul listei(stivei)} afisare;{afisam stiva}
x:integer; readln;{asteptam apasarea tastei <ENTER>}

54
x:=pop; if cap=nil then cap:=p
writeln('Am scos:',x) else sf^.urm:=p;
until x=-maxint;{scoatem elemente si afisam pina golim sf:=p;
stiva} end;
end. close(f);
repeat
clrscr;
Coada
writeln('0..Afisare');writeln('1..Adaugare');
Intr-o coada inserarea se face la unul din capete, iar stergerea la writeln('2..Extragere');writeln('3..Test');
celalalt capăt. FuncŃionează după principiul FIFO (Firs In First writeln('4..Exit');readln(op);
Out). Pentru alocarea dinamica inlantuita a cozii o variabila v va case op of
retine adresa elementului ce va fi scos, iar variabila sf va retine adresa '0':begin
p:=cap;
ultimului element introdus in coada. while p<>nil do
v sf begin
writeln(p^.d);p:=p^.urm;
end;
1 2 3 4 readln;
end;
'1':begin
Se folosesc aceleaşi operaŃii ca si la stiva. write('Dati elem:');readln(s);
new(p);p^.d:=s;p^.urm:=nil;
if cap=nil then cap:=p
else sf^.urm:=p;
program coada; sf:=p;
uses crt; end;
type pnod=^nod; '2':if cap<>nil then
nod=record begin
d:string;urm:pnod; writeln('Data:',cap^.d);
end; p:=cap;cap:=cap^.urm;dispose(p);
var cap,sf,p,q:pnod; readln;
f:text;op:char;s:string; end;
begin '3':if cap=nil then writeln('Goala') else
assign(f,'date.txt'); writeln('nu e goala');
reset(f); end;
while not eof(f) do until op='4';
begin rewrite(f);
new(p); p:=cap;
readln(f,s); while p<>nil do
p^.d:=s;p^.urm:=nil; begin

55
writeln(f,p^.d); end
p:=p^.urm; else
end; begin
close(f); a^.urm:=endl^.urm;
end. endl^.urm:=a;
end;
endl:=a;
Liste circulare end;
procedure citire;
Fie o lista liniara L. Stiind ca variabila de tip pointer cap var i:integer;
memoreaza adresa primului nod , iar sf adresa ultimului element din s:string;
begin
lista se pune problema ce s-ar intampla daca ar avea loc operatia write('Dati nr. de copii:');
sf^.urmator :=cap. Se observa ca dupa aceasta operatie lista nu va readln(n);
mai avea practic inceput si sfarsit, o astfel de lista se numeste lista for i:=1 to n do
circulara. begin
La fel ca la listele liniare si aici se poate face adaugarea sau write('Dati copilul ',i,' :');readln(s);
adaug(s);
eliminarea de noduri din lista, sau parcurgerea listei pornind da la un end;
anumit element ( Principul este acelasi ca si la listele liniare ). write('Dati nr. k:');readln(k);
Observatie ! o lista circulara cu un singur element retine in campul end;
« urmator » adresa sa. Ex cap^.inf :=4 ; cap^.urmator :=cap ; procedure sterge(x:pnod);
var a:pnod;
begin
program joc;
a:=x^.urm;{a=nodul(copilul) care se sterge(iasa din
type pnod=^nod;{pnod=pointer la nodul listei}
joc) }
nod=record
writeln(a^.d);{tiparim numele copilului}
d:string;{numele copilului}
x^.urm:=x^.urm^.urm;{nodul din fata lui 'a' pointeaza
urm:pnod;{legatura catre urmatorul nod}
catre cel de dupa 'a'}
end;
dispose(a);
var cap,endl:pnod;{cap=capul listei}
end;
n,k:integer;
procedure joc;
procedure adaug(s:string);
var a,p:pnod;
var a:pnod;
i:integer;
begin
begin
new(a);
p:=endl;
a^.d:=s;
while p^.urm<>p do
if cap=nil then begin
begin
cap:=a;
for i:=1 to k-1 do
cap^.urm:=cap;
p:=p^.urm;

56
sterge(p);
end;
writeln('A cistigat ',p^.d);
end;
begin
citire;
joc;
end.

57

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