A hash-tábla az információk hatékony tárolására és gyors lekérdezésére szolgáló adatszerkezet. A számítástechnikában az információk vagy adatok nyilvántartására szolgáló ilyen eszközöket adatszerkezeteknek nevezik. A hash-tábla olyan adatszerkezet, amely hash-funkciót használ az adatok helyének meghatározására: minden bejegyzéshez tartozik egy kulcs (például egy név) és egy hozzá tartozó érték (például egy telefonszám vagy más adat).
Hogyan működik röviden
Az adatokat általában egy egyszerű tömbben tároljuk, amelyet elképzelhetünk sok, számozott dobozként (indexek 0-tól felfelé). A hash-függvény a kulcsból számít egy számot (hash értéket), majd ezt a számot átalakítjuk a tömb indexére (például maradékos osztással). Így a kulcs alapján közvetlenül megmondható, melyik dobozba kerüljenek az adatok — vagy hol keressük őket.
Hash-függvény és tulajdonságai
- Determininsztikus: ugyanarra a kulcsra mindig ugyanazt az indexet kell adja.
- Gyors: a hash számítása legyen O(1) időben.
- Jól elosztott: a kulcsok egyenletesen osszanak el a táblában, hogy elkerüljük a halmozódást.
Egy jó hash-függvény minimalizálja az ütközéseket (amikor különböző kulcsok ugyanarra az indexre kerülnek), és gyorsan számítható. A gyakorlatban kriptográfiai hash-eket ritkábban használunk adatstruktúrákhoz, mert ezek lassabbak és más célra készültek; helyette egyszerűbb, gyors, de jól elosztó függvényeket alkalmaznak.
Ütközések és megoldási módok
Ütközés akkor fordul elő, ha két különböző kulcs ugyanazt az indexet kapja. A leggyakoribb ütközés-kezelési stratégiák:
- Keverés láncolással (chaining): minden tömbelemhez egy láncot (pl. lista) társítunk, és az ugyanarra az indexre kerülő bejegyzéseket abba tároljuk. Egyszerű és rugalmas megoldás.
- Nyílt címzés (open addressing): amikor ütközés történik, a táblán belül keresünk következő üres helyet. Ennek változatai:
- Lineáris próba (linear probing)
- Kvadratikus próba (quadratic probing)
- Dupla hash-elés (double hashing)
- Rehashing: ha túl sok az ütközés (vagy a terhelési tényező nagy), a táblát nagyobbra cseréljük és újra kiszámítjuk az indexeket.
Műveletek és időkomplexitás
- Beszúrás (insert): a kulcs hash-ét kiszámoljuk, és behelyezzük az adott indexre (ütközés esetén a kiválasztott stratégia szerint).
- Keresés (search): a kulcs hash-ét kiszámoljuk és az indexnél megkeressük a megfelelő bejegyzést.
- Törlés (delete): a bejegyzést eltávolítjuk; nyílt címzésnél külön gondoskodni kell arról, hogy a törlés ne törje meg a keresési láncot.
Átlagban a hash-táblák lekérdezései, beszúrásai és törlései O(1) idő alatt működnek, ha a terhelés alacsony és a hash-függvény jó. Rossz esetben (például sok ütközés vagy célzott hash-összeomlás) az idő komplexitás O(n) lehet.
Terhelési tényező és átméretezés
A terhelési tényező (load factor) a táblában tárolt elemek száma és a tábla méretének hányadosa. Ha ez a tényező túl magas, nő az ütközések valószínűsége, ezért sok implementáció automatikusan növeli a tábla méretét és újrahash-el (rehashing). Átméretezéskor általában a tábla méretét megduplázzák, és minden kulcs új indexet kap az új méretre.
Alkalmazások és példák
A hash-táblák gyakran gyorsabbak, mint más keresési struktúrák (például bináris keresőfák) átlagos esetben, ezért számos programozási feladatnál használják őket:
- asszociatív tömbök és szótárak
- adatbázisokhoz kapcsolódó indexelés
- gyorsítótárak (cache)
- halmazok implementálása
- szimbólumtáblák fordítókban, konfigurációs beállítások tárolása, stb.
Példa: egy telefonkönyv esetén a név a kulcs, a telefonszám az érték — a hash-függvény a névből számít egy indexet, így gyorsan megtalálható a szám.
Biztonsági megfontolások és implementációs tippek
- Hash flooding: ha a támadó tudja a hash-függvényt, sok ütközést generálhat, ami a teljesítményt lerontja. Emiatt modern rendszerek gyakran használnak véletlen kiinduló értékeket (salting) vagy adaptív hash-elést.
- Memória vs. sebesség: láncolásnál több memória kell a listastruktúrák tárolásához; nyílt címzésnél sűrűbben kell átméretezni. Az alkalmazás igényei alapján válasszunk stratégiát.
- Iterálás sorrendje: hash-táblák általában nem garantálják az elemek rendezett sorrendjét; ha rendezett iterációra van szükség, használjunk rendezett struktúrát vagy kiegészítő mechanizmust.
- Nyelvek implementációi: legtöbb programozási nyelv beépített, optimalizált hash-tábla implementációval rendelkezik (pl. Python dict, Java HashMap). Ezeket érdemes használni, kivéve speciális teljesítmény- vagy memóriaigény esetén.
Összegzés
A hash-tábla egy rendkívül hasznos, kulcs-érték alapú adatszerkezet, amely megfelelő hash-függvény és ütközés-kezelés mellett átlagosan állandó időben (O(1)) képes beszúrásra, keresésre és törlésre. Gyakran használják asszociatív tömbök, gyorsítótárak, adatbázisok és halmazok implementálására. Fontos figyelembe venni a terhelési tényezőt, az ütközések kezelését, valamint biztonsági kockázatokat (például hash flooding) a megbízható és hatékony működéshez.

