Sunteți pe pagina 1din 27

MINISTERUL EDUCAIEI I CERCETRII

CUPRINS

Introducere in liste...................................................................................................... 3 Liste Duble.................................................................................................................. 6 Structura listei......................................................................................................... 6 Operatii cu liste duble............................................................................................. 8 Cautare element.................................................................................................... 12 Stergere element................................................................................................... 14 Aplicatii..................................................................................................................... 18 Reinei coordonatele unui poligon i calculai perimetrul acestuia......................18 Concatenarea a dou liste duble...........................................................................20 Se citesc mai multe numere memorate ntr-o list dubla.Sfritul listei este marcat prin citirea unei valori egal cu suma ultimelor dou numere introduse.S se realizeze un subprogram recursiv pentru afiarea elementelor n ordinea invers introducerii................................................................................................ 23 BIBLIOGRAFIE........................................................................................................... 27

Introducere in liste

Lista este o structura dinamica, situata in memoria centrala, in care toate elementele sunt de acelasi tip; numarul de elemente este variabil, chiar nul. De remarcat diferentele fata de definitia tabloului: tabloul este o structura statica, situata in memoria centrala, in care toate elementele sunt de acelasi tip; numarul de elemente este constant. O alta definire a listei este: O lista L este o secventa de zero sau mai multe elemente, numite noduri, toate fiind de acelasi tip de baza T. L=a1,a2,...,an (n>=0) Daca n>=1, a1 se spune ca este primul nod al listei, iar an, ultimul nod. Daca n=0, lista este vida. Numarul de noduri se numeste lungimea listei. Un nod al listei liniare care apare ca o structura recursiva, avand o componenta de tip pointer la structura, reprezentand legatura ( inlantuirea ) spre nodul urmator. Lista in care fiecare nod are o sinfura inlantuire se numeste lista simplu inlantuita. struct nod{ TipCheie cheie; TipInfo info; struct Nod* urmator; }; struct nod* inceput; //pentru o scriere mai compacta se pot defini tipurile: typedef struct nod Nod, *pNod; pNod inceput; Caracteristica unei astfel de structuri consta in prezenta unei singure inlantuiri. Campul cheieserveste la identificarea nodului, campul urmatore pointer de inlantuire la nodul urmator, iar cel infocontine informatia utila.
3

Variabila inceputindica spre primul nod al listei. In unele situatii in locul lui inceputse utilizeaza un nod fictiv, adica o variabila de tip struct Nod cu campurile cheie si info neprecizate, dar campul urmatorindicand spre primul nod al listei. De asemenea uneori este util a se pastra pointerul spre ultimul nod al listei. O varianta este a listelor circulare la care dispare notiunea de prim, ultim nod, lista fiind un pointer ce se plimba pe lista. Tehnici de insertie a nodurilor

Insertia unui nod la inceputul listei

Daca inceputeste variabila pointer ce indica spre primul nod al listei, iarqo variabila auxiliara de tip pointer, secventa urmatoare realizeaza insertia la inceputul listei si actualizeaza pointerulinceput: pNod inceput, q; q=(pNod)malloc(sizeof(Nod)); //creaza spatiu pentru un nou nod q->urmator=inceput; //asignarea campurilor cheie si info inceput=q; Secventa este corecta si pentru insertia intr-o lista vida, caz in care valoarea lui inceput esteNULL.

Insertia unui nod la sfarsitul listei

Devine mai simpla daca se pastreaza o variabilasfarsit indicand spre ultimul nod al listei: pNod inceput, sfarsit, q; q=(pNod)malloc(sizeof(Nod)); //creaza spatiu pentru nou nod ultim sfarsit->urmator=q; q->urmator=NULL; //asignarea campurilor cheie si info sfarsit=q; Pentru insertia la sfarsitul listei este necesara existenta a cel putin unui nod, care se creaza prin secventa de la paragraful anterior.

Insertia unui nod dupa unul indicat


4

