This is an old revision of the document!
Laboratorul 7: Heap si tabele de dispersie
Obiective
În urma parcurgerii acestui laborator studentul va fi capabil:
1. Heap binar
Proprietați:
valoarea unui nod este mai mare (max heap)/mică (min heap) decât valorile tuturor copiilor săi
toate frunzele se găsesc pe nivelul h sau h-1, unde h este înălțimea arborelui
un heap binar este un arbore complet
Structura Heap:
- structura_heap.c
typedef struct
{
int *vec;
int size;
int capacity;
int type; // Tipul heap-ului, camp optional
}Heap;
Operații de bază:
1.1 Crearea unei structuri de tip Heap
- creare_heap.c
Heap* create(int capacitate)
{
Heap *h = (Heap *) malloc(sizeof(Heap));
if (h == NULL)
{
printf("Nu s-a putut aloca spatiu");
return;
}
h->size = 0; // Initial heap-ul este gol
h->capacity = capacitate;
h->vec = (int*) calloc(capacitate, sizeof(int));
if (h->vec == NULL)
{
printf("Nu s-a putut aloca spatiu");
return;
}
return h;
}
1.2 Popularea unui Heap
- populare_heap.c
void populateHeap(Heap *h, int *buf, int n)
{
if(h == NULL || buf == NULL || n ==0)
return;
while(n > h->capacity)
resize(h);
int i = 0;
for( i = 0; i < n; i++)
h->vec[i] = buf[i];
h->size = n;
for(i = (n-1)/2; i >= 0; i--)
heapify(h, i);
}
Etape:
se crează un heap cu o capacitate suficient de mare pentru stocarea elementelor
se mută elementele vectorului in spațiul de stocare al heap-ului
se aplică heapify pe toate nodurile interne
1.3 Adăugarea unui element
- adaugare_element.c
void insert(Heap *h, int x)
{
int i;
if(h->capacitate == h->size)
resize(h);
i = h->size;
h->size++;
while(i >= 0 && x > h->vec[parent(h,i)])
{
h->vec[i] = h->vec[parent(h,i)];
i = parent(h,i);
}
h->vec[i] = x;
}
Etape:
se verifică dacă avem suficient spațiu in heap, iar dacă nu avem se face o realocare
se adaugă elementul la finalul heap-ului și se compară cu parintele său
dacă este mai mare se interschimbă și se reia etapa 2
1.4 Ștergerea unui Element
Etape:
se mută ultimul element pe poziția elementului de șters
se aplică algoritmul heapify down pe elementul modificat
1.5 Heapsort
Etape:
se redimensionează heap-ul corespunzător
se populează heap-ul cu valorile vectorului pe care dorim să-l sortăm
se aplică heapify pe toate nodurile interne
se interschimbă primul element cu ultimul
se scade dimensiunea heap-ului
se aplică heapify pe poziția 0, apoi se reia până când epuizăm toate elementele
Probleme propuse
Implementați ștergerea unui element dintr-un heap.
Implementați metoda de sortare heapsort.
Aflați eficient cele mai mari/mici k elemente dintr-un vector folosind un heap.
Hint: Nu toate elementele trebuie introduse în heap
Fie un vector k-sortat de dimensiune n, sortați eficient vectorul k-sortat. Un vector se numeste k-sortat daca fiecăre element se află la maxim k poziții distanță de poziția sa din cadrul vectorului sortat.
Hint: Se poate mai eficient de O(nlogn)
Fie M vectori sortați de diferite dimensiuni. Interclasați vectorii eficient folosind un heap.
Hint: Ce dimensiune trebuie să aibă heap-ul?
2. Hashtable
O tabelă de dispersie (hashtable) este o structură de date ce realizează o mapare de forma cheie - valoare. Această formă de stocare facilitează accesul rapid la date.
2.1 Tratarea Coliziunilor
Dispersie deschisă(Chaining)
Dispersie închisă(Open addressing)
2.1.1 Dispersia deschisă
În cazul dispersiei deschise se folosesc liste înlănțuite pentru stocarea elementelor cu aceiași cheie. În cel mai nefavorabil caz toate elementele sunt puse la același index rezultând o complexitate O(n) pentru operațiile efectuate.
Mai jos aveți un exemplu de tabelă de dispersie în care coliziunile se tratează prin înlănțuire, iar funcția hash este f(x) = x % 7:
În cazul unei dispersii deschise este foarte important factorul de încărcare a = N/M unde:
2.1.2 Dispersia închisă
În cazul dispersiei închise toate elementele se memorează în tablea T, iar la producerea coliziunilor se verifică alte celule, cel mai simplu mod de rezolvare al coliziunilor este cel în care se caută prima celula liberă pentru inserare, dar se pot utiliza si alte metode.
Mai jos aveți un exemplu de tabelă de dispersie în care coliziunile se tratează liniar, iar funcția hash este f(x) = x % 7:
Probleme propuse
Fie structura din josul paginii. Considerați că trebuie stocate pentru căutări/adăugări/ștergeri cât mai rapide 10.000 de înregistrări de tip Student.Implementați folosind:
Tabelă de dispersie cu înlănțuire
Tabelă de dispersie cu adresare închisă
Găsiți toate perechile de mulțimi simetrice dintr-un vector de mulțimi de 2 elemente. Două mulțimi sunt simetrice dacă capătul din stanga al primei mulțimi este egal cu cel din dreapta a celei de-a doua, iar cătul din dreapta al primei este egal cu cel din stanga al celei de-a doua.
Exemplu: { [10, 20], [20, 10], [1, 11], [1, 10], [10, 1]} ⇒ {[10, 20], [1, 10]}
Hint: Se folosește o singură tabelă de dispersie.
- Student.c
typedef struct
{
int cod; // unic
char *nume, *prenume, *adresa;
int medie;
int an_studii;
}Student;