Sunteți pe pagina 1din 11

# Alexandru Cohal

Decembrie 2013
2

Cuprins

I ntroducere.............................................................................................................. 3

Funcii hash ............................................................................................................ 5
Metoda Diviziunii (restul mpririi la m) .................................................. 5
Metoda nmulirii ................................................................................................ 5
Metoda probabilistic (Hashing-ul universal) .......................................... 5

I nterpretarea cheilor ca numere naturale............................................. 6

Coliziunile................................................................................................................ 6
Chaining (nlnuire).......................................................................................... 6

Distribuia cheilor ............................................................................................... 8
Examinarea liniar ............................................................................................. 8
Examinarea ptratic ........................................................................................ 8
Hashing dublu ...................................................................................................... 8

Hashing-ul perfect .............................................................................................. 9

Hash-uri n STL ................................................................................................. 10

Aplicaii ................................................................................................................... 10
Algoritmul Rabin - Karp ................................................................................ 10
Alte probleme...................................................................................................... 11

Legturi ................................................................................................................... 11

Bibliografie............................................................................................................ 11

3

I ntroducere
Multe aplicaii necesit o mulime dinamic pentru care s se aplice numai operaiile
specifice pentru dicionare: inserare, cutare, tergere.
O tabel de dispersie (tabel hash) este o structur eficient de date pentru
implementarea dicionarelor care presupun operaiile menionate.
O tabel de dispersie este o generalizare a noiunii mai simple de tablou.

Adresarea direct ntr-un tablou folosete abilitatea noastr de a examina o poziie
arbitrar n timp (1). Adresarea direct este aplicabil numai n cazul n care ne permitem s
alocm un tablou care are cte o poziie pentru fiecare cheie posibil.

Figura 1.
Implementarea unei mulimi dinamice printr-un tablou cu adresare direct .
Fiecare cheie din universul = 0,1,2,,9 corespunde unui indice n tablou.
Mulimea = 2,3,5,8 a cheilor efective determin locaiile din tablou care conin pointeri
ctre elemente.
Celelalte locaii, haurate mai ntunecat, nu conin pointeri spre elemente.

Cnd numrul cheilor memorate efectiv este relativ mic fa de numrul total de chei
posibile, tabelele de dispersie devin o alternativ eficient la adresarea direct ntr-un tablou,
deoarece se folosete un tablou de mrime proporional cu numrul de chei memorate
efectiv.
n loc s se foloseasc direct cheia ca indice n tablou, indicele este calculat pe baza
cheii, folosind o funcie de dispersie (hash), care face maparea spaiului de chei ntr-un spaiu
Funcia genereaz o adres printr-un calcul simplu, aritmetic sau logic asupra cheii sau
asupra unei pri a cheii.

S considerm o mulime cu valori care trebuie stocate n structura de date (aceste
valori sunt denumite chei) i un vector cu componente (denumit tabel hash).
Vom considera o funcie hash prin care se asociaz fiecrei chei un numr ntreg din
intervalul [0, 1] :
[0, 1]
Funcia hash are proprietatea c valorile ei sunt uniform distribuite n intervalul
specificat. Aceste valori vor fi utilizate ca indici n vectorul . Mai exact, cheia va fi plasat
n tabela hash pe poziia () .
4

Datorit faptului c spaiul de chei este de obicei mult mai mare dect spaiul de
adrese, se poate ntmpla ca mai multe chei s aib aceeai adres. Aceasta se numete
coliziune ntre nregistrri.

Figura 2.
Folosirea unei funcii de dispersie pentru a transforma chei n poziii din tabela de
dispersie. Cheile
2
i
5
se transform n aceeai poziie, deci sunt n coliziune.

5

Funcii hash

Metoda Diviziunii (restul mpririi la m)

() = %

n acest caz este indicat s evitm ca s fie de forma 2

(pentru c atunci () ar
avea ca valoare ultimii bii ai lui ). Sau s fie o putere a lui 10 (pentru c atunci () ar
depinde numai de o parte din cifrele lui ). Exceptnd cazul n care tim c toate secvenele
binare de lungime apar cu acceai probabilitate ca ultimi bii ai cheii, este de preferat s
utilizm o funcie n care se utilizeaz toi biii cheii.
Se face o analiz a valorilor pe care le poate lua i se alege o valoare pentru
ntr-un mod corespunztor.

