Rozptylovací tabulky

Podobné dokumenty
Datové struktury 2: Rozptylovací tabulky

Návrh designu: Radek Mařík

Adresní vyhledávání (přímý přístup, zřetězené a otevřené rozptylování, rozptylovací funkce)

HASHING GENERAL Hashovací (=rozptylovací) funkce

Spojový seznam. Jan Kybic.

Vyhledávání, zejména rozptylování

Stromy. Jan Kybic.

Prioritní fronta, halda

Základy algoritmizace. Hašování

Úvod. Úvod do programování. Úvod. Hashovací tabulky

Třetí skupina zadání projektů do předmětu Algoritmy II, letní semestr 2017/2018

POZOR klíč NENÍ index (adresa), ale podle klíče se hodnoty ukládají na indexy (adresy).

vyhledávací stromové struktury

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

HASHING GENERAL Hashovací (=rozptylovací) funkce

Třídění a vyhledávání Searching and sorting

vyhledávací stromové struktury

SPJA, cvičení 1. ipython, python, skripty. základy syntaxe: základní datové typy, řetězce. podmínky: if-elif-else, vyhodnocení logických výrazů

Algoritmy a datové struktury

Jazyk C++ II. STL knihovna kontejnery část 2

boolean hasnext() Object next() void remove() Kolekce

Konečný automat. Jan Kybic.

Semestrální práce 2 znakový strom

IB111 Úvod do programování skrze Python

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Algoritmizace Hashing II. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

NPRG030 Programování I, 2018/19 1 / :03:07

Časová složitost / Time complexity

Vestavěné nástroje Pythonu

Tabulka. Často jde nejenom o dynamickou množinu, ale i statickou množinu. Matematické tabulky statická množina

Programování v Pythonu

5. Vyhledávání a řazení 1

Da D to t v o é v ty t py IB111: Datové typy

Základní informace o předmětu Otázka:

Dynamické datové struktury IV.

Algoritmy výpočetní geometrie

Topics. Vyhledávání, zejména rozptylování. Slovník - Dictionary. Vyhledávání. Rozptylování - Hashing. Rozptylování - Hashing

Algoritmy I, složitost

Lekce 4. Kolekce. Kolekce - seznamy, N-tice a slovníky. C2184 Úvod do programování v Pythonu podzim 2016

Programování v Pythonu

Náplň. v Jednoduché příklady na práci s poli v C - Vlastnosti třídění - Způsoby (algoritmy) třídění

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

Množina v C++ (set, multiset).

Rekurze a rychlé třídění

Hašování (Vyhledávání metodou transformace klíče)

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Stromy. Jan Hnilica Počítačové modelování 14

Programování: základní konstrukce, příklady, aplikace. IB111 Programování a algoritmizace

Šablony, kontejnery a iterátory

Databázové systémy Cvičení 5.2

1. Databázové systémy (MP leden 2010)

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Kombinatorika, výpočty

Spojová implementace lineárních datových struktur

součet cvičení celkem. známka. Úloha č.: max. bodů: skut. bodů:

Dynamické datové struktury III.

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Časová a prostorová složitost algoritmů

Programování v C++, 2. cvičení

AVL stromy. pro každý uzel u stromu platí, že rozdíl mezi výškou jeho levého a pravého podstromu je nejvýše 1 stromy jsou samovyvažující

Databáze I. 5. přednáška. Helena Palovská

Využití OOP v praxi -- Knihovna PHP -- Interval.cz

Základní datové struktury

map, multimap - Asociativní pole v C++.

Zpracování deklarací a přidělování paměti

Standardní algoritmy vyhledávací.

ALS1 Přednáška 1. Pravěpodobnost, náhodná proměnná, očekávaná hodnota náhodné proměnné, harmonická čísla

Binární vyhledávací stromy pokročilé partie

Zadání k 2. programovacímu testu

SQL tříhodnotová logika

Algoritmizace prostorových úloh

Algoritmizace a programování

Michal Krátký. Úvod do programování. Cíl kurzu. Podmínky získání zápočtu III/III

Abstraktní datové typy II.

TGH07 - Chytré stromové datové struktury

Potřebovali bychom tedy umět do heše přidávat nové hodnoty, najít hodnotu pro

Dynamické datové struktury I.

Robert Haken [MVP ASP.NET/IIS, MCT] software architect, HAVIT, Základní algoritmy v praxi

Algoritmizace prostorových úloh

Pole a kolekce. v C#, Javě a C++

Dynamické programování

