Documente Academic
Documente Profesional
Documente Cultură
Liste
numar (100)
adr_urm (110..10)
Variabila st este o variabil de tip referin. Ea reine adrese de nregistrri. La rndul ei, o nregistrare are dou cmpuri: numr care reine un numr ntreg (informaia util) ; i adr_urm care reprezint adresa unei alte nregistrri (de obicei adresa urmtoarei nregistrri). Astfel o nregistrare conine att informaie util ct i adrese ale altor nregistrri. Pentru a se rezerva spaiu pentru o nregistrare se folosete funcia new.
list = new Lista_numere;
Practic atunci cnd avem nevoie de o nou variabil, vom aloca spaiu pentru ea. Nu este necesar s avem declarate *list1, *list2 *listn pentru fiecare variabil de care avem nevoie, deoarece avem posibilitatea ca fiecare nregistrare s rein adresa unei alte nregistrri. Dac am avea o lista de 5 variabile, practic este necesar doar reinerea primei adrese deoarece adresa variabilei 2 o reinem n adr_urm din prima variabil, adresa variabilei 3 o reinem n adr_urm din cea de-a doua variabil etc. Atunci cnd nu ne mai este necesar o variabil, ea se terge (se elibereaz memoria rezervat pentru ea) folosind funcia delete.
delete list;
Observaii: list se refer la adresa la care se gsete variabila list list>numar se refer la cmpul numeric (informaia util) care are informaia memorat n variabila list list>adr_urm se refer la adresa unei alte nregistrri list>adr_urm>numar semnific variabila numar care se gsete n nregistrarea care are adresa adr_urm al nregistrrii cu adresa list.
.
adr n
nrn
NULL
Semnificaia notaiilor folosite este urmtoarea: adr1, adr2, . adrn reprezint adresele de memorie ale celor n nregistrri adr_urm2, adr_urm3, adr_urmn reprezint cmpurile din nregistrrile st, n care se reine adresa urmtoarei nregistrri. Practic adr_urm2 = adr2 ; adr_urm3 = adr3 ; . ; adr_urmn = adrn NULL semnific faptul c n cmpul respectiv nu exist nici o adres, deci dup aceast nregistrare nu mai exist nici o alta Exemplu de aezare n memoria calculatorului a unei liste: Pentru cazul nostru avem: adr1 = 15 (poziia la care se gsete primul octet din nregistrare: cmpul numar. De exemplu 100) adr_urm2 = adr2 = 43 (poziia n memorie a .. urmtoarei variabile) adrn = 362 La poziia 363 se gsete valoarea NULL Observm c spaiul alocat pentru aceste nregistrri nu este consecutiv. El este alocat acolo unde se gsete memorie liber, neocupat cu alte date. Denumirea de simplu nlnuit provine de la faptul c fiecare element al listei conine o singur adres, i anume adresa urmtorului element din list. 2
Operaiile pe care le putem face cu aceast structur de date sunt urmtoarele: creare, listare, adugare, tergere. Crearea listei Se va cere numrul n de nregistrri. Se creeaz o prim nregistrare avnd ca informaie util nr.1 Variabila prim, va reine adresa primei nregistrri din list. Pentru fiecare i cuprins ntre 2 i n se adaug cte o nou nregistrare listei. Variabila ultim reine adresa ultimei nregistrri din list, pentru a-i completa cmpul adres. Se procedeaz astfel deoarece atunci cnd am creat o nregistrare, nu se cunoate adresa nregistrrii care urmeaz.
void function creare() { int i; Lista_numere *temp; prim = new Lista_numere; //se aloc spaiu pentru prima nregistrare prim->numar = 1; prim->adr_urm = NULL; //iniial dup prima nregistrare nu mai urmeaz nici o alt nregistrare. Ea este i prima i ultima ultim = prim; //se pstreaz n ultim ultima nregistrare din list for (i=2; i<=n; i++) { temp = new Lista_numere; //alocarea de spaiu pentru nregistrarea nr. i temp->numar = i; //reinerea informaiei utile (numrul propriuzis) temp->adr_urm = NULL; //aceasta nregistrare se adaug ultima, la sfritul listei ultim->adr_urm = temp; ultim = temp; //Acum s-a refcut legtura dintre vechea ultim nregistrare i nregistrarea nou creat. Variabila temp devine ultima nregistrare. iniial: nr 1 adr_urm2 nri-1 nri NULL . NULL prim dup refacerea legturii: nr 1 adr_urm2 . prim }//end for ultim temp
nri-1
adr_urmi-1
nri
NULL ultim
Listarea Am precizat faptul c prim reine adresa primei nregistrri. Pentru a nu deteriora aceast valoare, o vom memora n variabila temp. Ct timp nu am ajuns la sfritul listei, vom tipri informaia util i ncrcm n temp adresa nregistrrii urmtoare
void function Listare() { Lista_numere *temp; temp = prim; while (temp != NULL) //cat timp nu s-a ajuns la sfrit
Adugarea n list Se consider c dorim s adugm o nou nregistrare dup nregistrarea nr 2. Pentru aceasta va trebui s ne poziionm pe nregistrarea dup care dorim s facem adugarea, alocarea spaiului pentru noua nregistrare, completarea informaiei utile pentru ea, completarea adresei urmtoarei nregistrri dup cea nou creat care va fi adresa urmtoarei nregistrri dup nregistrarea pe care suntem poziionai, cmpul adres al nregistrrii pe care suntem poziionai va lua valoarea noii nregistrri. adr_urm3 nr 1 adr_urm2 nr2 nr3 adr_urm4 .
prim adr2 adr3 nrx nreg. nou adr_x adr_urmx nrx adr_x void function Adaugare( ) { int nr; Lista_numere *temp, *nou; scanf(%d, &nr); temp = prim; //ne vom poziiona pe cea de-a doua nregistrare (temp devin nregistrarea 2) temp = temp->adr_urm; //se aloca spaiu pentru noua nregistrare nou = new Lista_numere; nou->numar = nr; //se creeaz legtura verde (din desenul 2) care este de fapt fosta legtur ctre elementul 3 (legtura verde din desenul 1) nou->adr_urm = temp->adr_urm; //se creeaz i legtura roie temp->adr_urm = nou; } adr_urm3
nr 1 adr_urm2 prim
nr2 adr2
adr_urm4
nreg. nou
tergerea din list Pentru tergere se procedeaz n mod diferit dac se terge prima nregistrare sau una diferit de aceasta. Dac dorim s tergem prima nregistrare, se salveaz coninutul acesteia ntr-o variabil temp, variabila prim va deveni cea de-a doua nregistrare, se terge variabila temp.
Dac dorim s tergem o alt nregistrare dect prima, se face poziionarea pe nregistrarea care urmeaz a se terge, cmpul de adres al nregistrrii precedente capt valoarea cmpului de adres al nregistrrii curente, eliberm spaiul rezervat nregistrrii curente.
nr 1 adr_urm2 prim nr2 adr2 adr_urm3 nr3 adr_urm4 adr3 nr3 adr_urm5 adr4
nr 1 adr_urm2 prim
nr2 adr2
adr_urm4
nr3
adr_urm4 adr3
Observm c este necesar s reinem i nregistrarea dinaintea nregistrrii de ters pentru a-i putea modifica cmpul adres
void function Stergere(int nr) //primete ca parametru nregistrarea de ters { Lista_numere *temp, *parinte; int i; //cazul cnd se terge prima nregistrare if (i == 1) { temp = prim; prim = prim->adr_urm; delete temp; } //end if else { temp = prim; //ne poziionm pe nregistrarea numrul nr (cea care se terge). n variabila printe se retine nregistrarea anterioar celei care se terge. for (i=0; i<nr; i++) { parinte = temp; temp = temp->adr_urm; } //end for //crem legtura verde(din desenul 2) parinte->adr_urm = temp->adr_urm; delete temp; } //end else }
adr_spaten-1 adr n
nrn
NULL
Fiecare nregistrare va reine att adresa urmtoarei nregistrri, ct i adresa nregistrrii de dinaintea ei.
Operaiile uzuale care se pot face cu o list dublu nlnuit sunt: adugare la dreapta, adugare la stnga, tergere la stnga, tergere la dreapta, listare de la dreapta la stnga, listare de la stnga la dreapta. Structura unei nregistrri are urmtoarea form:
struct Lista_numere { int numar; Lista_numere *next_adr; Lista_numere *last_adr; } Lista_numere *list;
a) Crearea listei Se va cere numrul n de nregistrri. Se creeaz o prim nregistrare avnd ca informaie util nr.1 Variabila prim, va reine adresa primei nregistrri din list. Pentru fiecare i cuprins ntre 2 i n se adaug cte o nou nregistrare listei. Variabila ultim reine adresa ultimei nregistrri din list, pentru a-i completa cmpul adres.
void function creare() { int i; Lista_numere *temp; prim = new Lista_numere; //se aloc spaiu pentru prima nregistrare prim->numar = 1; prim->next_adr = NULL; prim->last_adr = NULL; //iniial dup prima nregistrare nu mai urmeaz nici o alt nregistrare. Ea este i prima i ultima ultim = prim; //se pstreaz n ultim ultima nregistrare din list for (i=2; i<=n; i++) { temp = new Lista_numere; //alocarea de spaiu pentru nregistrarea nr. i temp->numar = i; //reinerea informaiei utile (numrul propriuzis) temp->next_adr = NULL; //se creaz legtura dintre noua nregistrare si ultima (sgeata verde din desen) temp->last_adr = ultim; //aceasta nregistrare se adaug ultima, la sfritul listei, deci se face i legtura roie ultim->next_adr = temp; ultim = temp; //Acum s-a refcut legtura dintre vechea ultim nregistrare i nregistrarea nou creat. Variabila temp devine ultima nregistrare. iniial:
NULL nr 1 adr_urm2
prim
adr_spaten nr 2 ultim
NULL temp
nrn
NULL
NULL nr 1 adr_urm2
prim
adr_spaten-1 nr 2 adr_urmn
adr_spaten-1 ultim
nrn
NULL
}//end for }
In funcia de creare s-a implementat adugarea la stnga. Funciile de tergere i listare se fac analog ca la listarea simplu nlnuit, inndu-se cont de faptul c n cazul de fa trebuie s se fac actualizarea a dou legturi n loc de una singur. Existena a dou legturi are avantajul ca permite deplasarea n list att spre dreapta (temp = temp->next_adr), ct i spre stnga (temp = temp->last_adr). n felul acesta la tergere nu mai este nevoie s se rein printele, ci pur i simplu se scrie temp->last_adr.
Stiva
O stiv se definete ca o list liniar simplu nlnuit n care toate intrrile i ieirile se fac pe la un singur capt al ei. Ea este o structur tip adugare n stiv LIFO: last in, first aut (ultimul sosit, primul plecat) In acest caz nregistrarea de pe nivelul k reine nregistrarea de pe nivelul k-1. In cazul stivei se reine doar elementul din vrful stivei nr 5 adr_urm4 (elementul 5 din exemplul nostru). adr 5 De exemplu elementul 4 nu se poate extrage pn nu s-a extras elementul 5. De asemenea nu se poate insera nici un nr 4 adr_urm3 alt element ntre elementul 4 i 5, n mod direct. Dac totui adr 4 dorim s facem acest lucru va trebui s extragem elementul 5, s adugm elementul care dorim s l inserm, i abia nr 3 adr_urm2 apoi s adugm din nou elementul 5. adr 3 Operaia de adugare n list se numete PUSH, iar cea de extragere POP.
Parcurgerea stivei: de la ultimul element )(din vrf), ctre primul (ctre baz
adr 2
nr 1
nr 2 adr_urm1
NULL
Adugarea i extragerea din stiv Elementul vrf semnific ultimul element din list (n exemplul nostru elementul cu adresa 5).
adr1
void function Push( ) { Lista_numere *temp; int nr; temp = new Lista_numere; //ce se face aici? scanf(%d,&nr); //se citeste numarul care se adaug //se va crea legtura cu elementul vrf (dup elementul inserat, n stiv va urma vrful temp->adr_urm = varf; // temp va deveni noul vrf al stivei varf = temp; } void function Pop ( ) { Lista_numere *temp; temp = vrf->next; delete vrf; varf = temp;
Probleme propuse
1. S se realizeze o list simplu nlnuit, unde funciile de creare, adugare, listare i tergere s fie implementate recursiv. 2. S se implementeze pentru lista dublu nlnuite operaiile de adugare(stnga, dreapta), tergere i listare 3. S se implementeze o list circular, dublu nlnuit. O list se numete circular, dac ultima nregistrare va avea o legtur spre prima, iar prima spre ultima, ca n figura:
adr_spat next_adr nr1 en 2
ne xt_ n ad r r 2
e
4
ad r _s pa t
5
nex t_a d
adr5
rn a r dr _ sp 4 e at
3
adr4
4. Scriei un program care s implementeze o stiv dublu nlnuit 5. S se scrie un program care sorteaz elementele dintr-o stiv, prin una din metodele nvate, folosind ca structur intermediar o list dublu nlnuit 6. Se consider o structur liniar simplu nlnuit la care toate intrrile se fac la captul din stnga, iar ieirile prin captul din dreapta. O astfel de structur se numete coad. Ea este de tipul FIFO (first in, first out)
intrri n coad
nr 1 adr_urm2 adr1
nr 2 adr_urm3 adr2
ne xt_ r d anr
3 2
adr1
r ad _s t pa e1
adr2
nrn adr n