Documente Academic
Documente Profesional
Documente Cultură
OBS:
Modul in care datele sunt organizate poate sa rezolve o buna parte din problema.
SD liniare - o structura de date e liniara daca elementele sale sunt organizate secvential (un
element poate sa aiba maxim 2 vecini: elementul urmator si elementul anterior). Usor de
implementat in memorie. Traversarea structurii se face liniar.
SD neprimitive SD primitive
Structuri de date
Liniare
integer
Neliniare Liniare
float
Arbori Liste inlantuite Liste neinlantuite
char
Grafuri Vector
Dublu Simplu Circulara pointer
Stiva
Coada
Simplu
Dublu Dublu
Simplu Circulara
Structuri de date
Observatie: Orice tip de date are un anumit domeniu (set de valori) si un anumit set de operatii
posibile. (Ex: pentru tipul boolean – valorile sunt true si false si setul de operatii include AND,
OR, NOT; in timp ce, pentru int valorile sunt in: -32,768 -> 32,767, iar operatiile includ +,-, *,/).
Creare – operatia de declarare are ca efect alocarea de spatiu pentru o variabila/un obiect de
tipul SD
Selectare element – accesarea unui element din structura in functie de tipul SD ( ex: elementul
cel mai din varf al unei stive, un element dintr-un arbore folosind o cheie, elementul cu indexul x
dintr-un tablou)
Cel mai simplu mod – dar nu neaparat cel mai eficient – este memorarea listei intr-un
vector. Succesiunea elementelor este astfel implicita (ordinea indicilor vectorului).
In cazul in care stuctura de date e dinamica (suporta frecvent operatii de inserare, stergere
a elementelor, redimensionare vector) aceasta implementare nu e eficienta.
In functie de numarul de legaturi intre elementele consecutive ale listei, ea poate sa fie
simplu sau dublu inlantuita (vom discuta doar primul caz, pentru moment).
Liste
• Listele simplu inlantuite sunt structuri de date dinamice, omogene.
• Adica, pentru accesarea listei trebuie cunoscuta adresa primului element (numit capul
listei/ inceputul listei); elementele urmatoare sunt accesate parcurgand lista (Ex: ca un
lift; ca sa ajung de la parter la etajul 3 trec prin P->1->2->3).
struct Elem
{
Data val; // info memorata
struct Elem* next;
//adresa elementului urmator
};
Crearea unei liste simplu inlantuite
struct Elem
Pentru a asigura un grad mai mare de generalitate listei, {
tipul datelor utile (in cazul de mai jos - int), va fi definit astfel: int
Data val; // info utila
struct Elem* next;
typedef int Data; //adresa elem. urmator
};
In cazul in care se doreste memorarea unui alt tip de date, trebuie schimbata doar
declaratia aliasului Data si verificat daca operatiile realizate pe un int in
implementarea functiilor (ex: =, ==) sunt valabile pentru noul tip de date stocat.
Daca nu se doreste definirea tipului de informatie stocat prin ceva de tip Data, se
foloseste direct numele tipului de date stocat.
Crearea unei liste simplu inlantuite
struct Elem
{
Data val; // datele efective memorate
struct Elem* next; // legatura catre nodul urmator (o adresa)
};
In cazul in care elementul este ultimul din lista, pointerul next va avea
valoarea NULL.
Ca sa nu scriu struct Elem mereu cand declar un nou element(in C), pot sa
numesc acest tip Node.
Node*n;
for (int i=0; i<5;i++){ //adaug alte noduri - la inceput
n= (Node*) malloc (sizeof(Node));
n->next=head; n->val=i+1;
head=n; //adresa de inceput a listei se tot modifica
} //ce ar trebui sa fac ca sa adaug la final?
#include <stdlib.h>
#include <stdio.h>
int main(){
int *p=NULL;
int n=6;
aloc(&p, n); // modific ce se gaseste in p (NULL)
for (int i=0; i<n;i++)
p[i]=n-i-1;
1. Care era complexitatea procedurii
for (int i=0; i<n;i++) de adaugare elemement pe pozitia
printf(“%d ”,p*i+); 0/ k /n-1/n?
return 0; 2. Ce se intampla daca nu avem destul
} spatiu in p?
Operatii cu liste
I. Inserare element - Inserarea unui element se poate face la inceputul, sfarsitul sau pe o
anumita pozitie a listei.
1. Inserare la inceput
Acesta este cazul cel mai simplu: trebuie doar alocat spatiul pentru element, legat de primul
element din lista si repozitionat capul listei:
//main
//main
//i=0; //i>0;
Operatii cu liste
3. Inserare pe o anumita pozitie (cazul general)
void addAtPos(Node**head,Data v, int pos) //pos=pozitia dupa care vreau sa adaug
{ if (*head!=NULL){ //daca lista nu e goala
Node*aux, *headcopy=*head;
Node* newNode=(Node*)malloc(sizeof(Node));//creez un nod nou
newNode->val=v; //stochez informatia data v
int p=0; //p e folosit la cautarea pozitiei pos in lista
} else addAtBeginning(&*head,v);
//daca lista era goala
}
//complexitate O(n);
int main(){
Node* head = NULL; //creez lista – e initial goala
for (int i=0;i<4;i++) addAtBeginning(&head,i); //adaug 4 elemente la inceputul ei
addAtPos(&head, 2, 100); //adauga pe pozitia 2 – elementul cu informatia 100
return 0;
//Tema: Implementati o functie care adauga nodul nou dupa un nod ce contine
}
Lista vs. Vector – inserare element
• Considerati un vector alocat dinamic (initial de dimensiune n).
*operatiile sunt posibile daca exista destul spatiu, altfel trebuie facuta o realocare (ceea ce
inseamna de cele mai multe ori copierea valorilor deja stocate = > O(n)).
Tema – Implementati!
Cat spatiu realoc? +1 sau *2 ?
Operatii cu liste
II. Parcurgerea listei
1. - cu afisarea datelor stocate in ordine
void print(Node*head){ //nu modific lista - > nu mai transmit head prin referinta
while (head!=NULL) //daca nu am ajuns la sfarsitul listei
{
printf( “ %d “ , head->val ); //afisaza informatia din acel nod
head=head->next; //si treci la urmatorul
}
}
//
int main(){
Node* head = NULL; //aceasta e lista – e initial goala
for (int i=0;i<4;i++) addAtBeginning(&head,i); //adaug 4 elemente la inceputul ei
print(head); //o parcurg si afisez continutul ei
return 0;
}
//Tema: Implementati o functie de parcurgere a listei din doua in doua elemente
Operatii cu liste
II. Parcurgerea listei
2. – recursiv de la final la inceput
void printR(Node*head){
if (head!=NULL) {
printR(head->next);
printf( “ %d “ , head->val );
}
//
int main(){
Node* head = NULL; //aceasta e lista – e initial goala
for (int i=0;i<4;i++) addAtBeginning(&head,i); //adaug 4 elemente la inceputul ei
printR(head); //o parcurg si afisez continutul ei de la final la inceput
return 0;
}
//Tema: Cum as putea sa afisez elementele in ordine- de la inceput la final folosind printR
//si ce am implementat pana acum?
//Mai folosesc o lista.
Operatii cu liste
III. Modificarea valorii elementului de pe o anumita pozitie
void modify(Node*head, Data newdata, int pos) //newdata – valoarea pe care vreau sa o
{ Node*aux=head; //stochez in nodul de pe pozita pos
int p=0;
while (head!=NULL && p<pos) {
aux=head;
head=head->next;
p++;
}
if (aux!=NULL) aux->val=newdata; //modific continutul elementului de pe pos
}
//complexitate O(n) – din cauza parcurgerii secventiale
//…->
Operatii cu liste
//…->
//stergerea unui element oarecare
Node *aux=*head;
while (headcopy!=NULL) {
if (headcopy->val!=val){ //trec prin lista pana gasesc elementul de sters
aux=headcopy;
headcopy=headcopy->next;
}else{
aux->next=headcopy->next;
free(headcopy); //sterg elementul cautat
return;
}
}
}
while (*head!=NULL){
//cat timp nu am ajuns la final sau lista nu e goala
headcopy=(*head)->next;
free(*head);
*head=headcopy;
}
*head=NULL;
}
//main
Node* head = NULL;
for (int i=0;i<4;i++) addAtBeginning(&head,i);
delete(&head,0); //sterg primul element
delete(&head,1); //sterg al doilea element din ce mai ramasase
deleteList(&head); //sterg toata lista
Concluzii
Lista vs. Vector
Hashmap (tabela de dispersie) – e o alternativa buna pentru stocarea de date (vector –>
indexat – de liste; indexarea in mare a datelor rezolva mare parte din problema accesarii
rapide a elementelor) – vom vedea in alt curs
Tema – Liste simplu inlantuite
1. Creati o lista direct in forma ordonata, datele (valori intregi) sunt citite de la tastatura.
Afisati-o!
2. Interclasati doua liste ce contin valori intregi ordonate (fara a pastra listele originale) si
afisati rezultatul.
3. Creati o functie pentru eliminarea elementelor care se repeta intr-o lista si afisati lista
rezultata.
4.* Polinoamele cu multi coeficienti nuli se numesc rare. Stocati informatiile utile pentru
un astfel de polinom sub forma de lista (ex: x^16+2x^5+8x). Calculati suma a doua polinoame
rare si afisati polinomul rezultat.
5. Scrieti o functie care determina cate elemente are o lista – se da adresa primului elem.
7. ** Pentru exemplul dat in curs - inlocuiti tipul Date din int cu:
Creare lista:
Node *head= (Node*)malloc(sizeof(Node));
head->next=NULL;
Initializare:
Node *head, *z= malloc(sizeof(Node));
head=z;
z->next=z;
Tema:
Implementati aceste
versiuni de liste,
inclusiv functiile de
creare /distrugere
lista.
Lista simplu inlantuita circulara
• Ultimul element din lista are ca nod urmator – primul element al listei
• Niciun element nu are nodul urmator NULL
• Pentru a identifica o lista circulara simplu inlantuita putem sa retinem adresa
oricarui element din lista
struct Elem
{
Data val; // datele efective memorate
struct Elem* next; // legatura catre nodul urmator
};
//definirea tipului se face la fel ca in cazul listei necirculare
Lista simplu inlantuita circulara
1. Inserare element dupa un anumit nod
void addAtPos(Node**head, int val, Node* pos) //pos - adresa nodului din lista dupa
//care se face inserarea; daca lista goala; pos este head
{
Node *headcopy=*head;
Node* newNode=(Node*)malloc(sizeof(Node));
newNode->val=val;
Node* headcopy=(*head)->next;
while (*head!=headcopy){
Node *aux=headcopy;
headcopy=headcopy->next;
free(aux);
free(*head);
*head=NULL;