Este simpla pentru ca se cunoaste pointerul spre nodul anterior si spre cel urmator celui care se insereaza (pointerul spre nodul urmator este valoarea campului urmator al nodului indicat). Insertia unui nod in fata unui nod indicat Printr-un artificiu, se reduce acest caz la cel anterior: se insereaza un nod dupa cel indicat, cheia si informatia din nodul indicat fiind atribuite noului nod inserat si fiind inlocuite cu valorile nodului care trebuia inserat. Tehnici de suprimare a nodurilor Pentru suprimarea nodului urmator celui indicat de o variabila pointerq, prin atribuirea: q->urmator=q->urmator->urmator; se exclud din lista legaturile la si de la nodul de suprimat. Pentru suprimarea nodului anterior unuia precizat, se aduce nodul precizat in cel de suprimat. Apoi se suprima succesorul lui, deci cel indicat initial de variabila pointer q: *q=*q->urmator; /* pentru expresia din dreapta, operatorul de selectie indirecta -> este mai prioritar decat cel de indirectare *, deci nu sunt necesare parantezele */ Traversarea unei liste Daca nodul de inceput al listei este indicat de variabila inceput, o variabila auxiliara q, care parcurge toate nodurile listei pana cand valoarea ei devine NULL, permite accesul la fiecare nod si efectuarea operatiei specifice traversarii: for(q=inceput;q!=NULL;q=q->urmator) //prelucrarea nodului indicat de q Daca lista are doua noduri fictive, unul de inceput si unul de sfarsit, secventa de traversare devine: for(q=inceput->urmator;q!=sfarsit;q=q->urmator) //prelucrarea nodului indicat de q

Liste Duble
Listele dublu inlantuite sunt structuri de date dinamice omogene. Ele au aceleasi caracteristici de baza ca si listele simplu inlantuite. Diferenta fata de acestea consta in faptul ca, pentru fiecare nod, se retine si adresa elementului anterior, ceea ce permite traversarea listei in ambele directii.

Lista dublu inlantuita poate fi reprezentata grafic astfel:

Structura listei
Structura folosita este similara cu cea de la liste simple. Pentru a asigura un grad mai mare de generalitate listei a fost creat un alias pentru datele utile (in cazul nostru un intreg):

// Datele asociate unui // element dintr-o lista typedef int Date;

In cazul in care se doreste memorarea unui alt tip de date, trebuie schimbata doar declaratia aliasului Date.
6

Pentru memorarea listei se foloseste o structura autoreferita. Acesta structura va avea forma:

// Structura unui element // dintr-o lista dublu inlantuita struct Element { // datele efective memorate Date valoare; // legatura catre nodul urmator Element* urmator, * anterior; };

In cazul in care elemenul este ultimul din lista, pointerul urmator va avea valoarea NULL. Pentru primul element, pointerul anterior va avea valoarea NULL. Declararea listei se face sub forma: // declarare lista vida Element* cap = NULL In cazul in care se doreste crearea unei liste circulare, pointerul urmator al ultimului element va referi primul element al listei, iar pointerul anterior al primului element va referi ultimul element.

Operatii cu liste duble


Principalele operatii cu liste sunt: Parcurgere si afisare lista Lista este parcursa pornind de la pointerul spre primul element si avansand folosind pointerii din structura pana la sfarsitul listei (pointer NULL). // Parcurgere si afisare lista dubla void Afisare(Element* cap) { // cat timp mai avem elemente // in lista while (cap != NULL) { // afiseaza elementul curent cout << cap->valoare << endl;

// avanseaza la elementul urmator cap = cap->urmator; } } Pentru parcurgerea inversa a listei se va porni cu un pointer catre ultimul element al listei, iar avansarea se va face folosind secventa cap = cap->anterior; .

Inserare element Inserarea unui element se poate face la inceputul sau la sfarsitul listei. a) Inserare la inceput Acesta este cazul cel mai simplu: trebuie doar alocat elementul, legat de primul element din lista si repozitionarea capului listei: // Inserare element la inceputul unei // liste dublu inlantuite void InserareInceput(Element* &cap, Date val) { // Alocare nod si initializare valoare Element *elem = new Element; elem->valoare = val; elem->anterior = NULL;

// legare nod in lista elem->urmator = cap; if (cap != NULL) cap->anterior = elem;

// mutarea capului listei cap = elem; }


9

b) Inserare la sfarsitul listei In acest caz trebuie intai parcursa lista si dupa aceea adaugat elementul si legat de restul listei. De asemenea, trebuie avut in vedere cazul in care lista este vida. // Inserare element la sfarsitul unei // liste dublu inlantuite void InserareSfarsit(Element* &cap, Date val) { // Alocare si initializare nod Element *elem = new Element; elem->valoare = val; elem->urmator = NULL; elem->anterior = NULL;

