Hašování

Pomocí hašování lze efektivně řešit situaci, kdy je třeba uložit "malou" podmnožinu "velkého" univerza možných prvků. Chceme přitom mít k dispozici operace:

  1. INSERT - uložení prvku
  2. DELETE - vymazání prvku
  3. MEMBER - dotaz na přítomnost prvku mezi uloženými

Univerzum může mít sice velikost N, ale my víme (z vlastností problému, který řešíme), že budeme operovat pouze nad jeho malou podmnožinou velikosti m. Použijeme tedy pouze malou tabulku (velikosti m) a hodnoty do ní budeme ukládat pomocí hašovací funkce. Ta nám bude počítat adresy v tabulce (tedy čísla v rozsahu 0,...,m) pro prvky z celého velkého univerza.

Existuje možnost, že hašovací funkce spočítá pro dva různé prvky stejnou adresu. Tomu se při hašování říká kolize a existuje množství způsobů, jak tento problém řešit.

VIP párty

Na cvičení jsme řešili ilustrační příklad, pro který jsme se snažili naprogramovat jednoduchou implementaci hašovací tabulky - šlo nám hlavně o operaci INSERT, která by nějakým způsobem řešila kolize. Mailem jsem obdržel implementaci od pana Dziewieckého a pana Chudáčka. Oběma jsem udělil 5 bonusových bodů.

Poznámka:

Hašování souvisí také s kryptografií. Ne náhodou jde o používání stejného pojmu. Liší se pouze způsobem použití hašovací funkce. Princip hašovací funkce je ale stále stejný: z "velkého čísla" počítá "malá" čísla.

Dynamické programování

Jde o způsob návrhu algoritmů, který využívá toho, že libovolná část optimálního řešení je vždy optimálním řešením části problému. Ne všechny problémy tuto vlastnost mají, ale pokud ano, dynamické programování na jejich řešení můžeme s výhodou použít.

Konkrétním problémem s výše uvedenou vlastností je například hledání nejkratší cesty v grafu. Platí zde totiž následující tvrzení:

O kusu nejkratší cesty

Mějme dánu nejkratší cestu s=v1,v2,...,vk=c mezi vrcholy s,c v grafu G=(V,E).

Potom libovolný kus vi,...,vj určený nějakými indexy i,j: 1 ≤ i < j ≤ k je nejkratší cestou mezi vrcholy vi,vj.

Floyd-Warshall

Jde o algoritmus, který dokáže v daném orientovaném váženém grafu nalézt délky nejkratších cest mezi všemi dvojicemi vrcholů (lze ho snadno upravit a během výpočtu udržovat i matici předchůdců, takže ty konkrétní cesty pak dokážeme zrekonstruovat také). Je navržený dynamicky:

FloydWarshall(G): A
// G=(V,E) - vazeny graf, |V|=n
// A - matice n X n
A_0 := matice sousednosti G s vahami hran
for k:=1 to |V| do
  for i:=1 to |V| do
    for j:=1 to |V| do
      alternativa:= A_(k-1)[i,k] + A_(k-1)[k,j]
      A_k[i,j] = min(A_(k-1)[i,j],alternativa)

return A_(|V|)

Pokud budou v G hrany se zápornou váhou, algoritmus si s tím poradí. Přítomnost záporného cyklu snadno odhalíme tak, že prozkoumáme diagonálu výsledné matice - bude obsahovat záporné číslo. To proto, že algoritmus dřív nebo později zjistí, že se do nějakého vrcholu v dostane po cestě kratší než 0.

Domácí úkol

Bohužel není ještě odemčena úloha, na hledání nejkratších cest, kterou jsem chtěl zadat původně. Zadal jsem místo toho Přidávání do AVL-stromu.