Definice
Binární halda je datová struktura tvaru binárního stromu, která uchovává množinu n porovnatelných prvků splňující vlastnost haldy. Halda může být uspořádána vzestupně nebo sestupně a proto často rozlišujeme dva druhy hald, pro které platí trochu jiná vlastnost haldy:
- Vlastnost minimové binární haldy (min-heap). Pro každý vrchol v a pro každého potomka t platí, platí k(v) ≤ k(t).
- Vlastnost maximové binární halda (max-heap). Pro každý vrchol v a pro každého potomka t platí, platí k(v) ≥ k(t).
Vlastnost haldy je rekurzivní - všechny podstromy haldy jsou také haldy. Díky této vlastnosti máme garantováno, že se halda chová jako prioritní fronta - na vrcholek haldy vždy musí vystoupat prvek s nejvyšší prioritou.
Vlastnosti stromů
Věta
Binární halda s n prvky má ⌈n/2⌉ listů a ⌊n/2⌋ vnitřních vrcholů.
Důkaz
Indukcí podle počtu vrcholů binárního stromu.
Věta o hloubce haldy
Halda s n prvky má ⌊log2 n⌋ + 1 hladin.
Důkaz
Binární strom s h úplnými hladinami má n = 20+ 21 + 22 + ··· + 2h−1 = 2h−1 vrcholů. Vzhledem ke tvaru haldy přibude nová hladina jen tehdy, když počet prvků n vzroste na mocninu dvojky.
Operace
Operace: | Složitost: |
Vkládání: | O(log n) |
Najdi minimum/maximum: | O(1) |
Odstraň minimum/maximum: | O(log n) |
Build: | O(n) |
Funkce k(x) nám vrací klíč. n je velikost haldy.
Vkládání (insert)
Princip:
- Podmínka na tvar haldy nám dovoluje přidat nový list na konec poslední hladiny. Pokud by tato hladina byla plná, můžeme založit novou s jediným listem úplně vlevo.
- Pokud je haldové uspořádání mezi novým listem a jeho rodičem v pořádku, můžeme skončit.
- Pokud ne, prohodíme k(l) a k(o).
- Tím, ale může nastat problém mezi klíčem vrcholu o a klíčem otce vrcholuo, tj. nemusí pro ně platit haldové uspořádání.
- Pokud pro ně neplatí, opět jejich klíče prohodíme a opakujeme,atd., až nejdále do kořene.
Pseudokód:
Procedura HeapInsert(H, k)
Vstup: Nový prvek p s klíčem k
1. n := n+1
2. p(n) ← p, k(n) ← k # Vlož na první volnou pozici v poslední hladině H nový vrchol p
3. BubbleUp(p)
Bublání funguje stejně jako v BubbleSortu, akorát místo průchodu pole probubláváme podél cesty ve stromě vedoucí z uzlu v do kořene nebo do listu.
Procedura BubbleUp(p)
1. Dokud p není kořen:
2. o := rodič(p) # ⌊i/2⌋
3. Pokud k(o) ≤ k(p):
4. vyskočíme z cyklu.
4. Prohodíme k(p) s k(o)
5. p := o
Analýza složitosti:
Časovou složitost odhadneme snadno: na každé hladině stromu strávíme nejvýše konstantní čas a hladin je logaritmický počet. Operace Insert tedy trvá O(log n).
Najdi minimum/maximum
Procedura HeapFindMin(p) 1. vratí klíč kořene r haldy
Nalezení a odstranění minima
Algoritmus HeapExtractMin(H) r = kořen, l = poslední list Prohoď k(r) a k(l) n := n−1 BubbleDown(r)
Procedura BubbleDown(v) Dokud mávnějaké syny: s:= takový synv, který má nejmenší klíč Pokudk(v)≤k(s): return Prohoď k(v) a k(s)
Implementace
Vztahy indexů v haldě
Má-li vrchol v index i, pak
- jeho levý potomek má index 2i a
- pravý potomek index 2i + 1,
- rodič má index ⌊i/2⌋ a
- výraz i mod 2 udává, zda je v připojen k rodiči levou či pravou hranou, tj. zda je jeho levý či pravý potomek.
Binární haldy mohou být implementovány jednoduše pomocí pole nebo spojového seznamu. K implementaci je také možné použít datové struktury binárního stromu.
K zamyšlení
Je binární halda úplný binární strom?
Ne. Je téměř úplný binární strom. Neúplná může být pouze poslední vrstva listů a to ještě jen zprava. Určitě je vyvážený binární strom.