Metoda nmulirii

() = [ ( ( ) ) ]

Se nmulete cheia cu un numr subunitar 0 < < 1, considerm partea fracionar
a lui , o nmulim cu i reinem doar partea ntreag a rezultatului.
Un avantaj al acestei metode este c nu exist valori particulare pentru care s
trebuiasc evitate ca la Metoda Diviziunii, prin urmare de obicei poate fi o putere a lui 2,
pentru a implementa eficient funcia hash.

Metoda probabilistic (Hashing-ul universal)

Dac un adversar rutcios va alege cheile astfel nct toate s aib aceeai valoare
pentru o anumit funcie hash, atunci obinem un timp de execuie liniar. Soluia ar fi s
alegem o funcie hash independent de cheile ce urmeaz a fi stocate.
Ideea de baz este s selectm funcia hash la ntmplare dintr-o list predefinit de
funcii hash la nceputul execuiei programului. Se numete familie universal de funcii hash
o mulime de funcii definite pe cu valori n {0,1, , 1} astfel nct pentru orice
pereche de chei , ( ) numrul funciilor hash din familie pentru care () = ()
este cel mult
||

## . Cu alte cuvinte, dac alegem aleator o funcie din aceast familie,

probabilitatea de obine o coliziune pentru cheile i este mai mic dect
1

.
Un exemplu care se comport foarte bine n practic este urmtorul: se genereaz
aleator un numr natural impar . Valoarea funciei pentru un ntreg se afl nmulind cu
i pstrnd cei mai semnificativi bii ai rezultatului (nmulirea se face pe 32 de bii, i
ignorm overflow).

6

I nterpretarea cheilor ca numere naturale

Majoritatea funciilor de dispersie presupun universul cheilor din mulimea
= 0,1,2, a numerelor naturale. Astfel, dac cheile nu sunt numere naturale, trebuie gsit
o modalitate pentru a le interpreta ca numere naturale.
De exemplu, o cheie care este un ir de caractere poate fi interpretat ca un ntreg ntr-
o baz de numeraie aleas convenabil. Prin urmare, identificatorul poate fi interpretat ca o
pereche de numere zecimale (112, 116), pentru c = 112 i = 116 n mulimea codurilor
ASCII; atunci exprimat ca un ntreg n baza 128 devine (112 128) +116 = 14452.
n mod obinuit, n orice aplicaie se poate crea direct o asemenea metod simpl de a
interpreta fiecare cheie ca un numr natural (posibil numr mare).

Coliziunile

Aa cum spuneam i mai devreme, datorit faptului c spaiul de chei este de obicei
mult mai mare dect spaiul de adrese, se poate ntmpla ca mai multe chei s aib aceeai
adres. Aceasta se numete coliziunentre nregistrri.
Prin urmare este necesar i un mecanism de rezolvare a coliziunilor. Exist dou
metode de rezolvare a coliziunilor.

Chaining (nlnuire)

Toate valorile sinonime (care au aceeai valoare hash) vor fi plasate ntr-o list
nlnuit. Astfel n vectorul pe poziia vom reine un pointer ctre nceputul listei
nlnuite formate din toate valorile pentru care () = .
Operaia de inserare se execut n (1) (se insereaz valoarea la nceputul listei
[()] ).
Operaia de cutare presupune cutarea elementului cu cheia n lista nlnuit
[()] .
Operaia de tergere presupune cutarea elementului cu cheia n lista nlnuit
[()] , apoi tergerea din list a acestuia.
Ultimele dou operaii au timpul de execuie proporional cu lungimea listei [()].
Analiznd complexitatea n cazul cel mai defavorabil, lungimea listei poate fi () (atunci
cnd toate elementele sunt sinonime).
Analiznd complexitatea n medie, observm c lungimea listei depinde de ct de
uniform distribuie funcia hash cheile.
Dac presupunem c funcia hash va distribui uniform valorile, atunci lungimea medie
a listei este

## (aceast valoare este denumit factor de ncrcare a tabelei), deci timpul de

execuie va fi (1 +

) .

7

