SDA Lucrarea 3
În acest laborator se vor implementa secvențe cu vectori și liste simplu și dublu înlănțuite.
Secvența (lista abstractă - List)
Secvența este o structură de date abstractă care stochează datele sub forma unui șir de elemente de același fel.
Secvența are următoarele proprietăți:
- Datele sunt stocate într-o anumită ordine (se poate spune că un element este plasat înaintea sau după un alt element în structură).
- Numărul de elemente ce poate fi stocat de structură este nelimitat (a nu se confunda cu infinit, există întotdeauna limita dată de memoria disponibilă).
- Elementele stocate în secvență sunt de același fel.
Secvența suportă următoarele operații de bază:
- Interogarea numărului de elemente din secvență.
- Inserția unui element pe o anumită poziție în secvență.
- Ștergerea unui element de pe o anumită poziție din secvență.
- Căutarea unui element în secvență (căutare care va întoarce primul index pe care apare elementul în structură).
- Accesarea unui element de pe o anumită poziție.
- Dacă există o relație de ordine pe mulțimea din care fac parte elementele, se poate defini operația de sortare a secevenței care implică mutarea elementelor pe alte poziții, astfel încât un element considerat mai mic după relația de ordine folosită să fie plasat înaintea oricărui element considerat mai mare.
Implementarea secvenței cu vectori
În cazul implementării cu vectori, elementele sunt plasate într-un vector de dimensiune fixă și cunoscută. Din cauza faptului că secvența are dimensiune nelimitată, se cere ca vectorii să suporte redimensionarea dinamică a acestora pentru a acomoda elemente suplimentare în momentul când se umplu. Astfel, suntem obligați ca pentru implementarea secvențelor să folosim alocare dinamică de memorie, iar tipul de date care poate fi folosit pentru stocarea adreselor alocate este pointerul. Totuși cunoaștem din lecțiile anterioare faptul că o variabilă de tip pointer nu memorează decât o adresă de start a zonei de memorie alocată, nu și dimensiunea ei. Prin urmare vom defini o structură numită ArrayList
care va stoca adresa de start dar și dimensiunea zonei alocate. Mai jos este un exemplu de secvență de valori întregi pe 16 biți:
struct ArrayList {
short * array; // pointer la zona de memorie alocată
unsigned capacity; // dimensiunea zonei alocate
};
În plus față de câmpurile de mai sus, structura ArrayList
trebuie să memoreze și numărul de elemente valide din secvență. Motivul fiind acela că inițial, chiar dacă vectorul este alocat și are o capacitate ne-nulă, el nu conține de fapt nici un element. Astfel introducem un nou câmp: size
, care reprezintă numărul de elemente din secvență, și care este inițial 0:
struct ArrayList {
short * array; // pointer la zona de memorie alocată
unsigned capacity; // dimensiunea zonei alocate
unsigned size; // numarul de elemente valide din secventa
};
Crearea unui ArrayList
Pentru crearea unei secvențe noi, se definește următoarea funcție:
/**
* Functia aloca memorie si creeaza un nou ArrayList cu o capacitate initiala.
* @param initialCapacity capacitatea initiala a secventei.
* @return pointer la o structura de tip ArrayList.
*/
struct ArrayList * createArrayList(unsigned initialCapacity);
Implementarea acestei funcții se face folosind următorul algoritm:
- Se alocă memorie pentru o variabilă de tip
struct ArrayList
. - Se inițializează
capacity
cu valoarea dininitialCapacity
. - Se inițializează
size
cu 0. - Se alocă memorie pentru un vector de
initialCapacity
elemente iar adresa alocată se memorează înarray
. - Se întoarce adresa variabilei de tip
struct ArrayList
.
Interogarea dimensiunii
Pentru interogarea dimensiunii, se definește următoarea funcție:
/**
* Functia intoarce numarul de elemente valide din lista specificata.
* @param list lista pentru care se cere dimensinea.
* @return numarul de elemente valide din lista list.
*/
unsigned arrayListSize(struct ArrayList * list);
Implementarea acestei funcții se face întorcând direct valoarea câmpului size din structură.
Inserția
Pentru inserția unui element value pe o anumită poziție index se definește următoarea funcție:
/**
* Functia inseareaza elementul value pe pozitia index in vector. Daca capacitatea este insuficienta
* se face realocare. Se afiseaza un mesaj de eroare daca index-ul este mai mare decat size.
* @param list lista in care se face insertia.
* @param index index-ul pe care se va face insertia
* @param value valoarea ce trebuie inserata
*/
void arrayListInsert(struct ArrayList * list, unsigned index, short value);
Inserția unui element value pe o anumită poziție index într-o secvență implementată cu vectori, se face urmând următorul algoritm:
- Dacă index este mai mare decat size, se afișează un mesaj de eroare și funcția se încheie.
- Dacă size este egal cu capacity, se face realocare de memorie alocând un vector nou de 2 * capacity elemente. Acest lucru se realizează folosind funcția realloc.
- Lui capacity i se atribuie valoarea 2 * capacity.
- Se folosește funcția memmove pentru a muta elementele de la poziția index la size - 1 cu un element mai la dreapta.
- Se atribuie elementului de pe poziția index din vector valoarea value.
- size se incrementează cu 1.
Ștergerea
Pentru ștergerea unui element de pe o anumită poziție index se definește următoarea funcție:
/**
* Functia sterge elementul pe pozitia index in vector. Se afiseaza un mesaj de eroare
* daca index-ul este mai mare decat (size - 1).
* @param list lista din care se face stergerea.
* @param index index-ul de la care se va face stergerea
*/
void arrayListDelete(struct ArrayList * list, unsigned index);
Ștergerea unui element de pe o anumită poziție index dintr-o secvență implementată cu vectori, se face urmând următorul algoritm:
- Dacă index este mai mare decat size - 1, se afișează un mesaj de eroare și funcția se încheie.
- Se folosește funcția memmove pentru a muta elementele de la poziția index + 1 la size - 1 cu un element mai la stânga.
- size se decrementează cu 1.
Căutarea
Pentru căutarea unui element value într-o secvență neordonată se definește următoarea funcție:
/**
* Functia cauta elementul value in vector si intoarce prima pozitie pe care apare.
* Se intoarce -1 daca valoarea nu exista in vector.
* @param list lista in care se face cautarea.
* @param value valoarea care se cauta.
* @return index-ul la care apare valoarea sau -1 daca nu exista in vector.
*/
int arrayListSearch(struct ArrayList * list, short value);
Căutarea unui element value într-o secvență neordonată implementată cu vectori, se face urmând următorul algoritm:
- Se iterează cu o variabilă i de la 0 la size - 1.
- Dacă elementul de pe poziția i din vector este egal cu value, se întoarce valoarea lui i.
- Se întoarce valoarea -1.
Accesarea elementului de pe o anumită poziție
Pentru accesarea unui element de pe poziția index dintr-o secvență se definește următoarea funcție:
/**
* Functia intoarce elementul din vector de pe poziția index. Daca index este mai mare decat (size - 1) se afiseaza
* un mesaj de eroare (si se întoarce 0).
* @param list lista in care se face accesul.
* @param index pozitia de la care se doreste citirea elementului.
* @return valoarea de la pozitia index sau 0 daca index este mai mare decat (size - 1)
*/
short arrayListGet(struct ArrayList * list, unsigned index);
Accesarea unui element de pe poziția index dintr-o secvență neordonată implementată cu vectori, se face urmând următorul algoritm:
- Dacă index este mai mare decât (size - 1) se afișează un mesaj de eroare și se întoarce 0.
- Se întoarce valoarea de la index-ul index din vector.
Sortarea unei secvențe implementate cu vectori - Bubble Sort
Pentru sortarea unei secvențe se definește următoarea funcție:
/**
* Functia sorteaza crescator elementele din secventa list folosind algoritmul Bubble Sort.
* @param list lista care se doreste sortata.
*/
void arrayListBubbleSort(struct ArrayList * list);
Sortarea unei secvențe implementată cu vectori se face urmând următorul algoritm:
- Se declară o variabilă done.
- Se atribuie lui done valoarea 1.
- Se iterează cu un contor i de la 0 la (size - 2)
- Dacă elementul de pe poziția i din vector este mai mare decât elementul de pe poziția (i + 1), acestea se interschimbă și lui done i se atribuie valoarea 0.
- După terminarea iterării peste vector, dacă done e 0, se sare la pasul 2 (se folosește o buclă do-while).
Implementarea secvenței cu liste simplu și dublu înlănțuite
În curând...