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

  1. maximální možný
  2. 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:

  1. poslední prvek přesuneme do kořene a
  2. propadáme ho dolů...

 

Tedy v každé úrovni:

  1. Musím najít nejmenšího z \(d\) potomků \(\rightarrow\) to je \(d-1\) porovnání
  2. 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:

  1. Odkazy jsou uspořádány v rostoucím pořadí velikostí podstromů, na které odkazují
  2. 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:

  1. Vytvoří nový binomický strom stupně 0
  2. 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:

  1. Najdi minimální kořen v seznamu kořenů
  2. Odstraň tento kořen, získáš tím jeho děti.
  3. Z dětí vytvoř haldu a slij ji se zbytkem haldy.

DeleteMin:

  1. Najdi minimální kořen v seznamu kořenů
  2. Odstraň tento kořen, získáš tím jeho děti.
  3. 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.

 

  1. Jaká je asymptotická složitost tohoto procesu?
  2. 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\).

 

  1. Kolik celkem listů obsahuje celá halda \(H\)?
  2. 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.

 

  1. Napište tento předpis.
  2. Navrhněte podobný způsob ukládání klíčů do pole pro ternární haldu a pro obecnou \(d\)-ární haldu.
  3. 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}$$

Na
Viděnou
Za týden :)