Sunteți pe pagina 1din 15

Liste liniare dublu înlănţuite

Clasa XI E

Rotaru Cosmin Leonard

Liceul de Informatică ,,Ştefan Odobleja”, Craiova, 2010

1
Liste liniare dublu înlănţuite

O listă liniară dublu înlanţuită este o listă care respectă următoarele reguli:
> fiecare element al listei memorează o informaţie de acelas tip;
> oricare element din interiorul listei are un predecesor şi un succesor;
> există un element pentru care nu există decât succesor, pe care-l vol numi primul element;
> există un element al listei care nu are decât un predecesor şi pe care-l vom numi ultimul
element.

Fiind structuri de date înlănţuite avem nevoie de un tip de date care să memoreze informaţia,
precum şi adresele elementului predecesor şi a elementului succesor.

Definirea unei liste dublu înlănţuite:


type lista=^nod;
nod=record
inf:integer;
urm,pred:lista;
end;

inf – câmpul de informaţie utilă;


urm – pointer ce conţine adresa elementului următor
pred – pointer ce conţine adresa elementului anterior(predecesor)

Datorită dublei legături o listă poate fi parcursă în ambele sensuri.De aceea pentru o mai usoară
gestionare a listei vom utiliza doi pointeri ce vor conţine:
 pr – adresa primului element.Primul element va avea în campul pred valoarea NIL
 ul – Adresa ultimui element.Primul element va avea în campul urm valoarea NIL

Crearea unei liste cu n elemente întregi


Vom utiliză trei pointeri:
 pr – va referi primul element al listei

2
 ul – va referi ultimul element al listei
 el_nou – va conţine la fiecare pas adresa elementului creat.

Vom crea mai întâi primul nod.Apoi, utilizând un ciclu for vom crea celelalte
noduri.Fiecare din cele n-1 noduri va fi adăugat la sfarsitul listei.
Putem descrie crearea unei liste astfel:
secventa_1;
for i:=1 to n-1 do
secventa_2;

1.Crearea primului nod(secvenţa_1):


> alocăm memorie primului element: New(pr);
> iniţializăm câmpul de informaţie utilă:Readln(pr^.inf);
> legătură anterioară cat şi cea următoare sunt NIL:
pr^.pred :=nil;pr^.urm:=nil;
> în acest moment primul element este şi ultimul: ul:=pr;

2.Crearea celorlalte noduri (secvenţa_2):


Vom crea celelalte elemente n-1 noduri utilizand un ciclu for.Fiecare element va fi
adăugat la sfarsitul listei.Pentru adăugarea unui nod la sfarsit vom proceda astfel:
> alocăm memorie unui nou element: new(el_nou);
> iniţializăm campul de informaţie utilă: readln(el_nou^.inf);
> legătura să urmatoare este NIL: el_nou^.urm:=nil;
> legatura să anterioară este ul: el_nou^.pred:=ul;
> legătura anterioară a lui ul trebuie să adreseze elementul adăugat: ul^.adr:=el_nou;
> elementul adăugat va deveni ultimul element: ul:=el_nou;

Parcurgerea unei liste dublu înlănţuite


Parcurgem nodurile listei cu ajutorul unui pointer p care, plecand de la primul nod (sau
ultimul nod), va referi pe rand fiecare nod al listei.

3
Parcurgerea listei direct
- Iniţial p este pointer către primul nod: p:=pr;
- Cat timp listă nu e vidă (p<>nil)
 Prelucrăm informaţia nodului referit de p:
write(p^.inf);
 Mutăm pointerul p la nodul următor:
p:=p^.urm;
p:=pr;
while p<>nil do
begin
write(p^.inf.’ ‘);
p:=p^.urm;
end;

Parcurgerea lstei invers


- Iniţial p este pointer către ultimul nod: p:=ul
- Cat timp listă nu este vidă (p<>nil)
 Prelucrăm informaţia nodului referit de p:
write(p^.inf);
 Mutăm pointerul p la nodul anterior:
