B={0,1,...,MAX-1} : K

Σχετικά έγγραφα
Metode iterative pentru probleme neliniare - contractii

Curs 10 Funcţii reale de mai multe variabile reale. Limite şi continuitate.

(a) se numeşte derivata parţială a funcţiei f în raport cu variabila x i în punctul a.

Curs 14 Funcţii implicite. Facultatea de Hidrotehnică Universitatea Tehnică "Gh. Asachi"

III. Serii absolut convergente. Serii semiconvergente. ii) semiconvergentă dacă este convergentă iar seria modulelor divergentă.

a n (ζ z 0 ) n. n=1 se numeste partea principala iar seria a n (z z 0 ) n se numeste partea

V.7. Condiţii necesare de optimalitate cazul funcţiilor diferenţiabile

Functii definitie, proprietati, grafic, functii elementare A. Definitii, proprietatile functiilor X) functia f 1

Integrala nedefinită (primitive)

Functii definitie, proprietati, grafic, functii elementare A. Definitii, proprietatile functiilor

TABELE DE DISPERSIE I. CONSIDERAŢII TEORETICE

Curs 4 Serii de numere reale

DISTANŢA DINTRE DOUĂ DREPTE NECOPLANARE

5. FUNCŢII IMPLICITE. EXTREME CONDIŢIONATE.

Analiza în curent continuu a schemelor electronice Eugenie Posdărăscu - DCE SEM 1 electronica.geniu.ro

Laborator 1: INTRODUCERE ÎN ALGORITMI. Întocmit de: Claudia Pârloagă. Îndrumător: Asist. Drd. Gabriel Danciu

R R, f ( x) = x 7x+ 6. Determinați distanța dintre punctele de. B=, unde x și y sunt numere reale.

MARCAREA REZISTOARELOR

Curs 1 Şiruri de numere reale

Metode de interpolare bazate pe diferenţe divizate

Planul determinat de normală şi un punct Ecuaţia generală Plane paralele Unghi diedru Planul determinat de 3 puncte necoliniare

Criptosisteme cu cheie publică III

Subiecte Clasa a VIII-a

Esalonul Redus pe Linii (ERL). Subspatii.

riptografie şi Securitate

Asupra unei inegalităţi date la barajul OBMJ 2006

Orice izometrie f : (X, d 1 ) (Y, d 2 ) este un homeomorfism. (Y = f(x)).

Seminar 5 Analiza stabilității sistemelor liniare

