12. Hashovací tabulky

12 - Hashovací tabulky

Připomenutí teorie

Přednášky 12 a 13 v oddíle Přednášky.

Hashing

Hashing (Rozptylování, Hashování) je klíčová metoda pro implementaci slovníku. Slovník (dictionary) je datová struktura sloužící k ukládání různorodých dat tak, abychom je byli schopni rychle nalézt. Jeho rychlost vychází právě z užití rozptylové (hashovací) funkce. Ta vrací adresy na které umisťujeme jednotlivé prvky (za konstantní čas)

Rozptylová (hashovací) funkce je funkce hh která danému datovému bodu xx přiřadí jednoznačně adresu h(x)h(x) (hash). Ideálně chceme aby:

  1. Byla rychlá

  2. Vedla k minimu kolizí

  3. Rovnoměrně využívala adresy (i blízké klíče na vzdálené adresy)

  4. Umisťovala prvky cca “náhodně”

Funkce musí pro stejný klíč vrátit stejnou adresu (stejný hash) neboli x=y    h(x)=h(y)x = y \implies h(x) = h(y). Může se ale stát, že dva různé klíče budou mít stejnou adresu xyh(x)=h(y)x \ne y \land h(x) = h(y). Tomuto případu se říká kolize a kolidujícím klíčům říkáme synonyma.

Kolize lze řešit různými způsoby:

  • Zřetězené hashování (Chaining) - Na každé adrese tvoříme spojovaný seznam klíčů se stejnou adresou (hashem).

  • Otevřené hashování (Open-address hashing) - vše vkládáme do stejné tabulky, při kolizi zkoušíme pozice o iki \cdot k polí dál, kde ii je počet kolizí daného klíče a kk se určí pomocí:

    • Linear probing - kk je konstanta, tedy zkoušíme vždy pozici o kk dále (modulo velikost tabulky);

    • Double hashing - k=h2(x)k = h_2(x), čili máme další rozptylovací funkci h2h_2, která nám určí (povětšinou) rozdílná kk pro rozdílná xx.

  • Srůstající hashování

Z hlediska složitostí se uvažuje že průměrný případ vložení, hledání i mazání klíče jako Θ(1)\Theta(1), nejhorší případ je ale O(n)\mathrm{O}(n), kvůli kolizím (kromě vkládání do zřetězeného rozptylování, tam je Θ(1)\Theta(1), protože vkládáme vždy na začátek seznamu).

Srůstající hashování (přednáška po Vánocích)

Anglicky coalesced hashing, je hashování podobné otevřenému, kde vkládáme prvky do jedné tabulky a v případě kolizí je pak vkládáme odzadu. Každý prvek má navíc ještě ukazatel, který ukazuje na pozici dalšího prvku kde hledat v případě kolize. V tomto je srůstající hashování zase podobné zřetězenému. Jednotlivé metody můžeme dělit podle toho, zda je na konci pole tzv. sklep, tedy část pole kterou nelze adresovat pomocí hashovací funkce (lze do ní vkládat jen při kolizích).

  • Bez sklepa

    • LISCH - Late Insert Standard Coalesced Hashing - na pozici právě přidaného prvku ukazuje poslední prvek se kterým byla kolize (poslední v řetězu)

    • EISCH - Early Insert Standard Coalesced Hashing - na pozici právě přidaného prvku ukazuje první prvek se kterým došlo ke kolizi, přidaný prvek ukazuje na ten co býval druhý v řetězu (pokud existuje).

  • Se sklepem

    • LICH - Late Insert Coalesced Hashing - jako LISCH, ale nejprve vkládáme kolize do sklepa (protože je na konci)

    • EICH - Early Insert Coalesced Hashing - jako EISCH, ale nejprve vkládáme kolize do sklepa (protože je na konci)

    • VICH - Variable Insert Coalesced Hashing - dokud vkládáme kolize do sklepa, vkládáme je podle LICH. Jakmile je sklep plný, vkládáme těsně za poslední prvek v řetězu který je ve sklepě. Když žádný z řetězu ve sklepě není, vkládáme podle EICH.

Jupyter notebook

Všechny následující úlohy jsou také v Jupyter notebooku.

Také na Google Colab.

Řešení jsou dostupná v Jupyter notebooku.

Také na Google Colab.

Řešené úlohy