p:=p^.pred;
p:=ul;
while p<>nil do
begin
write(p^.inf,’ ‘);
p:=p^.pred;
end;

4
Exemplu:
Următorul program realizeaza crearea şi afisarea unei liste dublu înlănţuite cu număr cunoscut
de elemente.

type lista=^nod; begin


nod=record while ul<>nil do begin
inf:integer; write(ul^.inf, ‘ ‘);ul:=ul^.pred;
pred,urm:lista; end;
end; writeln;
var pr,ul :lista; n:integer; end;
procedure creare (var pr,ul:lista); begin(main);
var p:lista; i:integer; readln(n); creare (pr,ul);
begin afis1(pr);
new (pr); afis2(ul);
readln(pr^.inf); end
pr^.pred:=nil; pr^.urm:=nil;
ul:=pr;
for i:=1 to n-1 do begin
new(p); readln (p^.inf);
p^.urm:=nil; p^.pred:=ul;
ul^.urm:=p; ul:=p;
end;
end;
procedure afis1(pr:lista);
begin
while pr<> nil do begin
write(pr^>inf, ‘ ‘); pr:=pr^.urm;
end;
writeln;
end;
procedure afis2(ul:lista);

5
Crarea unei liste când nu cunoastem numărul de elemente
Atunci când nu se cunoaste de la început numărul de elemente ce trebuie adaugate se va
utiliza un ciclu while în locul ciclului for pentru crearea listei.
În continuare vom prezenta o aplicatie care citeste numere dintr-un fisier şi creează o listă
liniară dublu înlăntuită.
Aplicatie
Se dă fisierul ,,Date.in’’ ce conţine numere întregi.Să se creeze o listă dublu înlăntuită ce
conţine numerele pare din fisier.
Mod de rezolvare: Se initializează pointerul către primul nod, pr cu NIL (initial este
vidă).Se citesc numerele din fisier, elementele pare fiind adăugate în listă.Dacă listă este vidă se
creează primul nod, care în acel moment este şi ultimul.Urmatoarele numere pare se adauge la
sfarsitul listei.

type lista=^/nod;
nod=record;
inf:integer;
pred,urm:lista;
end;
var pr,ul:lista; f:text;
procedure creare(var pr,ul:lista);
var el_nou:lista; k:integer;
begin
assign(f.’date.in); reset (f);
pr:=nil;
while not seekof(f) do begin
read(f,k);
if k mod 2=0 then begin
new (el_nou);
el_nou^.inf:=k;
if pr=nil then begin
{lista vida - se crează primul nod}
pr:=el_nou ;
end
else
begin
{noul element se adaugă la sfarsit}
el_nou^.pred:=ul;
ul^.urm:=el_nou
ul:=el_nou;
end;
end;
end;
pr^.pred:=nil; ul^.urm:=nil;
close (f);
end;
procedure afisare(pr:listă);
begin
while pr<>nil do begin
writeln(pr^.inf);
pr:=pr^.urm;
end;
end;
begin {main}
creare(pr,ul);
afisare
end.

Operaţii în liste dublu înlănţuite


A.Căutarea unui element de cheie k
Pentru căutarea unui element se parcurge listă prin intermediul unui pointer p. cat timp nu a
fost găsita valoarea k şi listă nu este vidă.In momentul când se găseste elementul ce îndeplineste
condiţia, se reţine adresa acestuia.Iniţial p adresează primul nod al listei.
Exemplu:
Funcţia caut descrisă mai jos verifică dacă o valoare k se află printre elementele unei listă
liniare dublu înlăntuită.Functia va returna adresa elementului de cheie k sau valoarea NIL când
valoarea k nu se află în lista.

function caut(pr:lista; k:integer):lista;


var p:lista;
begin
p:=pr;
while (p<>nil) and (p^.inf<>k) do
p:=p^.urm;
caut:=p;
end;

B.Inserarea înaintea primului element