Složitost algoritmů. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava

IB111 Úvod do programování skrze Python Přednáška 7

PB161 Programování v jazyce C++ Přednáška 3

Organizace a zpracování dat I

George J. Klir Vilem Vychodil (Palacky University, Olomouc) State University of New York (SUNY) Binghamton, New York 13902, USA

IAJCE Přednáška č. 9. int[] pole = new int[pocet] int max = pole[0]; int id; for(int i =1; i< pole.length; i++) { // nikoli 0 if (Pole[i] > max) {

IAJCE Přednáška č. 8. double tprumer = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7; Console.Write("\nPrumerna teplota je {0}", tprumer);

Základy algoritmizace. Pattern matching

Tabulka. Datová struktura, která umožňuje vkládat a později vybírat informace podle identifikačního klíče. Mohou být:

Fronta (Queue) Úvod do programování. Fronta implementace. Fronta implementace pomocí pole 1/4. Fronta implementace pomocí pole 3/4

Datové struktury. alg12 1

Šablony, kontejnery a iterátory

Pokročilá algoritmizace amortizovaná složitost, Fibonacciho halda, počítačová aritmetika

Algoritmy II. Otázky k průběžnému testu znalostí

Různé algoritmy mají různou složitost

2 Datové struktury. Pole Seznam Zásobník Fronty FIFO Haldy a prioritní fronty Stromy Hash tabulky Slovníky

Python profesionálně: dynamické parametry, generátory, lambda funkce... with. Dynamické parametry

IB111 Základy programování Radek Pelánek

Transkript:

Rozptylovací tabulky Hash tables Jan Kybic http://cmp.felk.cvut.cz/~kybic kybic@fel.cvut.cz 2016 1 / 31

Rozptylovací tabulka Hash table Rozptylovací tabulka = implementace množiny / asociativního pole + velmi rychlé vkládání i hledání, O(1) neudržuje uspořádání (hledání maxima/minima) méně efektivní využití paměti Co je to hash? hash rozemlít, rozsekat, sekané maso, haše,... hašiš hash function rozptylovací/transformační/hašovací/hešovací/ funkce: objekt celé číslo hash / fingerprint haš/heš, otisk 2 / 31

Rozptylovací tabulka (Hash table) Základní myšlenky a vlastnosti pole m přihrádek (slots) pro ukládání položek. položka (item) = klíč (key) + hodnota (value) klíč je unikátní rozptylovací funkce (hash function) : ϕ: klíč číslo přihrádky 0... m 1 více položek v jedné přihrádce = kolize (collision/clash) operace jsou rychlé, protože víme, v které přihrádce hledat v každé přihrádce je jen omezený počet položek 3 / 31

Relativní naplnění tabulky (load factor) Průměrný počet položek na přihrádku load factor λ = počet položek n počet přihrádek m velké λ hodně kolizí zpomalení operací malé λ hodně prázdných položek nevyužitá paměť 4 / 31

Příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m = x % m Vložíme čísla Vznikne tabulka x 54 26 93 17 77 31 ϕ(x) 10 4 5 6 0 9 0 1 2 3 4 5 6 7 8 9 10 77 26 93 17 31 54 Relativní naplnění λ = 6/11 0.54 5 / 31

Rozptylovací funkce Hash function Nutné vlastnosti Stejné klíče musí mít stejný otisk x = y ϕ(x) = ϕ(y) Neměnnost / nenáhodnost / konstantnost / opakovatelnost Požadované vlastnosti Rychlost výpočtu Různé klíče mají mít pokud možno různý otisk x y velká P [ ϕ(x) ϕ(y) ] každý klíč jiný otisk = perfect hashing rovnoměrné využití všech přihrádek pravděpodobnost zvolení konkrétní přihrádky 1/m (i pro strukturované vstupy) malé množství kolizí Kvalitu lze ověřit experimentálně. Souvislost s kryptografií a náhodnými čísly. 6 / 31

Rozptylovací funkce Pro celá čísla ϕ(x) = x mod m = x % m Pro znaky ord(c) % m Pro k-tice ϕ ( (x 1, x 2,..., x k ) ) k = x i p i 1 mod m kde p je vhodné prvočíslo dostatečně velké a nesoudělné s m. i=1 7 / 31

Rozptylovací funkce Pro celá čísla ϕ(x) = x mod m = x % m Pro znaky ord(c) % m Pro k-tice ϕ ( (x 1, x 2,..., x k ) ) k = x i p i 1 mod m kde p je vhodné prvočíslo dostatečně velké a nesoudělné s m. i=1 def hash_string(x,m): h=0 for c in x: h=((h*67)+ord(c)) % m return h Soubor hashing.py. 7 / 31

Rozptylovací funkce v Pythonu Funkce hash pro neměnné hodnoty (immutable): čísla, řetězce, n-tice, logické hodnoty, funkce, neměnné množiny (frozenset), objekty... nikoliv pro pole, množiny (set) Vrací (velké) celé číslo. print(hash(34)) 34 print(hash("les")) 7824003431697358632 print(hash((7,"pes"))) -4517796161293337072 8 / 31

Rozptylovací funkce v Pythonu Funkce hash pro neměnné hodnoty (immutable): čísla, řetězce, n-tice, logické hodnoty, funkce, neměnné množiny (frozenset), objekty... nikoliv pro pole, množiny (set) Vrací (velké) celé číslo. print(hash(34)) 34 print(hash("les")) 7824003431697358632 print(hash((7,"pes"))) -4517796161293337072 Používáme hash(x) % m. V Pythonu y % m 0 pokud m > 0. 8 / 31

Další použití rozptylovacích funkcí Rychlé ověřené rovnosti velkých objektů (DNA řetězce, otisky prstů, obrázky,... ): Předpočítej otisk každého objektu v databázi Pokud hash(x)=hash(y), pokračuj úplným porovnáním x a y 9 / 31

Velikost rozptylovací tabulky Vhodná velikost je prvočíselná např. 11, 103, 1009... Jinak riziko kolizí pokud ϕ(x) {k, 2k, 3k,... } Dynamická realokace: pokud se tabulka naplní (λ > λmax ) vytvoříme větší tabulku (m 2m) pokud se tabulka vyprázdní (λ < λ min ) vytvoříme menší tabulku (m m/2) Možné hodnoty m 0 = 11, λ max = 0.75, λ min = 0.25. 10 / 31

Nalezení prvočíselné velikosti Najde první prvočíslo větší než n. Pokud takové není, vrátí n a vypíše varování. primes=prvocisla_eratosthenes(100000) def find_prime_size(n): for i in range(len(primes)): if primes[i]>n: return n print("pozor, tabulka prvočísel je příliš krátká.") return n Zrychlování Tabulku (vybraných) prvočísel lze předpočítat. Vyhledávání lze zrychlit binárním půlením. Prvočísla nejsou potřeba všechna. Soubor hashing.py. 11 / 31

Řešení kolizí Co když dvě položky mají stejný otisk? Zřetězení (chaining) Každá přihrádka je seznam (nebo pole). Zaplnění λ může být > 1. 12 / 31

Řešení kolizí Co když dvě položky mají stejný otisk? Zřetězení (chaining) Každá přihrádka je seznam (nebo pole). Zaplnění λ může být > 1. Otevřené adresování (open addressing) Kapacita přihrádky je 1. Pokud je přihrádka m 0 = ϕ(x) obsazená, zkusíme jinou (m 1, m 2,... ) Lineární zkoušení (linear probing) zkusíme mi = m 0 + i. 12 / 31

Řešení kolizí Co když dvě položky mají stejný otisk? Zřetězení (chaining) Každá přihrádka je seznam (nebo pole). Zaplnění λ může být > 1. Otevřené adresování (open addressing) Kapacita přihrádky je 1. Pokud je přihrádka m 0 = ϕ(x) obsazená, zkusíme jinou (m 1, m 2,... ) Lineární zkoušení (linear probing) zkusíme mi = m 0 + i. Kvadratické zkoušení (quadratic probing) zkusíme m i = m 0 + ai 2 + bi, např. a = 1, b = 0. Dvojité rozptylování (double hashing) zkusíme m i = m 0 + iψ(x). 12 / 31

Řešení kolizí Co když dvě položky mají stejný otisk? Zřetězení (chaining) Každá přihrádka je seznam (nebo pole). Zaplnění λ může být > 1. Otevřené adresování (open addressing) Kapacita přihrádky je 1. Pokud je přihrádka m 0 = ϕ(x) obsazená, zkusíme jinou (m 1, m 2,... ) Lineární zkoušení (linear probing) zkusíme mi = m 0 + i. Kvadratické zkoušení (quadratic probing) zkusíme m i = m 0 + ai 2 + bi, např. a = 1, b = 0. Dvojité rozptylování (double hashing) zkusíme m i = m 0 + iψ(x). Menší režie než zřetězení. Zaplnění λ nesmí být velké ( 0.7). Rozptylovací funkce nesmí vytvářet shluky. 12 / 31

Počet porovnání při hledání úspěšné neúspěšné zřetězení 1 + λ 2 λ ( ) ( ( ) ) 2 1 otevřené adresování 2 1 + 1 1 1 λ 2 1 + 1 1 λ Počet přístupů do paměti je větší o 1 + režie přihrádek (např. 2 přístupy na porovnání u spojového seznamu). 13 / 31

Otevřené adresování příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m Vložíme čísla x 54 26 93 17 77 31 44 55 20 ϕ(x) 10 4 5 6 0 9 0 0 9 Po vložení 31: 0 1 2 3 4 5 6 7 8 9 10 77 26 93 17 31 54 14 / 31

Otevřené adresování příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m Vložíme čísla x 54 26 93 17 77 31 44 55 20 ϕ(x) 10 4 5 6 0 9 0 0 9 Po vložení 44: 0 1 2 3 4 5 6 7 8 9 10 77 44 26 93 17 31 54 14 / 31

Otevřené adresování příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m Vložíme čísla x 54 26 93 17 77 31 44 55 20 ϕ(x) 10 4 5 6 0 9 0 0 9 Po vložení 55: 0 1 2 3 4 5 6 7 8 9 10 77 44 55 26 93 17 31 54 14 / 31

Otevřené adresování příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m Vložíme čísla x 54 26 93 17 77 31 44 55 20 ϕ(x) 10 4 5 6 0 9 0 0 9 Po vložení 20: 0 1 2 3 4 5 6 7 8 9 10 77 44 55 20 26 93 17 31 54 14 / 31

Otevřené adresování příklad m = 11 přihrádek, rozptylovací funkce ϕ(x) = x mod m Vložíme čísla x 54 26 93 17 77 31 44 55 20 ϕ(x) 10 4 5 6 0 9 0 0 9 Po vložení 20: 0 1 2 3 4 5 6 7 8 9 10 77 44 55 20 26 93 17 31 54 Prázdné položky = speciální hodnota. Implementace např. Problem Solving with Algorithms and Data Structures https://interactivepython.org/runestone/static/pythonds/sortsearch/hashing.html 14 / 31

Mazání položek Zřetězení smažeme ze seznamu přihrádky. 15 / 31

Mazání položek Zřetězení smažeme ze seznamu přihrádky. Otevřené adresování smazané položky označíme speciální hodnotou přeskoč. Mazání často není potřeba 15 / 31

Implementace rozptylové tabulky Asociativní mapa, kolizní strategie zřetězení. Podobné rozhraní jako BinarySearchTree a dict: h=hashtable(n) vytvoření h=put(h,key,value) vložení položky get(h,key) value nalezení/vyzvednutí hodnoty items(h) seznam dvojic (klíč,hodnota) class Hashtable: def init (self,n=13): # n je doporučená velikost self.size=find_prime_size(n) self.keys =[ [] for i in range(self.size) ] self.values=[ [] for i in range(self.size) ] self.count=0 Soubor hashing.py. 16 / 31

Nalezení položky def get(h,key): """ Vrátí value prvku s klíčem key, jinak None """ m=hash(key) % h.size # číslo příhrádky i=find_index(h.keys[m],key) # je tam? if i is None: # není return None return h.values[m][i] def find_index(l,x): """ Vrátí index i aby l[i]==x nebo None pokud x není v l """ for i,v in enumerate(l): # dvojice index, hodnota if v==x: return i return None V pythonu existuje metoda pole index, používá výjimky. Soubor hashing.py. 17 / 31

Vložení položky def put(h,key,value): """ Vloží pár key -> value do tabulky a vrátí odkaz na aktualizovanou """ m=hash(key) % h.size # číslo přihrádky i=find_index(h.keys[m],key) # je tam? if i is not None: # klíč v tabulce už je h.values[m][i]=value return h h.keys[m].append(key) # klíč v tabulce není h.values[m].append(value) h.count+=1 if h.count>h.size*0.75: # je tabulka moc plná? return grow_table(h) return h 18 / 31

Zvětšení tabulky def grow_table(h): """ Vytvoří větší tabulku, překopíruje tam obsah a vrátí ji """ hnew=hashtable(2*h.size) for i in range(h.size): # okopíruj vše do hnew keys=h.keys[i] values=h.values[i] for j in range(len(keys)): put(hnew,keys[j],values[j]) return hnew 19 / 31

Získání obsahu tabulky def items(h): """ Vrátí seznam dvojic klíč,hodnota """ r=[] for i in range(h.size): r+=zip(h.keys[i],h.values[i]) return list(r) 20 / 31

Získání obsahu tabulky def items(h): """ Vrátí seznam dvojic klíč,hodnota """ r=[] for i in range(h.size): r+=zip(h.keys[i],h.values[i]) return list(r) Další možná rozhraní iter, reduce, iterátor... list dělá z posloupnosti (lazy/on-demand) seznam volíme dle aplikace 20 / 31

Příklad from hashing import * t=hashtable() t=put(t, pi, 3.14159) t=put(t, e, 2.71828) t=put(t, sqrt2,1.41421) t=put(t, golden,1.61803) print(get(t, pi )) 3.14159 print(get(t, e )) 2.71828 print(get(t, gamma )) None 21 / 31

Příklad: Počítání frekvence slov Zjistěte relativní frekvence slov v daném textu (souboru) Načtení souboru, rozdělení na slova. Spočítání frekvence slov Seřazení a vytisknutí def word_frequencies(filename): w=read_words(filename) # seznam slov c=word_counts_dictionary(w) # seznam dvojic (slovo,počet) print_frequencies(c) Soubor word_frequencies.py. 22 / 31

Načtení slov word_pattern=re.compile(r [A-Za-z]+ ) def read_words(filename): words=[] with open(filename, rt ) as f: # otevři textový soubor for line in f.readlines(): # čti řádku po řádce line_words=word_pattern.findall(line) line_words=map(lambda x: x.lower(),line_words) words+=line_words return words 23 / 31

Spočítání slov (1) dict Asociativní mapa count uchovává počet výskytů, klíčem je slovo. def word_counts_dictionary(words): """ Vrátí seznam dvojic slov a jejich frekvencí """ counts={} # slovník for w in words: if w in counts: counts[w]+=1 else: counts[w]=1 return list(counts.items()) 24 / 31

Spočítání slov (2) Rozptylovací tabulka import hashing def word_counts_hashtable(words): """ Vrátí seznam dvojic slov a jejich frekvencí """ counts=hashing.hashtable() for w in words: value=hashing.get(counts,w) if value is None: counts=hashing.put(counts,w,1) else: counts=hashing.put(counts,w,value+1) return hashing.items(counts) 25 / 31

Spočítání slov (3) Vyhledávací strom import binary_search_tree as bst # implementace pomocí vyhledávacího stromu def word_counts_bst(words): """ Vrátí seznam dvojic slov a jejich frekvencí """ counts=none for w in words: value=bst.get(counts,w) if value is None: counts=bst.put(counts,w,1) else: counts=bst.put(counts,w,value+1) return bst.items(counts) 26 / 31

Setřídění a tisk def print_frequencies(counts,n=10): """ Vytiskne n nečastěji použitých slov dle seznamu dvojic (slovo,frekvence) counts """ # setřiď od nejčastějšího counts.sort(key=lambda x: x[1],reverse=true) # celkový počet slov nwords=functools.reduce(lambda acc,x: x[1]+acc,counts,0) for i in range(min(n,len(counts))): print("%10s %6.3f%%" % (counts[i][0],counts[i][1]/nwords*100.)) 27 / 31

Frekvence slov příklad Terminal> python3 word_frequencies.py poe.txt the 7.653% of 4.589% and 2.605% to 2.484% a 2.282% in 2.096% i 1.371% it 1.233% that 1.121% was 1.103% is 0.912% with 0.844% at 0.812% as 0.761% this 0.732% 28 / 31

Porovnání rychlosti Četnost slov 10 2 10 1 word_counts_dictionary word_counts_hashtable word_counts_bst time [s] 10 0 10-1 10-2 10 4 10 5 10 6 N 29 / 31

Rozptylovací tabulky shrnutí Implementace asociativní mapy nebo množiny. Velmi rychlé operace vkládání a vyhledávání (v průměru O(1), nejhorší případ O(n)). Citlivé na volbu rozptylovací funkce a velikost tabulky. Potřebuje rozptylovací funkci a test na rovnost. Nepotřebuje/neumí porovnávat velikost. 30 / 31

Náměty na domácí práci Implementujte otevřenou adresaci. Najděte závislost času na zaplnění tabulky. Implementujte mazání. Implementujte zcela stejné rozhraní jako dict Implementujte počítání frekvence slov bez asociativní mapy, například na základě třídění. Porovnejte efektivitu. 31 / 31