n tabela hash nu sunt memorai pointeri, ci sunt memorate elementele mulimii .
Astfel n tabel se vor afla poziii ocupate cu elemente din i poziii libere (acestea vor fi
marcate cu o valoare special pe care o vom denumi ).
n acest caz, pentru a insera un element n tabela hash se vor executa mai multe
ncercri, pn cnd determinm o poziie liber, n care putem plasa elementul .
n acest caz, funcia hash va avea doi parametri: cheia i numrul ncercrii curente
(numerotarea ncercrilor va ncepe de la 0):
{0,1, . . . , 1} {0,1, . . . , 1}
Operaia de inserare: Pentru a insera elementul n tabela se examineaz n ordine
poziiile (, 0), (, 1), , (, 1). Aceast secven de poziii trebuie s fie o
permutare a mulimii {0,1, , 1}.
Operaia de cutare: Cutarea unui element n tabel presupune examinarea aceleiai
secvene de poziii ca i inserarea. Dac n tabel nu se efectueaz tergeri, cutarea se termin
fr succes la ntlnirea primei poziii libere.
Operaia de tergere: tergerea unui element dintr-o tabel hash este dificil. Nu
putem doar marca poziia pe care este plasat cheia ca fiind liber. n acest mod, cutare
oricrei chei pentru care pe parcursul inserrii am examinat poziia i am gsit-o ocupat se
va termina fr succes.
O soluie ar fi ca la tergerea unui element pe poziia respectiv s nu plasm valoarea
, ci o alt valoare special (pe care o vom denumi ). Funcia de inserare poate
fi modificat astfel nct s insereze elementul pe prima poziie pe care se afl sau
.
Dac alegem aceast soluie, timpul de execuie al cutrii nu mai este proporional cu
factorul de ncrcare a tabelei. Din acest motiv, tehnica de rezolvare a coliziunilor prin
nlnuire este mai utilizat pentru cazul n care structura de date suport i operaii de
tergere.

8

Distribuia cheilor

Pentru ca distribuia cheilor s fie uniform, funcia hash trebuie s genereze cu egal
probailitate oricare dintre cele ! permutri ale mulimii {1,2, . . . , 1}.
Pentru a determina secvena poziiilor de examinat se utilizeaz 3 tehnici. Fiecare
dintre aceste 3 tehnici garanteaz c pentru orice cheie secvena poziiilor de examinat este o
permutare a mulimii {0,1, . . . , 1}. Nici una dintre acestea nu asigur o distribuie perfect
uniform.

Examinarea liniar

Considernd o funcie hash obinuit
: {0,1, . . . , 1}
(denumit funcie hash auxiliar), tehnica examinrii liniare utilizeaz funcia:
(, ) = ( () + ) % .

Observaie
Deoarece prima poziie din secven determin ntreaga secven de poziii de
examinat, deducem c exist doar m secvene de examinare distincte.

Examinarea liniar este uor de implementat, dar genereaz un fenomen denumit
primary clustering (secvena de poziii ocupate devine mare, i astfel timpul mediu de
execuie al cutrii crete).

Examinarea ptratic

Examinarea ptratic utilizeaz o funcie hash de forma:
(, ) = () +
1
+
2

2
%
unde este funcia hash auxiliar, iar
1
i
2
0 sunt constante auxiliare.

Observaie
Aceast metod funcioneaz mai bine dect examinarea liniar, dar pentru a
garanta faptul c ntreaga tabel este utilizat, ,
1
i
2
trebuie s ndeplineasc anumite
condiii.

Hashing dublu

Hashing-ul dublu utilizeaz o funcie de forma:
(, ) =
1
+
2
() %
unde
1
i
2
sunt funcii hash auxiliare.
Pentru ca ntreaga tabel s fie examinat, valoarea
2
() trebuie s fie relativ prim
cu . O metod sigur este de a-l alege pe o putere a lui 2, iar
2
s produc numai valori
impare. Sau s fie un numr prim, iar
2
s produc numere < .

Observaie
Hashingul dublu este mai eficient dect cel liniar sau ptratic.

9

Hashing-ul perfect

Exist aplicaii n care mulimea cheilor nu se schimb (de exemplu, cuvintele
rezervate ale unui limbaj de programare, numele fiierelor scrise pe un CD, etc). Hashing-ul
poate fi utilizat i pentru probleme n care mulimea cheilor este static (odat ce au fost
inserate cheile n tabela hash, aceasta nu se mai schimb). n acest caz, timpul de execuie n
cazul cel mai defavorabil este (1).
Hashing-ul se numete hashing perfect dac nu exist coliziuni.

