#!/usr/bin/env python # coding: utf-8 # # Hash Taulak ( _Associative array_ , _Elkartze Arrayak_ ) # # * _gako_ -etatik _balio_ -etarako aplikazioa # * Python-eko `dict` eta `set` objektuak # * _gako_ -aren gain _Hash funtzio_ bat aplikatzean, arrayari dagokion indize bat lortu. # # Hash Table # ## Hash Funtzioa # # * Edozein informazioren gain aplikatzean, tamaina finkoko balio bat (zenbaki bat) lortu. # * Informazio baten _sinadura_ (laburpen) digitala. # * Propietateak: # * Hash balioen banaketa uniformea # * Berdinak diren bi objektuen hash balioak berdinak dira # * Kontrakoak ez du zertan egia izan behar. # * Adibide bat: # * [SHA256:](https://andersbrownworth.com/blockchain/hash) _informazioa_ → 256 bit # ## Hash Taulen bi erabilpen # # * **Hash Map** (hiztegiak) : `gako` → `(gako,balio)` # * **Hash Set** (multzoak) : `gako` → `(gako,)` # # ## Hash Taulen inplementazioa # # * $N$ tamainako Taula/Array/Zerrenda bat erabili. # * Okupazio faktorea (*load factor*): $LF : {n_{stored}}/{N}$ # * $g$ gako bati taulan dagokion posizioa: $i \; = \; hash(g)\; \% \; N$ # * *Talkak* edo *kolisioak* gerta daitezke # * **Kolisioa**: Bi $g_1 , g_2$ gako ezberdinei $i_1 = i_2$ posizio berdina esleitzea # * $hash(g_1) = hash(g_2)$ balio berdina izan dezakete. # * $hash(g_1) \ne hash(g_2)$ izanda ere, $(hash(g_1)\, \% \, N) = (hash(g_2)\, \% \, N)$ gerta daiteke. # In[34]: N=17 T = [None]*N print(T) g,b = "Ane",656354364 i = hash(g)%N T[i] = (g,b) print(T) g,b = "Unai",656455384 i = hash(g)%N T[i] = (g,b) print(T) g,b = "Raul",656455384 i = hash(g)%N T[i] = (g,b) print(T) # In[10]: print(hash("kaixo"), hash("kaixo") % 10) print(hash("kaixoooooooooooooooo"), hash("kaixoooooooooooooooo") % 10) # ### Kolisioen ebazpena I : Taula berdimentsionatu # # * Kolisio bat ematen den bakoitzean, taularen tamaina handitu dezakegu. # * Tamaina handitzean, talka berri baten probabilitatea txikiagoa da. # * Baina... zenbatekoa da probabilitate hori? # * 2450 gako baditugu 1.000.000 tamaina duen taula batetan (400-etik gelaxka bakarra okupatua), guztiz uniformea den hash funtzio bat erabilita ere, talka bat gertatzeko probabilitatea 95% da # * _Birthday Problem_ edo [Urtebetetzeen Ebazkizuna](https://eu.wikipedia.org/wiki/Urtebetetzeen_ebazkizuna) # * $LF \; \ll \; 1$ # * Memoriaren erabilpen **oso kaxkarra** # ### Kolisioen ebazpena II : Helbideratze Irekia (*Open addressing*) # # * $g$ gako bati taulan dagokion posizioa ez da $i \; = \; hash(g)\; \% \; N$ izango # * $i$ posiziotik abiatuko gara # * elementua topatu arte # * gelaxka huts bat topatu arte # # Hash Table - Open addressing # # In[36]: N=10 T = [None]*N print(T) g,b = "Ane",656354364 i = hash(g)%N T[i] = (g,b) print(T) g,b = "Unai",656455384 i = hash(g)%N T[i] = (g,b) print(T) g,b = "Raul",656455384 i = hash(g)%N # behar adina aldiz... i = (i+1)%N T[i] = (g,b) print(T) # **Helbideratze Irekia**-ren ezaugarriak: # # * Hash balioen banaketa uniformeak garrantzi handia du # * $LF \; <= \; 1$ # * $LF \; > 0.7$ → **errendimendu eskasa** → Taula berdimentsionatu # # Hash Table - Average insertion time # # # ### Kolisioen ebazpena III : Kateatze Banatua (*Separate Chaining*) # # * $g$ gako bati taulako $i \; = \; hash(g)\; \% \; N$ posizioko **zerrenda** dagokio # # Hash Table - Separate Chaining # # In[42]: N=3 T = [[] for _ in range(N)] print(T) g,b = "Ane",656354364 i = hash(g)%N T[i].append((g,b)) print(T) g,b = "Unai",656455384 i = hash(g)%N T[i].append((g,b)) print(T) g,b = "Raul",656455384 i = hash(g)%N T[i].append((g,b)) print(T) # **Kateatze Banatua**-ren ezaugarriak: # # * $LF \; > \; 1$ izan daiteke # * $LF \; \gg 1$ → **errendimendu eskasa** → Taula berdimentsionatu