> Se alocă memorie unui nou element: new(el_nou);
> Se înitializează campul de informatie utilă: readln(el_nou^.inf);
> Legătura cu anteriorul este NIL: el_nou^.pred:=NIL;
> Legătura cu elementul anterior va fi primul nod: el_nod^.urm:=pr;
> Legătura pred a primului nod trebuie să adreseze nodul creat:pr^.pred:=el_nou;
> Acum nodul creat devine primul element: pr:=el_nou;

procedure inser_inainte_prim(var pr:lista);


var el_nou:lista;
begin
new(el_nou);
readln(el_nou^.inf);
el_nou^.pred:=nil;
el_nou^.urm:=pr;
pr^.pred:=el_nou;
pr:=el_nou;
end;
C.Inserarea înaintea elementelor de cheie k
Trebuie analizat cazul particular de inserare înaintea primului element, siţuatie în care se
modifică adresa primului element.Dacă elementul de cheie k este primul element atunci vom
realiza inserarea înaintea primului element.In caz contrar procedăm astfel:
 Determinăm adresa elementului de cheie k: p:=caut(pr,k);
 Se aloca memorie unui element: new(el_nou);
 Se îniţiălizează campul de informaţie utilă: readln(el_nou^.inf);
 Legătura următoare va trebui să adreseze elementulu de cheie k: el_nou^.urm:=p;
 Legătura anterioară va adresa nodul anterior nodului de cheie k:
el_nou^.pred:=p^.pred
 Se stabileste legătura dintre nodul anterior nodului de cheie k şi nodul creat:
p^.pred^.urm:=el_nou;
 Se stabileste legătura dintre nodul de cheie k şi nodul creat: p^.pred:=el_nou;

procedure inser_inainte(var pr:lista; k:integer);


var p,el_nou:lista;
begin
p:=caut(pr,k);
if p<>nil then
if p^.pred=nil then {se adaugă înaintea primului element}
inser_inainte_prim(pr)
else begin {element interior}
new(el_nou^.inf);
readln(el_nou^.inf);
el_nou^.urm:=p;
el_nou^.pred:=p^.pred;
p^.pred^.urm:=el_nou;
p^.pred:=el_nou;
end;
end;
D.Inserarea după elementul de cheie k
Trebuie să verificăm dacă nodul adaugat se insereaza după ultimul nod, situaţie în care în
urma inserarii se modifica adresa ultimului nod.In cazul în care elementul de cheie k este ultimul
nod, se adauga elementul la sfarsitul listei, în caz contrar(elementul este interior) se procedeaza
astfel:
> Determinam adresa elementului de cheie k: p:=caut(pr,k);
> Se aloca memorie unui nou element: new(el_nou);
> Se iniţializeaza campul de informaţie utila: readln(el_nou^.inf);
> Legatura urmatoare va trebui să adreseze nodul urmator nodului de cheie k:
el_nou^.urm:=p^.urm;
> Legatura anterioara va adresa nodul cheie k: el_nou^.pred:=p
> Se stabileste legatura dintre nodul de cheie k şi nodul creat:
p^.urm^.pred:=el_nou;
> Se stabileste legatura dintre nodul de cheie k şi nodul creat: p^.urm:=el_nou;

procedure inser_dupa(pr:lista; var ul:lista; k:integer);


var p,el_nou:lista;
begin
p:=caut(pr,k);
if p^.urm=nil then inser_dupa_ultimul(ul) {se adauga după ultimul element}
else begin {element interior}
new(el_nou); readln(el_nou^.inf);
el_nou^.urm:=p^.urm;
el_nou^.pred:=p;
p^.urm^.pred:=el_nou;
p^.urm:=el_nou;
end;
end;
E.Eliminarea primului element
> Se salveaza adresa primului nod în pointerul p: p:=pr;
> Se stabileste primul element: pr:=p^.urm;
> Legatura anterioara a nodului ce a devenit primul element devine NIL:pr^.pred:=nil;
> Se sterge fizic nodul care initial era primului element: dispose(p);

procedure elimin_prim(var pr:lista);


var p:lista;
begin
if pr<>nil then begin
p:=pr;
pr:=p^.urm;
pr^.pred:=nil;
dispose(p);
end;
if pr=nil then ul:=nil;
end;

