Ahoj! Hašovací tabulka (anglicky hash table nebo hash map) je opravdu šikovná datová struktura. Představ si ji jako kouzelnou kartotéku, která ti umožní bleskově najít, přidat nebo smazat informace.
Pojďme se na to podívat podrobněji:
Základní myšlenka:
Cílem hašovací tabulky je ukládat data ve formě párů klíč-hodnota (key-value). Klíč je unikátní identifikátor, podle kterého chceme data rychle najít, a hodnota jsou samotná data, která k tomuto klíči patří.
Například:
* Klíč: "telefonní_číslo_jana_novaka", Hodnota: "777 123 456"
* Klíč: "produkt_id_123", Hodnota: {název: "Super Kniha", cena: 299, ...}
Jak to funguje? Klíčové komponenty:
-
Pole (Array): V srdci hašovací tabulky je obyčejné pole. Každá pozice (index) v tomto poli se často nazývá "kapsa" (bucket) nebo "slot". Velikost tohoto pole je na začátku nějak určena.
-
Hašovací funkce (Hash Function): Tohle je ten "kouzelný" prvek. Hašovací funkce vezme tvůj klíč (což může být text, číslo, cokoliv) a převede ho na celé číslo. Toto číslo se pak typicky upraví (např. pomocí operace modulo % velikostí pole), aby odpovídalo platnému indexu v našem poli (kapse).
- Důležité vlastnosti dobré hašovací funkce:
- Deterministická: Pro stejný klíč musí vždy vrátit stejný haš (stejný index po úpravě).
- Rychlá: Výpočet haše by měl být velmi rychlý.
- Rovnoměrná distribuce: Měla by se snažit co nejlépe "rozházet" různé klíče do různých kapes pole, aby se minimalizovaly kolize (o tom za chvíli).
-
Páry Klíč-Hodnota: To jsou data, která ukládáme.
Procesy v hašovací tabulce:
Problém: Kolize (Collisions)
Co když dva různé klíče (např. "Alice" a "Bob") dají po aplikaci hašovací funkce a následné úpravě na index stejný index v poli? Tomu se říká kolize. Je to nevyhnutelné, protože počet možných klíčů je obvykle mnohem větší než počet kapes v poli.
Řešení kolizí:
Existuje několik strategií, jak kolize řešit:
-
Řetězení (Chaining / Separate Chaining):
- Každá kapsa v poli neobsahuje přímo hodnotu, ale ukazatel na spojový seznam (nebo jinou datovou strukturu, třeba dynamické pole) prvků.
- Pokud dojde ke kolizi (více klíčů se mapuje na stejný index), nový pár klíč-hodnota se prostě přidá na konec tohoto spojového seznamu v dané kapse.
- Při vyhledávání: vypočítáš index, projdeš spojový seznam v dané kapse a porovnáváš klíče, dokud nenajdeš ten správný.
-
Otevřené adresování (Open Addressing):
- Pokud je cílová kapsa obsazená, zkusí se najít jiná volná kapsa v poli podle nějakého pravidla.
- Příklady pravidel:
- Lineární zkoušení (Linear Probing): Zkus následující kapsu (index + 1), pak index + 2, atd., dokud nenajdeš volnou.
- Kvadratické zkoušení (Quadratic Probing): Zkus index + 1^2, pak index + 2^2, atd.
- Dvojité hašování (Double Hashing): Použije se druhá hašovací funkce k určení "kroku", o kolik se posunout při hledání volné kapsy.
- Při vyhledávání: musíš postupovat stejným "zkoušecím" způsobem, dokud prvek nenajdeš nebo nenarazíš na prázdnou kapsu (což znamená, že tam prvek není).
Výhody hašovacích tabulek:
- Rychlost: V průměrném případě jsou operace vložení, vyhledání a smazání velmi rychlé – teoreticky v konstantním čase O(1). To znamená, že doba potřebná k operaci nezávisí na počtu prvků v tabulce (pokud je hašovací funkce dobrá a kolizí je málo).
- Flexibilita: Klíče mohou být různého typu.
Nevýhody hašovacích tabulek:
- Kolize: Špatná hašovací funkce nebo příliš mnoho prvků v malé tabulce může vést k mnoha kolizím, což degraduje výkon. V nejhorším případě (všechny klíče kolidují do jedné kapsy) se operace mohou zpomalit na O(n), kde n je počet prvků (např. u řetězení procházíš dlouhý seznam).
- Paměť: Pokud je pole příliš velké a málo zaplněné, plýtvá se pamětí. Pokud je příliš malé, roste počet kolizí. Proto hašovací tabulky často implementují mechanismus změny velikosti (resizing) – když se tabulka příliš zaplní (tzv. load factor překročí určitou mez), vytvoří se nová, větší tabulka a všechny prvky se do ní znovu "přehašují". To je časově náročná operace.
- Není uspořádaná: Prvky v hašovací tabulce nejsou typicky uloženy v žádném konkrétním pořadí (např. podle klíče). Pokud potřebuješ procházet prvky v seřazeném pořadí, hašovací tabulka není ideální volba (lepší by byl např. binární vyhledávací strom).
Příklad z reálného světa:
Představ si slovník cizích slov.
* Klíč: Cizí slovo (např. "table")
* Hodnota: Překlad a popis (např. "stůl")
* Hašovací funkce: Vezme slovo "table", nějak ho zpracuje a řekne ti, že máš hledat na stránce (indexu) č. 58.
* Kolize: Pokud by jiné slovo také směřovalo na stránku 58, musel bys na té stránce mít seznam všech slov, která tam patří, a najít to správné.
Hašovací tabulky jsou základem mnoha programovacích jazyků a systémů – například slovníky (dictionaries) v Pythonu, HashMap v Javě, objekty v JavaScriptu (do jisté míry), databázové indexy, keše (caches) atd.
Doufám, že ti to takhle stačí pro představu! Kdybys měl jakékoli další otázky, klidně se ptej.