SEMINAR 14. Funcţii de mai multe variabile (continuare) ( = 1 z(x,y) x = 0. x = f. x + f. y = f. = x. = 1 y. y = x ( y = = 0

COLEGIUL NATIONAL CONSTANTIN CARABELLA TARGOVISTE. CONCURSUL JUDETEAN DE MATEMATICA CEZAR IVANESCU Editia a VI-a 26 februarie 2005.

Subiecte Clasa a VII-a

Seminariile Capitolul X. Integrale Curbilinii: Serii Laurent şi Teorema Reziduurilor

Functii Breviar teoretic 8 ianuarie ianuarie 2011

Curs 2 Şiruri de numere reale

Principiul incluziunii si excluziunii. Generarea şi ordonarea permutărilor. Principiul porumbeilor. Pri

Sisteme diferenţiale liniare de ordinul 1

Aplicaţii ale principiului I al termodinamicii la gazul ideal

După cum se observă, tabela din figură, ca şi marea majoritate a tabelelor, este alcătuită din articole.

Definiţia generală Cazul 1. Elipsa şi hiperbola Cercul Cazul 2. Parabola Reprezentari parametrice ale conicelor Tangente la conice

EDITURA PARALELA 45 MATEMATICĂ DE EXCELENŢĂ. Clasa a X-a Ediţia a II-a, revizuită. pentru concursuri, olimpiade şi centre de excelenţă

Capitolul 4 PROPRIETĂŢI TOPOLOGICE ŞI DE NUMĂRARE ALE LUI R. 4.1 Proprietăţi topologice ale lui R Puncte de acumulare

Sortare. 29 martie Utilizarea şi programarea calculatoarelor. Curs 16

2 Transformări liniare între spaţii finit dimensionale

Cursul Măsuri reale. D.Rusu, Teoria măsurii şi integrala Lebesgue 15

a. 11 % b. 12 % c. 13 % d. 14 %

Metode de sortare. Se dau n numere întregi, elemente ale unui vector a. Se cere să se aranjeze elementele vectorului a în ordine crescătoare.

8 Intervale de încredere

Algoritmica grafurilor XI. Cuplaje in grafuri. Masuri de calitate. Numere Ramsey

5.4. MULTIPLEXOARE A 0 A 1 A 2

III. Reprezentarea informaţiei în sistemele de calcul

Spatii liniare. Exemple Subspaţiu liniar Acoperire (înfăşurătoare) liniară. Mulţime infinită liniar independentă

Lucrare. Varianta aprilie I 1 Definiţi noţiunile de număr prim şi număr ireductibil. Soluţie. Vezi Curs 6 Definiţiile 1 şi 2. sau p b.

Laborator 11. Mulţimi Julia. Temă

1.3 Baza a unui spaţiu vectorial. Dimensiune


Capitolul 4. Integrale improprii Integrale cu limite de integrare infinite

Examen AG. Student:... Grupa:... ianuarie 2011

Geometrie computationala 2. Preliminarii geometrice

V O. = v I v stabilizator

BARAJ DE JUNIORI,,Euclid Cipru, 28 mai 2012 (barajul 3)

SERII NUMERICE. Definiţia 3.1. Fie (a n ) n n0 (n 0 IN) un şir de numere reale şi (s n ) n n0

1.7. AMPLIFICATOARE DE PUTERE ÎN CLASA A ŞI AB

f(x) = l 0. Atunci f are local semnul lui l, adică, U 0 V(x 0 ) astfel încât sgnf(x) = sgnl, x U 0 D\{x 0 }. < f(x) < l +

Lectia VI Structura de spatiu an E 3. Dreapta si planul ca subspatii ane

Conice. Lect. dr. Constantin-Cosmin Todea. U.T. Cluj-Napoca

T R A I A N ( ) Trigonometrie. \ kπ; k. este periodică (perioada principală T * =π ), impară, nemărginită.

4. Liste. Generalităţi. a1, a2,,an p<n ap+1 p>1 n Operaţii specifice listelor. operaţii fundamentale NULL

Analiza funcționării și proiectarea unui stabilizator de tensiune continuă realizat cu o diodă Zener

2. Circuite logice 2.4. Decodoare. Multiplexoare. Copyright Paul GASNER

CONCURSUL DE MATEMATICĂ APLICATĂ ADOLF HAIMOVICI, 2017 ETAPA LOCALĂ, HUNEDOARA Clasa a IX-a profil științe ale naturii, tehnologic, servicii

2.1 Sfera. (EGS) ecuaţie care poartă denumirea de ecuaţia generală asferei. (EGS) reprezintă osferă cu centrul în punctul. 2 + p 2

Proiectarea algoritmilor: Programare dinamică

Tipuri abstracte de date.

Să se arate că n este număr par. Dan Nedeianu

Fig Impedanţa condensatoarelor electrolitice SMD cu Al cu electrolit semiuscat în funcţie de frecvenţă [36].


Proiectarea Algoritmilor 2. Scheme de algoritmi Divide & Impera

Integrale cu parametru

Examen AG. Student:... Grupa: ianuarie 2016

Stabilizator cu diodă Zener

CONCURS DE ADMITERE, 17 iulie 2017 Proba scrisă la MATEMATICĂ

Sortare şi cǎutare. 8 ianuarie Utilizarea şi programarea calculatoarelor. Curs 11

5.5. REZOLVAREA CIRCUITELOR CU TRANZISTOARE BIPOLARE

Toate subiectele sunt obligatorii. Timpul de lucru efectiv este de 3 ore. Se acordă din oficiu 10 puncte. SUBIECTUL I.

Ecuatii exponentiale. Ecuatia ce contine variabila necunoscuta la exponentul puterii se numeste ecuatie exponentiala. a x = b, (1)

VII.2. PROBLEME REZOLVATE

Concurs MATE-INFO UBB, 1 aprilie 2017 Proba scrisă la MATEMATICĂ

7 Distribuţia normală

Al cincilea baraj de selecţie pentru OBMJ Bucureşti, 28 mai 2015

prin egalizarea histogramei

CURS 11: ALGEBRĂ Spaţii liniare euclidiene. Produs scalar real. Spaţiu euclidian. Produs scalar complex. Spaţiu unitar. Noţiunea de normă.

Universitatea din Bucureşti Facultatea de Matematică şi Informatică. Algebră (1)

Vectori liberi Produs scalar Produs vectorial Produsul mixt. 1 Vectori liberi. 2 Produs scalar. 3 Produs vectorial. 4 Produsul mixt.

Zgomotul se poate suprapune informaţiei utile în două moduri: g(x, y) = f(x, y) n(x, y) (6.2)

Cursul 6. Tabele de incidenţă Sensibilitate, specificitate Riscul relativ Odds Ratio Testul CHI PĂTRAT

CURS XI XII SINTEZĂ. 1 Algebra vectorială a vectorilor liberi

Principiul Inductiei Matematice.

a. Caracteristicile mecanice a motorului de c.c. cu excitaţie independentă (sau derivaţie)

SEMINARUL 3. Cap. II Serii de numere reale. asociat seriei. (3n 5)(3n 2) + 1. (3n 2)(3n+1) (3n 2) (3n + 1) = a

4.TABLOU. Lect. dr. Trimbitas Gabriela

Transcript:

Tabele de Dispersie. Definiţii şi terminologie. Tabelele de dispersie reprezintă o modalitate foarte eficientă de implementare a dicţionarelor. Acestea asigură complexitate constantă O() în medie, pentru operaţiile de inserare, ştergere şi căutare. Dispersia nu presupune ordonarea informaţiei păstrate. Operaţiile cu arbori, care presupun ordonarea informaţiei între elemente sunt mai puţin eficiente (O(log n)). Dacă: structura de date (tabela de dispersie) e accesată prin valoarea unei chei în O() funcţia care transformă cheia într-o poziţie într-un tabel are complexitate O() atunci inserarea / ştergerea / căutarea se vor face cu complexitate O() Dispersia implementează această idee folosind: o tabelă de dispersie o funcţie de dispersie Dacă funcţia de dispersie calculează pentru două chei diferite aceeaşi valoare de dispersie, se produce o coliziune. Aceesul la cheile aflate în coliziune nu se mai face cu complexitate constantă. Pentru a reduce coliziunile se folosesc tabele de dimensiuni foarte mari. (eficienţa temporală mai bună este anihilată de eficienţa spaţială mai proastă). Tabelele de dispersie pot fi deschise (sau externe) şi închise (sau interne). Funcţii de dispersie. Fie K o mulţime de chei (întregi, şiruri de caractere, forme complexe de biţi) şi B o mulţime de valori de dispersie (bini). Vom considera B={0,,...,MAX-. Aplicaţia hash : K B poartă numele de funcţie de dispersie, şi asociază mulţimii cheilor o mulţime de valori de dispersie. Este de dorit ca această funcţie să fie injectivă, adică la două chei diferite k k 2 să corespundă valori de dispersie diferite hash(k ) hash(k 2 ), în caz contrar apare o coliziune. Funcţia de dispersie trebuie să fie aleasă astfel încât să asigure o dispersie cât mai uniformă, care să minimizeze numărul de coliziuni. In general numărul cheilor efectiv memorate este mult mai mic decât numărul total de chei posibile. Utilizarea adresării directe, având complexitate O() ar conduce la folosirea neeficientă a unor tablouri foarte mari care ar conţine relativ puţine elemente. Căutarea în dicţionar se face cu complexitate O() dacă: se reprezintă datele printr-un tabel de dispersie H se găseşte o funcţie de dispersie care mapează cheile în indici din tabelul de dispersie în mod unic: k k 2 hash(k ) hash(k 2 ) memorează elementul (k,i) în H[hash(k)]

Alegerea funcţiei de dispersie Fie MAX dimensiunea tabelului de dispersie. Pentru valoarea de dispersie 0:MAX- se introduce tipul Index: typedef unsigned int Index; Pentru chei întregi se folosesc:. Metoda împărţirii : hash(k) = k % MAX în care MAX trebuie să fie un număr prim care să nu fie apropiat de o putere a lui 2. Index Hash(void *k, Index MAX){ return *(int*)k % nextprim(max); 2. Metoda înmulţirii: reţine o parte din biţii părţii fracţionare a produsului k*a, în care A este o constantă (Knuth recomandă pentru A raportul de aur ( 5-)/2). De exemplu dacă dimensiunea tabelei de dispersie este de 024, este suficient un index de 6 biţi, deci se calculează partea fracţionară a lui A: 2 6 *A = 40503 şi se selectează cei mai semnificativi 0 biţi, prin deplasare dreapta cu 6 poziţii. Index Hash(void *k, Index MAX){ Index c=40503; return (c * *(int*)k) >> 6; Dacă cheia este un şir de caractere, typedef char *Index; se foloseşte una din funcţiile: 3. Adunarea codurilor caracterelor. Index Hash(void *k, Index MAX){ Index vd=0; while(*(char*)k!= 0) vd += *(char*)k++; return ( vd % nextprim(max) ); 4. Metoda sau-exclusiv. Dintr-un tablou de numere generate aleator se selectează acele numere care au ca indici caracterele cheii şi face sau-exclusiv între ele: unsigned char Rand8[256]; Index Hash(void *k, Index MAX){ Index vd = 0; while(*(char*)k) vd = Rand8[vd ^ *(char*)k++]; return (vd % nextprim(max)); 5. Metoda acumulării polinomiale. 2

Se partiţionează biţii cheii în componente de lungime fixă (8, 6 sau 32 de biţi), fie acestea a 0, a,...,a n-. Se evaluează polinomul p(z)=a 0 +a z+...+a n- z n-, într-un punct dat z (cu rezultate bune se ia z=32), ignorând depăşirile. Se evaluează polinomul cu schema lui Horner, în O(n). p i (z)=a n-i- +zp i- (z), i=:n- Index Hash(void *k, Index MAX){ Index vd=0; while(*(char*)k!= 0) vd = (vd<<5)+*(char*)k++; return ( vd % nextprim(max) ); 6. Dispersie universală O familie de funcţii de dispersie este universală dacă pentru orice 0 j, k M- Prob(h(j)=h(k)) /M Se alege p prim între M şi 2M Se alege aleatoriu 0<a<p şi 0 b<p şi se defineşte: hash(k)=(ak+b)%p%n Mulţimea tuturor funcţiilor h astfel definite este universală. Demonstraţie: f(k)=(ak+b)%p şi g(k)=k % M h(k)=g(f(k)) Presupunem că am avea coliziuni: f(k)=f(j) aj + b aj + p b p = ak + b ak + p b p a aj + p b ak + p b ( j k) = p a(j-k) este deci multiplu de p, dar ambii factori sunt mai mici ca p, rezultă că a(j-k) = 0, adică j=k contradicţie! de unde rezultă că f nu produce coliziuni. Dacă f nu produce coliziuni, atunci numai g ar putea produce coliziuni. Fixăm un număr x. Dintre cei p întregi y=f(k), diferiţi de x, numărul pentru care g(y)=g(x) este cel mult p/n - Întrucât există p selecţii posibile pentru x, numărul de funcţii care ar putea produce o coliziune între j şi k este cel mult: p( p/n -) p(p-)/n Există p(p-) funcţii h, astfel că probabilitatea unei coliziuni este cel mult: 3

( p ) / N = p( p ) N p adică mulţimea tuturor funcţiilor posibile este universală. Putem da pentru orice funcţie de dispersie semnătura comună: Index hash(void *cheie, Index ind); Utilizatorul îşi poate defini propria funcţie de dispersie, transmisă ca pointer la funcţie în lista de parametri a operaţiilor primitive. În acest scop vom defini tipul pointer la funcţia de dispersie: typedef Index (*PFD)(void *, Index); Strategii de rezolvare a coliziunilor. In cazul dispersiei deschise (cu înlănţuire), coliziunile se rezolvă prin punerea lor într-o listă înlănţuită asociată valorii de dispersie comune.se crează astfel un tablou de liste de coliziune. În cazul dispersiei închise: toate elementele se memorează în tabelul de dispersie nu se mai folosesc pointeri la producerea unei coliziuni se verifică alte celule, până când se găseşte una liberă.celulele verificate formează un lanţ de coliziune h 0 (x), h (x),... unde h i (x)=(hash(x)+f(i))%m cu F(0)=0 Funcţia F dă strategia de rezolvare a coliziunii. Întrucât toate datele se introduc în tabela de dispersie este necesar un tabel cu dimensiune mai mare. În general factorul de încărcare ar trebui să fie sub 0.5 pentru dispersia închisă. Dispersie deschisă (sau înlănţuită) Dimensiunea tabloului listelor de coliziuni este numărul total de valori de dispersie MAX. Lista elementelor cu aceeasi valoare de dispersie 0 MAX- Inlantuirea coliziunilor in cazul dispersiei deschise Operaţiile specifice sunt: TD TD_New (int m) -crează un tabel de dispersie cu m liste de coliziune vide, 4

void TD_Insert (TD h, void *k, void *info, PFC comp, PFD hash) - insereaza perechea (k, info) în lista cu numărul hash(k). Compararea cheilor se face cu funcţia comp. List_Iter TD_Search (TD h, void *k, PFC comp, PFD hash) - caută cheia k în lista de coliziune hash(k) şi întoarce adresa nodului din lista de coliziune care conţine cheia void *TD_Remove (TD h, void *k, PFC comp, PFD hash) şterge din lista de coliziune cu numărul hash(k) elementul cu cheia k. Funcţia întoarce adresa informaţiei asociate cheii. void *TD_Get(Lista L,List_Iter p) obţine informaţia asociată cheii din lista de coliziune, din nodul dat ca parametru. int TD_Empty(TD h) test tabel de dispersie vid int TD_Size(TD h) numărul de elemente memorat în tabelul de dispersie. In cazul cel mai nefavorabil, complexitatea acestor operaţii este O(n). In medie, complexitatea acestor operaţii este O(+λ), în care factorul de încărcare λ = n/max, unde n este numărul elementelor memorate MAX este dimensiunea tabelei de dispersie. (în cazul dispersiei deschise λ poate fi supraunitar). Dispersia cu înlănţuire separată are dezavantajul că necesită pointeri, alocare de memorie, deci este lentă. // Dispersie deschisa #ifndef TD_H #define TD_H #include list.h Interfaţă dispersie deschisă. typedef int (*PFC)(void*, void*); typedef int (*PFD)(void*, int); struct TabDisp; typedef struct TabDisp *TD; TD TD_New (int m); List_Iter TD_Search (TD h, void *k, PFC comp, PFD hash); void TD_Insert (TD h, void *k, void *info, PFC comp, PFD hash); void *TD_Remove(TD h, void *k, PFC comp, PFD hash); void TD_Delete (TD *h); int TD_Empty (TD h); int TD_Size (TD h); #endif Implementare dispersie deschisă. Pentru a păstra structura nodurilor TAD Listă, vom grupa asocierea (cheie, informaţie) într-o structură şi vom defini funcţii pentru creerea acestei asocieri şi pentru selectarea componentelor. Aceste funcţii vor fi interne secţiunii de implementare, deci inaccesibile utilizatorului. typedef struct per{ 5

void *ch; //cheia elementului void *info; //informaţia elementului *pereche; //creaza perechea (cheie,informatie) intorcand adresa asocierii void *dublet(void *k, void *i){ pereche p =(pereche)malloc(sizeof(struct per)); p->ch = k; p->info = i; return p; //selecteaza cheia din asocierea (cheie, informatie) void *sel_cheie(pereche p){ return p->ch; //selecteaza informatia din asocierea (cheie, informatie) void *sel_info(pereche p){ return p->info; Tabela de dispersie va conţine dimensiunea max, numărul de elemente şi tabloul listelor de coliziune. struct TabDisp{ int max; int n; List *lcol; ; //dimensiune TD //numar efectiv elemente din TD //tabloul de liste de coliziune Iniţializarea tabelei de dispersie presupune: alocarea de memorie pentru structura tabelă de dispersie şi iniţializarea ei alocarea de memorie pentru tabloul de liste de coliziune şi iniţializarea fiecărei liste ca listă vidă H max n lcol n prim ultim TD TD_New (int m){ TD h; h=(td)malloc(sizeof(struct TabDisp)); h->max=m; h->n=0; h->lcol=(lista*)malloc(m*sizeof(lista)); int i; 6

for(i=0; i<m; i++) h->lcol[i]=l_new(); return h; Funcţia TD_Search() întoarce poziţia nodului cu cheia k în lista de coliziune a elementelor cu aceeaşi valoare de dispersie sau NULL, dacă elementul nu există în tabela de dispersie. List_Iter TD_Search (TD h, void *k, PFC comp, PFD hash){ List_Iter p; p=l_find(h->col[hash(k, h->max)], k, comp); return p; Funcţia TD_Insert()caută mai întâi elementul cu cheia k în tabela de dispersie. Dacă îl găseşte, el nu mai trebuie inserat, altfel se crează un nod în care se pune cheia k şi informaţia asociată info, şi se inserează în lista selectată de funcţia de dispersie. void TD_Insert (TD h, void *k, void *info, PFC comp, PFD hash){ List_Iter p; p=td_search (H, k, comp, hash); if(p) return; //exista, nu se mai pune void *d = dublet(k, info); L_Insert(h->lcol[hash(k,h->max)], p, d); h->n++; Penru funcţia TD_Remove() se caută mai întâi elementul în tabela de dispersie, în lista corespunzăoare cheii. Dacă nu se găseşte, nu avem ce şterge, altfel se şterge elementul din listă şi se scade numărul elementelor din listă. void *TD_Remove (TD h, void *k, PFC comp, PFD hash){ List_Iter p; p=td_search (h, k, comp, hash); if(!p) return NULL; void *d=l_remove(h->lcol[hash(k,h->max)],p); h->n--; return sel_info((struct per *)d); void TD_Delete(TD *h){ int i; for(i=0; i<(*h)->max; i++) L_Delete(&(*h)->lcol[i]); free(*h); Dispersia închisă. Dacă funcţia iniţială de dispersie este h(x), notată h(x, 0), atunci celelalte funcţii de dispersie se obţin astfel:. Verificarea liniară adoptă o funcţie liniară de i, de obicei F(i)=i. Celulele alăturate sunt verificate ciclic în căutarea unei celule libere. Dacă tabelul este suficient de mare se va găsi o celulă liberă, dar timpul de căutare poate deveni foarte mare. 7

h(x,i)=(h(x)+i) % MAX Lanţul de coliziune poate avea dimensiunea maximă M; el se termină mai devreme, dacă se întâlneşte o celulă marcată LIBER. Verificarea liniară favorizează creerea de blocuri vecine ocupate aglomerări (ciorchini) primare, care pot apare şi pentru tablouri puţin ocupate şi degrada performanţele. 2. Verificarea pătratică foloseşte F(i)=i 2 şi elimină aglomerările primare. Dacă dimensiunea tabloului este număr prim, un nou element poate fi întotdeauna inserat dacă tabelul este cel puţin pe jumătate gol. h(x,i)=(h(x)+i 2 ) % MAX Metoda verificării pătratice generează cel mult o secvenţă de MAX funcţii de dispersie, dar produce aglomerări secundare 3. Dispersia dublă foloseşte o a doua funcţie de dispersie h 2 (k) şi tratează coliziunile punând elementul în prima celulă liberă dintre h(x,i)=(h(x)+ih 2 (x)) % MAX, a doua funcţie de dispersie h 2 (k) nu poate lua valoarea 0 dimensiunea tabelei trebuie să fie un număr prim, pentru a permite verificarea tuturor celulelor a doua funcţie de dispersie h 2 (k) este de forma: h 2 (k)=q-k%q în care q este prim şi q < M Metoda dispersiei duble generează cel mult o secvenţă de MAX 2 funcţii de dispersie, dar nu produce nici aglomerări primare nici secundare. Factorul de încărcare λ=n/max afectează performanţele tabelei de dispersie. Pentru verificarea liniară, funcţiile primitive sunt: TD_Search (h, k, comp, hash) caută cheia k mai întâi în h[hash(k)] dacă nu o găseşte, continuă căutarea în h[hash(k)+i] până când: o o găseşte pe k - succes o dă peste o poziţie liberă în tabelul de dispersie - eşec o a efectuat MAX tentative - eşec TD_Remove (h, k, comp, hash) caută cheia k mai întâi în H[hash(k)] dacă găseşte pe k, îi pune marcajul STERS, fără a-l şterge efectiv -succes. Dacă nu-l găseşte, continuă căutare în h[hash(k)+i] până când: o îl găseşte în proba i şi îi pune marcajul STERS - succes o găseşte o celulă liberă sau face MAX încercări - eşec TD_Insert (h, k, i, comp, hash) caută cheia k mai întâi în h[hash(k)] dacă k este găsit, el nu va mai fi inserat dacă poziţia poziţia cercetată are marcajul LIBER sau STERS este pusă cheia în poziţia respectivă şi marcajul pe OCUPAT dacă poziţia este OCUPAT se încearcă punerea elementului în poziţia h[hash(k)+i]. Se fac cel mult MAX tentative. Interfaţă dispersie închisă. 8

#ifndef _HT_probQ #define _HT_probQ struct TabDisp; typedef struct TabDisp *TD; typedef int (*PFC)(void*, void*); typedef int (*PFD)(void*, int); TD TD_New (int m); int TD_Search (TD h, void *k, PFC comp, PFD hash); void TD_Insert (TD h, void *k, void *inf, PFC comp, PFD hash); void TD_Remove (TD h, void *k, PFC comp, PFD hash); void TD_Delete (TD *h); int TD_Empty (TD h); int TD_Size (TD h); TD TD_ReDisp(TD h, PFC comp, PFD hash); #endif Implementare dispersie închisă. În cazul dispersiei închise nu se face o ştergere efectivă a elementelor din tabela de dispersie, deoarece aceasta este costisitoare, necesitând deplasări de elemente, cu complexitate O(MAX). Poziţiile din tabela de dispersie vor fi marcate cu valorile OCUPAT şi LIBER. La ştergerea unui element în tabela de dispersie, acesta nu va primi marcajul LIBER, deoarece s-ar întrerupe lanţul de valori aflate în coliziune, marcând în mod fals sfârşitul acestora. Astfel dacă am avea două elemente în coliziune, ele ar fi memorate unul după celălalt în tabela de dispersie. Dacă se şterge primul, marcându-l ca LIBER, o căutare a celui de-al doilea element ar testa mai întâi pe primul, ar găsi poziţia LIBER şi ar ajunge la concluzia greşită că elementul căutat nu există. Pentru ştergere se va folosi o altă valoare a marcajului: STERS care permite continuarea căutării. Un element din tabela de dispersie va fi descris aşadar prin: cheie, valoare asociată şi marcaj de ocupare. Un grup de elemente aflate în coliziune poate avea lungimea cel mult MAX sau se poate termina mai repede printr-o celulă marcată LIBER. Trecerea la următorul element din grup, în cazul verificării pătratice se face adunând la poziţia iniţială p pe i 2 (sau adăugând 2*i- la poziţia curentă) enum Marcaj{OCUPAT, LIBER, STERS; struct Elem{ void *ch; void *info; enum Marcaj mark; ; struct TabDisp{ int max; int n; struct Elem *TabCel; ; TD TD_New(int m){ TD h; int i; h=(td)malloc(sizeof(struct TabDisp)); h->max=nextprim(m); 9

h->n=0; h->tabcel=(struct Elem*)malloc(sizeof(struct Elem)*h->max); for(i=0; i<h->max; i++) h->tabcel[i].mark=liber; return h; int TD_Search (TD h, void *k, PFC comp, PFD hash){ int p; int i=0; p=hash(k, h->max); while(i < h->max && h->tabcel[p].mark!= LIBER && comp(h->tabcel[p].ch, k)!=0) { p += 2* ++i ; if(p >= h->max) p -= h->max; if(i > h->max h->tabcel[p].mark==liber) return h->max; // esec - nu a gasit return p; // succes void TD_Insert(TD h, void *k, void *inf, PFC comp, PFD hash){ int p = TD_Search (h, k, comp, hash); if(p < h->max) return; //cheia exista deja int i=0; while(i < h->max && h->tabcel[p].mark==ocupat) { p += 2* ++i ; if(p >= h->max) p -= h->max; assert(i < h->max); h->tabcel[p]->ch = k; h->tabcel[p]->info = inf; h->tabcel[p].mark = OCUPAT; h->n++; void TD_Remove (TD h, void *k, PFC comp, PFD hash){ int p = TD_Search (H, k, comp, hash); if(p >= h->max) return; //nu exista cheia in TD int i=0; while(i < h->max && h->tabcel[p].mark!=liber && comp(h->tabcel[p].ch, k)!=0) { p += 2* ++i ; if(p >= h->max) p -= h->max; if(h->tabcel[p].mark==ocupat && 0

comp(h->tabcel[p].ch, k)==0) { h->tabcel[p].mark = STERS; h->n--; Redispersare. Dacă factorul de încărcare al tabelei de dispersie depăşeşte 0.5, operaţiile de inserare pot eşua. În această situaţie se preferă reconstruirea tabelei de dispersie cu dimensiune dublată. Schimbarea dimensiunii presupune recalcularea poziţiei ocupate de elemente în noua tabelă de dispersie. Operaţia este scumpă, cu complexitate O(n), dar se face rar. TD TD_ReDisp(TD h, PFC comp, PFD hash){ struct Elem *TCv = h->tabcel; int n = h->n; int mv = h->max; h = TD_New (2*mv); h->n = n; int i; for(i=0; i<mv; i++) if(tcv[i].mark==ocupat) TD_Insert(h, TCv[i].ch, TCv[i].info, comp, hash); free(tcv); return h; Eficienţa operaţiilor în Tabele de dispersie. Este strict legată de numărul de coliziuni. Dacă numărul de elemente memorate se apropie de dimensiunea tabelei de dispersie (factorul de încărcare se apropie de ) numărul de coliziuni creşte rapid. Alegerea unei funcţii de dispersie eficiente reduce numărul de coliziuni. Dimensiunea tabelei de dispersie trebuie să fie număr prim. Strategia de rezolvare a coliziunilor influienţează numărul acestora. Distribuţia cheilor influienţează de asemenea numărul de coliziuni. Este de dorit ca aceste chei să fie distribuite aleator. Numărul mediu de comparaţii pentru o căutare, aplicând diferite strategii de rezolvare a coliziunilor: Număr de comparaţii Căutare cu succes Căutare fără succes Încercări liniare 2 + Încercări pătratice ln( λ) Înlănţuire + λ 2 λ λ 2 λ λ + 2 ( λ)

Probleme propuse. Daţi conţinutul tabelei de dispersie obţinută prin inserarea caracterelor E X A M E N P A R T I A L, în această ordine într-un tabel, iniţial vid cu M=5 liste, folosind înlănţuire separată cu liste neordonate. Se foloseşte funcţia de dispersie k mod M pentru a transforma litera cu numărul de ordine k din alfabet într-un indice în tabel, De exemplu, hash(i) = hash(9) = 99 % 5 = 4. Daţi conţinutul tabelei de dispersie obţinută prin inserarea caracterelor E X A M E N P A R T I A L, în această ordine într-un tabel, iniţial vid de dimensiune M=6, folosind verificarea lineară. Se foloseşte funcţia de dispersie k mod M pentru a transforma litera cu numărul de ordine k din alfabet într-un indice în tabel, De exemplu, hash(i) = hash(9) = 99 % 5 = 4. Daţi conţinutul tabelei de dispersie obţinută prin inserarea caracterelor E X A M E N P A R T I A L, în această ordine într-un tabel, iniţial vid de dimensiune M=6, folosind dispersia dublă. Use the hash function k mod M pentru proba iniţială şi funcţia de dispersie secundară (k mod 3) +. 2