// daca avem lista vida if (cap == NULL) // doar modificam capul listei cap = elem; else { // parcurgem lista pana la ultimul nod Element *nod = cap;
10

while (nod->urmator != NULL) nod = nod->urmator; // adaugam elementul nou in lista nod->urmator = elem; elem->anterior = nod; } }

c) inserare dupa un element dat void InserareInterior(Element* &cap, Element* p, Date val) { // Alocare si initializare nod Element *elem = new Element; elem->valoare = val; elem->urmator = NULL; elem->anterior = NULL;

// lista vida if (cap == NULL) { cap = elem;

11

return; } // inserare la inceputul listei if (cap == p) { elem->urmator = cap; cap->anterior = elem; cap = elem; return; } // inserare in interior elem->urmator = p->urmator; elem->anterior = p; p->urmator->anterior = elem; p->urmator = elem;

Cautare element
Cautarea unui element dintr-o lista presupune parcurgerea listei pentru identificarea nodului in functie de un criteriu. Cele mai uzuale criterii sunt cele legate de pozitia in cadrul listei si de informatiile utile continute de nod. Rezultatul operatiei este adresa primului element gasit sau NULL.

12

a) Cautarea dupa pozitie Se avanseaza pointerul cu numarul de pozitii specificat: // Cautare element dupa pozitie Element* CautarePozitie(Element* cap, int pozitie) { int i = 0; // pozitia curenta

// parcurge lista pana la // pozitia ceruta sau pana la // sfarsitul listei while (cap != NULL && i < pozitie) { cap = cap->urmator; i++; }

// daca lista contine elementul if (i == pozitie) return cap; else return NULL;

13

b) Cautarea dupa valoare

Se parcurge lista pana la epuizarea acesteia sau identificarea elementului:

// Cautare element dupa valoare Element* CautareValoare(Element* cap, Date val) { // parcurge lista pana la gasirea // elementului sau epuizarea listei while (cap != NULL && cap->valoare != val) cap = cap->urmator;

return cap; }

Stergere element
a) Stergerea unui element din interiorul listei (diferit de capul listei)

14

// sterge un element din interiorul listei // primind ca parametru adresa elementului void StergereElementInterior(Element* elem) { // scurcircuitam elementul elem->anterior->urmator = elem->urmator; elem->urmator->anterior = elem->anterior;

// si il stergem delete elem; }

b) Stergerea unui element de pe o anumita pozitie

Daca elementul este primul din lista, atunci se modifica capul listei, altfel se cauta elementul si se sterge folosind functia definita anterior:

void StergerePozitie(Element* &cap, int pozitie) { // daca lista e vida nu facem nimic if (cap == NULL) return;
15

// daca este primul element, atunci // il stergem si mutam capul if (pozitie == 0) { Element* deSters = cap; cap = cap->urmator; cap->anterior = NULL; delete deSters; return; }

// daca este in interor, atunci folosim // functia de stergere Element* elem = CautarePozitie(cap, pozitie); StergereElementInterior(elem); }

c) stergerea dupa o valoare

Se cauta elementul si se foloseste functia de stergere element:

16

void StergereValoare(Element* &cap, Date val) { // daca lista e vida nu facem nimic if (cap == NULL) return;

// daca este primul element, atunci // il stergem si mutam capul if (cap->valoare == val) { Element* deSters = cap; cap = cap->urmator; cap->anterior = NULL;

delete deSters; return; }

// cautam elementul Element* elem = CautareValoare(cap, val);

17

// daca a fost gasit, atunci il stergem if (elem->urmator != NULL) StergereElementInterior(elem); }

Aplicatii
Reinei coordonatele unui poligon i calculai perimetrul acestuia
#include<stdio.h> #include<conio.h> #include<alloc.h> #include<math.h> struct nod { int x,y; struct nod *next; }*l,*q; int n,i; float p; struct nod* creare() { struct nod* aux;int x,y; l=NULL;
18

