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:

  • să implementeze algoritmi ce au la baza o structura de tip Heap
  • să selecteze tipul de tabelă de dispersie potrivit pentru o problemă

Structura laboratorului se gaseste in acest link.

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ă:

  • Creare/Distrugere Heap
  • Popularea unui Heap
  • Adăugarea unui Element
  • Ștergere unui Element
  • Extragere element maxim/minim
  • Sortare - Heapsort

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:

  1. se crează un heap cu o capacitate suficient de mare pentru stocarea elementelor
  2. se mută elementele vectorului in spațiul de stocare al heap-ului
  3. 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->capacity == 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:

  1. se verifică dacă avem suficient spațiu in heap, iar dacă nu avem se face o realocare
  2. se adaugă elementul la finalul heap-ului și se compară cu parintele său
  3. dacă este mai mare se interschimbă și se reia etapa 2

1.4 Ștergerea unui Element

Etape:

  1. se mută ultimul element pe poziția elementului de șters
  2. se aplică algoritmul heapify down pe elementul modificat

1.5 Heapsort

Etape:

  1. se redimensionează heap-ul corespunzător
  2. se populează heap-ul cu valorile vectorului pe care dorim să-l sortăm
  3. se aplică heapify pe toate nodurile interne
  4. se interschimbă primul element cu ultimul
  5. se scade dimensiunea heap-ului
  6. se aplică heapify pe poziția 0, apoi se reia până când epuizăm toate elementele

Probleme propuse

  1. Implementați ștergerea unui element dintr-un heap.
  2. Implementați metoda de sortare heapsort.
  3. Aflați eficient cele mai mari/mici k elemente dintr-un vector folosind un heap.
    1. Hint: Nu toate elementele trebuie introduse în heap
  4. 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.
    1. Hint: Se poate mai eficient de O(nlogn)
  5. Fie M vectori sortați de diferite dimensiuni. Interclasați vectorii eficient folosind un heap.
    1. 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

  1. Dispersie deschisă(Chaining)
  2. 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:

  • N - numărul de chei stocate
  • M - numărul slot-uri puse la dispoziție

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

  1. 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:
    1. Tabelă de dispersie cu înlănțuire
    2. Tabelă de dispersie cu adresare închisă
  2. 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;
sda-ab/laboratoare/08.1618150575.txt.gz · Last modified: 2021/04/11 17:16 by leonard.necula
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0