Řešená úloha 1: Do nejprve prázdné tabulky s rozptylovací funkcí h(x)=x mod 6h(x) = x \ \mathrm{mod}\ 6 byly vloženy následující prvky v uvedeném pořadí a celkem nastala jedna kolize.
a) 6,12,246, 12, 24
b) 24,6,1224, 6, 12
c) 1,7,61, 7, 6
d) 5,6,75, 6, 7
e) 2,3,42, 3, 4

Řešení

c), kolidují klíče 1 a 7.


Rozptylování s vnějším zřetězením

Řešená úloha 2: Pro danou rozptylovací funkci h(k)=k mod 5h(k) = k \ \mathrm{mod}\ 5 zvolte velikost tabulky a nakreslete stav po vložení prvků následující posloupnosti při vnějším zřetězení prvků.

20,9,0,17,22,15,23,18,8,720, 9, 0, 17, 22, 15, 23, 18, 8, 7

Řešení

11_04_chaining.svg


Řešená úloha 3: Doplňte implementaci zřetězeného hashování v Jupyter notebooku.

Řešení

Otevřené rozptylování

Řešená úloha 4: Vložte následudící posloupnost prvků do hashovací tabulky o velikosti m=11m = 11, pomocí otevřeného hashování.

5,6,1,10,13,18,14,30,0,8,165, 6, 1, 10, 13, 18, 14, 30, 0, 8, 16

Vkládejte najednou do 3 tabulek, ve dvou uvažujte linear probing s inkrementem 1 a 3, v poslední provádějte double hashing. Hashovací funkce:

h1(x)=x mod 8,h2(x)=(x mod 7)+1h_1(x) = x \ \mathrm{mod}\ 8, h_2(x) = (x \ \mathrm{mod}\ 7) + 1
Řešení

0

1

2

3

4

5

6

7

8

9

10

Linear +1

0

1

10

18

8

5

6

13

14

30

16

Linear +3

18

1

10

0

30

5

6

8

13

14

16

Double hash.

0

1

10

16

30

5

6

18

13

14

8

Počet kolizí při vkládání:

Vkládané číslo

5

6

1

10

13

18

14

30

0

8

16

Celkem

Linear +1

0

0

0

0

2

1

2

3

0

4

10

22

Linear +3

0

0

0

0

1

3

1

3

1

6

7

22

Double hashing

0

0

0

0

2

1

3

3

0

5

1

15


Řešená úloha 5: Doplňte implementaci otevřeného hashování v Jupyter notebooku.

Řešení

Srůstající hashování

Řešená úloha 6: Uvažujte hash funkci h(x)=x mod 9h(x) = x \ \textrm{mod} \ 9. Vložte do hashovací tabulky čísla z posloupnosti:

9,11,18,27,29,36,43,45,509, 11, 18, 27, 29, 36, 43, 45, 50

Jak bude tabulka vypadat pro EISCH a jak pro LISCH?

LISCH

index

0

1

2

3

4

5

6

7

8

hodnota

9

50

11

45

43

36

29

27

18

následovník

8

-

6

1

3

4

-

5

7

EISCH

index

0

1

2

3

4

5

6

7

8

hodnota

9

50

11

45

43

36

29

27

18

následovník

3

7

6

5

8

1

-

4

-


Řešená úloha 7: Doplňte implementaci metody get pro srůstající hashování v Jupyter notebooku.

Řešení

Řešená úloha 8: Doplňte implementaci metody insert pro LISCH hashovací tabulku v Jupyter notebooku.

Řešení

Řešená úloha 9: Doplňte implementaci metody insert pro EISCH hashovací tabulku v Jupyter notebooku.

Řešení

Řešená úloha 10: Uvažujte hash funkci h(x)=x mod 7h(x) = x \ \textrm{mod} \ 7 a sklep o velikosti 2. Vložte do hashovací tabulky čísla z (stejné) posloupnosti:

9,11,18,27,29,36,43,45,509, 11, 18, 27, 29, 36, 43, 45, 50

Jak bude tabulka vypadat pro EICH, LICH a jak pro VICH?

LICH

index

0

1

2

3

4

5

6

7

8

hodnota

50

29

9

45

11

43

27

36

18

následovník

-

7

-

-

8

0

-

5

-

EICH

index

0

1

2

3

4

5

6

7

8

hodnota

50

29

9

45

11

43

27

36

18

následovník

5

0

-

-

8

7

-

-

-

VICH

index

0

1

2

3

4

5

6

7

8

hodnota

50

29

9

45

11

43

27

36

18

následovník

5

7

-

-

8

-

-

0

-