for(i=n;i>=1;i--) { aux= (struct nod* )malloc(sizeof(struct nod)); printf("coordonatele vfului %d",i); printf("x=" ); scanf("%d",&x); printf("y=" ); scanf("%d",&y); aux->x=x; aux->y=y; aux->next=l; if (i==n) q=aux; l=aux; } q->next=l; return l; } void afisare() { struct nod* c; c=l; printf("(%d,%d)",c->x,c->y); c=l->next; while(c!=l) { printf("(%d,%d)",c->x,c->y); c=c->next; } } void perimetru()
19

{ struct nod*c; c=l; p=0; for(i=1;i<=n;i++) { p+=pow(pow(c->x-c->next->x,2)+pow(c->y-c->next->y,2),0.5); c=c->next; } } void main(void) { clrscr(); printf("nr de varfuri este " ); scanf("%d",&n); l=creare(); afisare(); perimetru(); printf("p=%f",p); getch(); }

Concatenarea a dou liste duble


#include <conio.h> #include <stdio.h> #include <alloc.h> struct nod
20

{ int x; struct nod *next; }*l,*l1,*u,*u1,*ultim; int i,n; struct nod* creare(struct nod *l, int k) {struct nod*aux; int v; printf("nr de noduri=" ); scanf("%d",&n); l=NULL; ultim=NULL; for (i=n;i>=1;i--) { aux= (struct nod*)malloc(sizeof(struct nod)); printf("\nInfo. nodului %d = ",i); scanf("%d",&v); aux->x=v; aux->next=l; if (i==n) ultim=aux; l=aux; } u->next=l; if(k==0) u=ultim;
21

else u1=ultim; return l; } void afisare(struct nod*l) { struct nod*c; c=l; printf("\n" ); printf("%d ",l->x); c=l->next; while (c!=l) { printf("%d ",c->x); c=c->next; } } struct nod* concat(struct nod* l,struct nod* l1) { struct nod* c,*aux; u->next=l1; u1->next=l; return l; } void main() { clrscr();
22

l=creare(l,0); afisare(l); l1=creare(l1,1); afisare(l1); printf("\nListele concatenate\n" ); l=concat(l,l1); afisare(l); getch(); }

Se citesc mai multe numere memorate ntr-o list dubla.Sfritul listei este marcat prin citirea unei valori egal cu suma ultimelor dou numere introduse.S se realizeze un subprogram recursiv pentru afiarea elementelor n ordinea invers introducerii
#include <conio.h> #include <stdio.h> #include <alloc.h> struct nod { int x;
23

struct nod *next; }*l,*q,*linv,*qinv; int i,n,start,stop; struct nod* insert(int x){ struct nod*aux; aux= (struct nod*) malloc (sizeof(struct nod)); aux->x=x; aux->next=l; if (start) q=aux; l=aux; return l; } struct nod* creare() { int v1,v2,v3; l=NULL;start=1; printf("Info.= " ); scanf("%d",&v1); l=insert(v1); start=0; stop=0; printf("Info.= ") ; scanf("%d",&v2); l=insert(v2);
24

printf("Info.= " ); scanf("%d",&v3); while(stop==0){ if(v3==v1+v2) stop=1; l=insert(v3); v1=v2; v2=v3; printf("Info.= " ); scanf("%d",&v3); } q->next=l; return l; } void afisare(struct nod*l) { struct nod*c; c=l; printf("%d ",c->x); c=l->next; while (c!=l) { printf("%d ",c->x); c=c->next; } printf("\n" );
25

} struct nod* inversa(struct nod* l) { struct nod*aux,*q,*c; int v; if(l==NULL) linv=NULL; else{ linv=insert(l->x); qinv=linv; for(c=l->next;c!=l;c=c->next) linv=insert(c->x); qinv->next=linv; } return linv; } void main() { l=creare(); afisare(l); linv=inversa(l); afisare(linv); getch(); }

26

BIBLIOGRAFIE
Manual informatic clasa a XI-a.Editura LS Soft.Autori: Vlad Huanu, Tudor Sorin; Programarea modern n C++.Editura Teora.Autor: Andrei Alexandrescu; http://www.cs.uregina.ca/Dept/manuals/Manuals/7Language/ 7_18C++/c++.htm Secrete de programare in Windows 98.Editura ZY.Autor: Clayton Walnum; file://localhost/D:/download/Liste%20dublu%20inlantuite, %20liste%20circulare.htm http://www.skullbox.info/board/-curs-c-lectia-12-listep31092.html http://cppcorner.3x.ro/circularlist.html

27