F.Eliminarea ultimului element


> Se salveaza adresa primului nod în poainterul p: p:=pr;
> Se stabileste primul element: pr:=p^.urm;
> Legatura anterioara a nodului ce a devenit primul element devine NIL: pr^.pred:=nil

procedure elimin_prim(var pr:lista);


var p:lista;
begin
if pr<>nil then begin
p:=pr;
pr:=p^.urm;
pr^.pred:=nil;
dispose(p);
end;
if pr=nil then ul:=nil;
end;

F.Eliminarea ultimului element


> Se salveaza adresa ultimului nod în pointerul p: p:=ul;
> Se stabileste ultimul element: ul:p^.pred
> Legatura urmatoare a nodului ce a devenit ultimul element devine NIL:ul^.urm:=nil;
> Se sterge fizic nodul care iniţial era primul element: dispose(p);

procedure elimin_ultim(var ul:lista);


var p:lista;
begin
if ul<>nil then begin
p:=ul; ul:=p^/pred;
ul^.urm:=nil;
dispose(p);
end;
if ul=nil then pr:=nil;
end;

G.Eliminarea elementului de cheie k


În aceasta situaţie trebuie verificatre cazurile particulare în care nodul de cheie k este primul
respectiv ultimul element.In cazul în care elementul este interior(nici primul nici ultimul) se
procedeaza astfel:
> Ne poziţionam pe elementul de cheie k salvand adresa acestuia în pointerul p: p=caut(pr,k);
> Se stabileste legatura dintre nodul predecesor nodului de cheie k şi nodul urmator
p^.pred^.urm:=p^.urm
> Se stabileste legatura dintre nodul urmator nodului de cheie k şi nodul predecesor:
p^.urm^.pred:=p^.pred
> Se elimina fizic nodul referit de p:dispose(p);
procedure elimin_el_k(pr:lista;k:integer);
var p:lista;
begin
p:=caut(pr,k_;
if p<>nil then begin
p^.pred^.urm:=p^.urm;
p^.urm^.pred:=p.pred;
dispose(p);
end else writeln(‘nu exista cheia k în lista’);
end;
Aplicatii rezolvate
1) Se dă fisierul Numar.in ce conţine numere întregi .Să se creeze o listă dublu înlantuita ce
conţine numerele pozitive din fisier.
Mod de rezolvare: Se parcurge fisierul citind fiecare număr.Dacă numărul este pozitiv şi
listă nu este vida va fi adaugat în listă la sfarsit,Dacă listă este vida se va crea primul element
ce cincide în aceasta situatie cu ultimul element.Este necesar ca la început pointerul ce
adresează primul element să fie initializat cu NIL.

type lista=^.nod; ul^.urm:=nil;


nod:=record end;
inf:integer; procedure afis1(pr:lista);
pred,urm:lista; var p:lista;
end; begin
var pr,ul:lista; f:text; p:=pr;
procedure creare(var pr,ul:lista); while p<>nil do begin
var p:lista; k:integer; write(p.inf,’ ‘);
begin p:=p^.urm;
assign(f,’numar.in’);reset(f); end;
pr:=nil; writeln;
while nod seekof(f) do begin end;
read(f,k); procedure afis2(ul:lista);
if k>=0 then begin begin
new(p);p^.inf:=k; while ul<>nil do begin
if pr:=p; ul:=p; write(ul^.inf,’ ‘_;
end; ul:=ul^.pred;
else begin end;
p^.pred:=ul; ul^.urm:=p; writeln;
ul:=p; end;
end; begin
end; creare(pr,ul);
end; afis1(pr);
pr^.pred:=nil; afis2(ul);
end.
Bibliografie:
Metode de progrãmare , structuri dinamice de date şi grafuri - Eugen Popescu, Sofia
Viţelaru, Marius Nicoli, Mihaela Codres, Mihaela Grindeanu, Ecaterina Boarnă (Colectia
informatica NR. 9)