Řešená úloha 11: Co musíme změnit na implementaci LISCH hashovací tabulky, abychom dostali LICH hashovací tabulku v Jupyter notebooku.

Řešení

Nic, stačí používat hashovací funkci, které nebude adresovat celou tabulku. Neadresovaná část tabulky se tak stane sklepem.


Řešená úloha 12: Co musíme změnit na implementaci EISCH hashovací tabulky, abychom dostali EICH hashovací tabulku v Jupyter notebooku.

Řešení

Nic, stačí používat hashovací funkci, které nebude adresovat celou tabulku. Neadresovaná část tabulky se tak stane sklepem.


Řešená úloha 13: Projděte implementaci metody insert pro VICH hashovací tabulku v Jupyter notebooku.


Benchmarky srůstajícího hashování

Řešená úloha 14: Srovnejte počty přístupů do tabulky mezi jednotlivými metodami srůstajícího hashování spuštěním kódu ze sekce "Benchmarky srůstajícího hashování" v Jupyter notebooku.

Řešení

Pro čtení je nejvýhodnější VICH a pro zápis je nejvýhodnější EICH.


Hashování objektů

Řešená úloha 15: Doplňte implementaci metody hash třídy Node v Jupyter notebooku.

Řešení

Další úlohy

Zřetězené rozptylování

Úloha 16: Pro danou rozptylovací funkci h(k)=k mod 9h(k) = k \ \mathrm{mod}\ 9 zvolte velikost tabulky a nakreslete stav po vložení prvků následující posloupnosti při vnějším zřetězení prvků.

12,19,24,17,4,21,5,16,11,212, 19, 24, 17, 4, 21, 5, 16, 11, 2


Otevřené rozptylování

Úloha 17: Do rozptylovací tabulky velikosti 10 s otevřeným rozptylováním a s rozptylovací funkcí h(k)=k mod 7h(k) = k \ \mathrm{mod}\ 7 vložte následujících 6 klíčů.

Použijte strategii Linear Probing s inkrementem 1.

12,23,15,29,22,1412, 23, 15, 29, 22, 14


Úloha 18: Do rozptylovací tabulky velikosti 11 s otevřeným rozptylováním a s rozptylovací funkcí h(k)=k mod 8h(k) = k \ \mathrm{mod}\ 8 vložte následujících 6 klíčů.

Použijte strategii Linear Probing s inkrementem 3.

10,16,15,31,23,1410, 16, 15, 31, 23, 14


Úloha 19: Do do prázdné tabulky velikosti NN, vkládejte klíče: 27,23,2,28,17,7,14,30,12,21,11,127, 23, 2, 28, 17, 7, 14, 30, 12, 21, 11, 1 Určete počet kolizí v uvedených variantách:

a) N=13N = 13, Linear Probing s inkrementem 1.
b) N=17N = 17, Linear Probing s inkrementem 1.
c) N=17N = 17, Linear Probing s inkrementem 5.
d) N=13N = 13, Double Hashing, h2(k)=1+k mod 3h_2(k) = 1 + k \ \mathrm{mod}\ 3.
e) N=13N = 13, Double Hashing, h2(k)=1+k mod 5h_2(k) = 1 + k \ \mathrm{mod}\ 5.
f) N=17N = 17, Double Hashing, h2(k)=1+k mod 5h_2(k) = 1 + k \ \mathrm{mod}\ 5.


Srůstající hashování

Úloha 20:

Uvažujte hash funkci h(x)=x mod 10h(x) = x \ \textrm{mod} \ 10. Vložte do hashovacích tabulek čísla z posloupnosti:

10,12,20,23,32,39,4010, 12, 20, 23, 32, 39, 40

Jak bude tabulka vypadat pro EISCH a jak pro LISCH?


Úloha 21:

Uvažujte hash funkci h(x)=x mod 8h(x) = x \ \textrm{mod} \ 8 a sklep o velikosti 2. Vložte do hashovacích tabulek čísla z (té samé) posloupnosti:

10,12,20,23,32,39,4010, 12, 20, 23, 32, 39, 40

Jak bude tabulka vypadat pro EICH, LICH a jak pro VICH?


Úloha 22:

Předpokládejme, že v tabulkách získaných v příkladech 1 a 2, (případně 3 a 4) vyhledáváme pouze klíče v nich uložené a každý klíč stejně často. Která z těchto tabulek je nejvýhodnější?


Je na stránce chyba?

Nahlašte nám ji

Máte otázky nebo připomínky?

Edit Dejte nám vědět