Hashing-ul perfect se realizeaz pe dou niveluri.

La primul nivel, este similar cu hashing-ul cu nlnuire: cele chei vor fi distribuite
cu ajutorul unei funcii hash n locaii.
Dar n loc de a crea o list nlnuit cu toate cheile distribuite n locaia , la cel de al
doilea nivel vom utiliza cte o tabel hash secundar

## care are asociat o funcie hash

pentru fiecare locaie n care exist coliziuni.
Pentru a garanta faptul c nu vor exista coliziuni n tabela hash secundar,
dimensiunea

## a tabelei hash secundare trebuie s fie cel puin egal cu

2
(unde

este
numrul de chei care sunt distribuite n locaia ).
Evident, descrierea grupurilor de la primul nivel trebuie s conin i funcia hash
aleas pentru grupul respectiv, precum i dimensiunea spaiului de memorie alocat tabelei
hash secundare.
O alegere a funciei hash dintr-o familie universal de funcii hash asigur c
dimensiunea total a spaiului de memorie utilizat este ().

10

Hash-uri n STL

hash
hash_map
hash_multimap
hash_set
hash_multiset

Aplicaii

Algoritmul Rabin - Karp

Fie un ir de caractere i un pattern de caractere.
S se verifice dac apare sau nu ca subsecven n irul .

Soluie:
Fie numrul de caractere distincte care apar n . Un ir de lungime poate fi
considerat un numr n baza +1 avnd cifre (se folosesc cifre de la 1 la ).
Se asociaz pattern-ului o valoare (irul de caractere este considerat ca un numr
ntreg n baza +1).
Pentru fiecare secven de caractere din irul se calculeaz

, valoarea n baza
+1 a subsecvenei din care ncepe la poziia i ( [ +1] ). Evident, =

dac
i numai dac = [ +1].
Valorile

## pentru = 1, +1 se pot calcula astfel:

+1
= ( +1) (

( + 1)
1
[]) +[ +] .
Singura dificultate const n faptul c i

## pot fi numere foarte mari. Prin urmare,

operaiile cu ele nu se execut n timp constant.
Se va lucra cu i

## mod , unde este un numr prim convenabil ales, aadar se

folosete o funcie de dispersie. Pot aprea probleme deoarece =

nu
implic faptul c =

## (apar coliziuni). Dar dac

, atunci sigur

.
Aadar, algoritmul Rabin - Karp este unul probabilistic, eficiena n detectarea
potrivirii pattern-ului depinznd de funcia de dispersie. Pentru a elimina potrivirile false,
se poate aplica o verificare normal pentru fiecare potrivire detectat sau se pot folosi mai
multe funcii de dispersie.

11

Alte probleme

Hashuri (Infoarena)
Loto (Infoarena)
Eqs (Infoarena)
Oite (Infoarena)
Strmatch (Infoarena)
Abc2 (Infoarena)
String (Infoarena)
Circular (Campion)
Repeat (Campion)

Registration system (Codeforces)
Ograzi (Infoarena)
Rk (Infoarena)
Patrate3 (Infoarena)
Flori2 (Infoarena)
Banana (Infoarena)
Subsecvente (Campion)
Take5 (Infoarena)
Petr# (Codeforces)

Legturi

MIT - Lecture 7: Hashing, Hash Functions
MIT - Lecture 8: Universal Hashing, Perfect Hashing
Tabele hash prezentare detaliata (Infoarena)
Hash functions, tables and primes - oh my! (articol)
Stack Exchange Computer Science (discuie)
Stack Exchange Mathematics (discuie)
Stackoverflow (discuie)
Got-fu? (articol)
Hash table (Wikipedia)

Bibliografie

Thomas H. Cormen, Charles E. Leiserson, Ronald R. Rivest, Introducere n
algoritmi, Editura Computer Libris Agora, Cluj Napoca, 2000
Emanuela Cerchez, Marinel erban, Programarea n limbajul C/C++ pentru
liceu volumul III, Editura Polirom, Iai, 2006
Dana Lica, Mircea Paoi, Fundamentele programrii volumul III, Editura
L&S SOFT, Bucureti, 2006.

Alexandru Cohal
alexandru.cohal@yahoo.com
alexandru.c04@gmail.com
Decembrie 2013