Haldy binární, binomiální, Fibonacciho
LAB 04
B4M33PAL - Ing. David Pařil
Příklad
Cena Binární haldy
Z binární haldy obsahující \(n^3\) prvků, jejíž kořen obsahuje nejmenší hodnotu z celé haldy, odstraníme \(n^2 \cdot \lg(n)\) nejmenších prvků.
Jaká je asymptotická složitost této akce?
Bude složitost jiná, pokud halda nebude binární ale binomiální?
Řešení
Odstranění prvku z binární haldy trvá \(O(\log(N))\)
V našem případě \(O(\log(n^3))\)
Což je vlastně \(O(\log(n))\) (PALovská aproximace™)
Odstranit máme právě \(n^2 \cdot \lg(n)\) prvků
Získáváme:
$$O(n^2 \cdot \log^2(n))$$
Příklad
Problém kapitána paklíče
Je dána \(d\)-ární halda s hloubkou \(h\), jejíž všechny listy leží ve stejné hloubce a která proto obsahuje právě \(\frac{d^h-1}{d-1}\) klíčů.
Jaký je
- maximální možný
- minimální možný
počet porovnání dvou klíčů když provedeme operaci deleteMin?
\(\frac{3^3-1}{3-1}\)
Řešení
Operace deleteMin probíhá takto:
- poslední prvek přesuneme do kořene a
- propadáme ho dolů...
Tedy v každé úrovni:
- Musím najít nejmenšího z \(d\) potomků \(\rightarrow\) to je \(d-1\) porovnání
- Porovnám kořen podstromu s nejmenším potomkem \(\rightarrow\) \(+1\) porovnání
Nejlepší případ: skončíme hned na první úrovni \(\rightarrow\) \(d\) porovnání
Nejhorší případ: propadneme se skrz celý strom \(\rightarrow\) \(d(h-1)\) porovnání
Maximální počet propadnutí
Příklad
Příklad s krátkým zadáním a ještě kratším řešením
Jaký je nejvyšší možný stupeň uzlu v binomiální haldě s \(N\) klíči?
Stupeň:
0
1
2
3
(počet synů)
Stupeň:
0
1
2
3
Řešení
min: 1
max: 1
Kolik hodnot se mi tam vleze?
Stupeň:
0
1
2
3
Řešení
min: 2
max: 3
Stupeň:
0
1
2
3
Řešení
min: 4
max: 7
Stupeň:
0
1
2
3
Řešení
min: 8
max: 15
Stupeň:
0
1
2
3
Řešení
min: \(2^k\)
max: \(2^{k+1}-1\)
\(2^k \leq N \lt 2^{k+1}\)
min: 8
max: 15
min: 4
max: 7
min: 2
max: 3
min: 1
max: 1
Příklad
Binomiální Chaos
Uzel v binomiální haldě může mít stupeň vyšší než dva (obecně není shora omezen).
Uzel odkazuje na další binomiální stromy. Máme dvě možnosti:
- Odkazy jsou uspořádány v rostoucím pořadí velikostí podstromů, na které odkazují
- Odkazy jsou řazeny náhodně
Rozhodněte, jestli volba implementace ovlivňuje rychlost operací
Insert a DeleteMin.
(počet synů)
1. Řazené odkazy
2. Náhodné odkazy
Už známe 😎👍
Ajejej 🙉
Insert:
- Vytvoří nový binomický strom stupně 0
- Sléváme stromy stejných řádů (na úrovni kořenů)
\(\rightarrow\) pořadí dětí uvnitř uzlu se při Insert vůbec nepoužívá
DeleteMin:
- Najdi minimální kořen v seznamu kořenů
- Odstraň tento kořen, získáš tím jeho děti.
- Z dětí vytvoř haldu a slij ji se zbytkem haldy.
DeleteMin:
- Najdi minimální kořen v seznamu kořenů
- Odstraň tento kořen, získáš tím jeho děti.
- Z dětí vytvoř haldu a slij ji se zbytkem haldy.
Za předpokladu, že každé dítě má uložený stupeň svého kořene:
- Musím seřadit \(k\) číšel (např. quicksort) \(\rightarrow O(k \log k)\) (\(k\) je počet dětí)
- Počet dětí \(k\) je \(\leq \log_2 N\) (viz předchozí úloha)
- Následované slitím se zbytkem \(\rightarrow O(\log N)\)
- Celkem: \(O(k \log k + \log N) = O(\log N \cdot \log \log N)\)
1. S řazením:
\(O(\log N)\) 😎👍
Příklad
Rozklad Fibonaciho haldy
Do nejprve prázdné Fibonacciho haldy vložíme \(2^n + 5\) navzájem různých klíčů (\(n > 2\)).
Poté v haldě provedeme operaci DeleteMin včetně následující konsolidace haldy.
Žádné jiné operace s haldou neprovádíme. Kolik binomiálních stromů s kořenem v kořenovém seznamu haldy bude halda obsahovat po této akci?
Řešení
Co se stane, když vložím \(\textcolor{blue}{2^n} + \textcolor{red}{5}\) různých klíčů?
\(\textcolor{blue}{2^3} = 8\)
\(\textcolor{red}{5}\)
\(\textcolor{blue}{2^n} + \textcolor{red}{5}\) samostatných uzlů (stupeň 0)...
Řešení
DeleteMin mi odebere 1 uzel. Zbývá \(\textcolor{blue}{2^n} + \textcolor{red}{4}\) kořenů stupně 0.
\(\textcolor{blue}{2^3} = 8\)
\(\textcolor{red}{4}\)
Konsolidace spojuje kořeny stejného stupně, dokud nezůstane
nejvýše jeden strom každého stupně.
\(\textcolor{blue}{2^n} + \textcolor{red}{4}\) můžeme napsat jako \(\textcolor{blue}{2^n} + \textcolor{red}{2^2}\) \(\rightarrow\) tedy zůstanou dva binomiální stromy
Řešení
\(\textcolor{blue}{2^n} + \textcolor{red}{4}\) můžeme napsat jako \(\textcolor{blue}{2^n} + \textcolor{red}{2^2}\) \(\rightarrow\) tedy zůstanou dva binomiální stromy
2
n
1
0
3
n-1
n+1
Příklad
Reprezentace Binomiální haldy
Zvolte a popište vhodnou datovou strukturu, pomocí níž lze reprezentovat binomiální haldu v paměti počítače.
Zdůvodněte, že vaše reprezentace zachovává asymptotickou složitost operací Insert, AccessMin a DeleteMin.
(Ve své reprezentaci můžete využít i více různých datových struktur)
Typická implementace umožňující
přístup v \(O(x)\) využívá manipulaci s pointery:
Řešení
class FibonacciHeap():
def __init__(self):
self.n = 0
self.min = None
self.root_list = None
class Node():
def __init__(self, key):
self.key = key
self.degree = 0
self.mark = False
# pointers
self.parent = None
self.child = None
self.left = None
self.right = None
Řešení
class FibonacciHeap():
def __init__(self):
self.n = 0
self.min = None
self.root_list = None
class Node():
def __init__(self, key):
self.key = key
self.degree = 0
self.mark = False
# pointers
self.parent = None
self.child = None
self.left = None
self.right = None
Každý uzel má odkazy na:
- svého rodiče
- jedno ze svých dětí
- sousedy vlevo a vpravo
Řešení
class FibonacciHeap():
def __init__(self):
self.n = 0
self.min = None
self.root_list = None
class Node():
def __init__(self, key):
self.key = key
self.degree = 0
self.mark = False
# pointers
self.parent = None
self.child = None
self.left = None
self.right = None
Každý uzel si pamatuje:
- svojí hodnotu (klíč)
- svůj stupeň (počet svých dětí)
Řešení
class FibonacciHeap():
def __init__(self):
self.n = 0
self.min = None
self.root_list = None
class Node():
def __init__(self, key):
self.key = key
self.degree = 0
self.mark = False
# pointers
self.parent = None
self.child = None
self.left = None
self.right = None
Root list: je vzestupně řazený seznam kořenů dle jejich stupně
Příklad
Best case halda
Je dáno \(n\) navzájem různých celočíselných klíčů a prázdná binární halda.
kde \( n \geq 2\)
Všechny klíče vložíme jeden po druhém v náhodném pořadí do dané haldy.
- Jaká je asymptotická složitost tohoto procesu?
- Je možné, že pro některé pořadí klíčů bude asymptotická složitost menší nebo větší než v náhodném případě?
Insert do binární haldy přidá prvek na poslední list a probublává nahoru.
Hloubka haldy po \(m\) vložených prvcích je \(O(\log m)\)
Tedy očekáváná cena jednoho insertu je \(O(\log m)\)
Pro všechny inserty \(m = 1...n\) je to pak \(O(n \log n)\)
Řešení
Best case:
Worst case:
klíče vkládáme vzestupně \(\rightarrow\) nebubláme \(\rightarrow\) \(O(n)\)
klíče vkládáme sestupně \(\rightarrow\) max. bublání \(\rightarrow\) \(O(n \log n)\)
Příklad
Maximum v binomiální haldě
V binomiální haldě, která udržuje klíče s minimální hodnotou v kořenech svých stromů máme najít klíč s maximální hodnotou a poté ho z haldy vymazat.
Zdůvodněte asymptotickou složitost této akce.
V min-binomiální haldě leží maximum vždy v listu...
Seznam listů ale nemáme.
Maximum proto nalezneme jen lineárním průchodem přes uzly (resp. listy)
Složitost operace: \(O(n)\)
Samotné odebrání maximálního prvku pak stojí \(O(\log n)\):
- decrease-key na \(-\infty\) \(\rightarrow\) \(O(\log n)\)
- delete-min \(\rightarrow\) \(O(\log n)\)
Řešení
Příklad
listí 🍃
Předpokládejme, že binomiální halda \(H\) obsahuje \(k\) bin. stromů \(T_1, T_2, ... T_k\).
- Kolik celkem listů obsahuje celá halda \(H\)?
- Pokud \(H\) obsahuje \(n\) klíčů, jaká je maximální možná hodnota \(k\) v závislosti na \(n\)?
Počet listů 🍁 v binomickém stromu \(T_i\) je:
$$L(T_i) = \begin{cases} 1 & i=0\\ 2^{i-1} & i\ge 1 \end{cases}$$
Řešení 1.
🍁=1
🍁=1
🍁=2
🍁=4
0
1
2
3
Počet listů 🍁 v binomické haldě \(H\) je:
$$L(H)=\sum_{i=1}^k L\!\left(T_{i}\right) =\sum_{i=1}^k \frac{2^i}{2}= \frac N 2$$
Počet stromů 🌳 \(k\) v binomiální haldě je roven počtu jedniček 1️⃣ v binárním zápisu \(n\).
Z toho plyne ostrá horní mez:
$$k \leq (\log_2 n) + 1$$
Řešení 2.
0
1
2
3
Příklad
Reprezentace binární haldy
Když binární haldu reprezentujeme polem klíčů, existuje jednoduchý předpis, jak z indexu prvku pole obsahujícího určitý klíč určit indexy prvků obsahující levého a pravého potomka tohoto klíče.
- Napište tento předpis.
- Navrhněte podobný způsob ukládání klíčů do pole pro ternární haldu a pro obecnou \(d\)-ární haldu.
- Napište příslušné vztahy, pomocí nichž z indexu prvku obsahujícího klíč určíte indexy prvků obsahující potomky tohto klíče.
Řešení
Binární halda (\(d=2\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Ternární halda (\(d=3\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Řešení
Binární halda (\(d=2\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Ternární halda (\(d=3\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Levý potomek:
\(2i+1\)
Pravý potomek:
\(2i+2\)
Rodič:
\(\frac{i-1}{2}\)
1. potomek:
\(3i+1\)
2. potomek:
\(3i+2\)
Rodič:
\(\frac{i-1}{3}\)
3. potomek:
\(3i+3\)
Řešení
Binární halda (\(d=2\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Ternární halda (\(d=3\))
0
1
2
3
4
5
6
7
8
9
10
11
12
Levý potomek:
\(2i+1\)
Pravý potomek:
\(2i+2\)
Rodič:
\(\frac{i-1}{2}\)
1. potomek:
\(3i+1\)
2. potomek:
\(3i+2\)
Rodič:
\(\frac{i-1}{3}\)
3. potomek:
\(3i+3\)
Obecně:
\(k\)-tý potomek:
$$K\cdot i + k$$
rodič:
$$\frac{i-1}{K}$$