Základní datové struktury III: Stromy, haldy prof. Ing. Pavel Tvrdík CSc. Katedra počítačových systémů Fakulta informačních technologií České vysoké učení technické v Praze c Pavel Tvrdík, 2010 Efektivní algoritmy (BI-EFA) ZS 2010/11, Přednáška 4 Evropský sociální fond. Praha & EU: Investujeme do vaší budoucnosti prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 1 / 24
Motivace Volání rekurzivní funkce Motivace 1: Volání rekurzivní funkce Stromy jako DS jsou potřebné pro řešení rekurzivně definova(tel)ných problémů. Příklad: graf volání QuickSortu. 179 24125 2621714 19128 23 291112 175 25 9125 21412811125 1717 24261923291725 5 2 8 5 9 1214121112 192317 24 262925 3 5 5 8 11 121212 14 17 19 23 25 26 29 prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 2 / 24
Motivace Rekurzivně definova(tel)ná množina dat Motivace 2: Rekurzivně definova(tel)ná množina dat Množina všech permutací dané posloupnosti. * * * * 1 * * * 2 * * * 3 * * * 4 * * * 2 1 * * 2 3 * * 2 4 * * 2 4 1 * 2 4 3 * prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 3 / 24
Stromy v teorii grafů Volné stromy Volné stromy Definice 1 Volný strom je každý souvislý acyklický a neorientovaný graf. Les je každý acyklický a neorientovaný graf. Poznámka: Většina algoritmů nad stromy funguje i nad lesy. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 4 / 24
Stromy v teorii grafů Volné stromy Vlastnosti volných stromů Věta 2 Nechť G = (V (G), E(G)) je neorientovaný graf. Pak následující tvrzení jsou ekvivalentní. 1 G je volný strom. 2 Jakékoli 2 uzly v G jsou spojeny jedinečnou jednoduchou cestou. 3 G je souvislý, ale pokud vyjmeme jakoukoli hranu z E(G), výsledný graf bude nesouvislý. 4 G je souvislý a E(G) = V (G) 1. 5 G je acyklický a E(G) = V (G) 1. 6 G je acyklický, ale pokud přidáme jakoukoli hranu do E(G), výsledný graf bude obsahovat aspoň jeden cyklus. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 5 / 24
Stromy v teorii grafů Kořenové stromy Kořenové stromy Definice 3 Kořenový strom je volný strom, ve kterém jeden z uzlů, r, je odlišen od ostatních jako kořen a hrany jsou orientované stejným směrem vzhledem ke kořenu r. Nechť uzel u leží na (jedinečné) cestě z kořene r do uzlu v. Pak u je předek v a v je potomek u. Nejbližší předek uzlu je jeho rodič a nejbližší potomek je jeho syn. Každý uzel kromě kořenu má jedinečného rodiče. Uzly se stejným rodičem jsou sourozenci. Uzel, který nemá potomky, se nazývá list. Ostatní uzly jsou vnitřní. Stupeň vnitřního uzlu je počet jeho synů. k-ární strom: každý vnitřní uzel má stupeň nejvýše k. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 6 / 24
Stromy v teorii grafů Kořenové stromy Hloubka a výška Definice 4 Uzly u ve vzdálenosti k od kořenu r tvoří hladinu uzlů v hloubce (depth) d(u) = k. Hloubka stromu d(t ) je hloubka od kořene nejvzdálenějšího listu. Výška (height) uzlu u je h(u) = d(t ) d(u). Výška podstromu T s kořenem r je h(r ) = max u T (d(u) d(r )). Kořen r má hloubku d(r) = 0. Poznámka: Pokud nebude řečeno jinak, stromem budeme dále rozumět kořenový strom. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 7 / 24
Stromy jako datové struktury Uspořádané stromy Uspořádané stromy k-ární stromy jsou z implementačních důvodů obvykle uspořádané. Definice 5 Uspořádaný strom. Synové každého vnitřního uzlu jsou očíslovány (zleva doprava) čísly {1,..., #počet synů}. Dva kořenové stromy se stejnými uzly v jiném pořadí jsou různé uspořádané stromy. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 8 / 24
Stromy jako datové struktury Poziční stromy Poziční stromy k-ární stromy jsou z implementačních důvodů ještě častěji poziční. Definice 6 Poziční strom. Synové každého vnitřního uzlu jsou označeny různými čísly. Pokud žádný syn není označen číslem i, pak i-tý syn chybí a příslušný podstrom je prázdný (NIL). Dva kořenové stromy se stejnými podstromy ale jiným označením pozic jsou různé poziční stromy. k-ární strom je poziční strom, kde každý uzel má syny označeny čísly k. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 9 / 24
Stromy jako datové struktury Binární stromy Binární stromy Definice 7 k-ární strom pro k = 2 se nazývá binární. Alternativní rekurzivní definice binárního stromu. Definice 8 Binární strom (BS) T je datová struktura definovaná nad konečnou množinou uzlů, která buď neobsahuje žádné uzly nebo obsahuje 3 disjunktní množiny uzlů: kořen, BS zvaný levý podstrom a BS zvaný pravý podstrom. Pokud není levý podstrom prázdný (NIL), jeho kořen je levým synem kořenu. Podobně pro pravý podstrom. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 10 / 24
Stromy jako datové struktury Plné, výškově vyvážené a úplné stromy k-ární stromy Plné, výškově vyvážené a úplné k-ární stromy Definice 9 (a) Plný k-ární strom: Každý vnitřní uzel má stupeň právě k. (b) Výškově vyvážený strom: Hloubka libovolných dvou listů se liší nejvýše o 1. (c) Úplný k-ární strom: Výškově vyvážený plný k-ární strom, plněný zleva doprava, kde nejvýše 1 vnitřní uzel má stupeň menší než k. Užší definice: plný k-ární strom, jehož všechny listy mají stejnou hloubku. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 11 / 24
Stromy jako datové struktury Vlastnosti úplných k-árních stromů Vlastnosti úplných k-árních stromů Věta 10 Nechť T je úplný k-ární strom o n uzlech. Pak Hloubka d(t ) je log k n d(t ) log k n. Počet uzlů v hloubce i < d(t ) je k i. Pro n = kd(t )+1 1 k 1 mají všechny listy hloubku d(t ) a všechny vnitřní uzly stupeň k. Počet listů je pak k d(t ) a počet vnitřních uzlů je k d(t ) 1 k 1. Domácí úkol: Najděte přesný výraz pro d(t ). prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 12 / 24
Stromy jako datové struktury Vlastnosti binárních a úplných binárních stromů Vlastnosti úplných binárních stromů (ÚBS) Věta 11 Nechť T je ÚBS o n uzlech. Pak (a) Hloubka d(t ) = log n. (b) Počet uzlů v hloubce i < d(t ) je 2 i. (c) Počet vnitřních uzlů je n/2 a počet listů je n/2. (d) Pro n = 2 d(t )+1 1 mají všechny listy hloubku d(t ). Věta 12 Nechť T je libovolný binární strom o n uzlech. Pak (e) log n d(t ) n 1. (f) Počet uzlů stupně 2 = počet listů minus jedna. (Snadno indukcí.) prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 13 / 24
Implementace binárních stromů Implementace obecného binárního stromu pomocí spojových struktur Implementace binárního stromu pomocí spojových struktur struct node { int val; node *parent; node *left; node *right } prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 14 / 24
Implementace binárních stromů Implementace ÚBS pomocí pole Implementace ÚBS pomocí pole Věta 13 Nechť T je ÚBS o n uzlech. Předpokládejme, že uzly T jsou číslovány zleva doprava shora dolů a že kořen má číslo 1. Pak lze ÚBS reprezentovat pomocí jednorozměrného pole A[1,..., n] tak, že uzel stromu i je reprezentován prvkem pole A[i]. Indexy rodiče, levého syna a pravého syna uzlu i v poli A lze spočítat pomocí následujících funkcí: parent(i) = i/2. left(i) = 2i. right(i) = 2i + 1. prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 15 / 24
Binární halda Definice Binární halda (heap) Definice 14 Uvažujme pole A[1,..., Length(A)] ordinálního typu implementující ÚBS pomocí funkcí parent, left, right. Pak binární halda o velikosti Heap Size(A) Length(A) je dynamická množina uložená v A[1,..., Heap Size(A)], jejíž prvky splňují H-vlastnost: Pro každý prvek s indexem 1 < i Heap Size(A) platí A[parent(i)] A[i]. (1) prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 16 / 24
Binární halda Udržování H-vlastnosti Algoritmus udržování H-vlastnosti Algoritmus 15 Vstup: Pole A a index i takový, že binární podstromy s kořeny v A[left(i)] a A[right(i)] jsou binární haldy (splňují H-vlastnost), ale přitom A[i] < A[left(i)] nebo A[i] < A[right(i)]. procedure heapify(a, i) { (1) l left(i); (2) r right(i); (3) if (l Heap Size(A) & A[l] > A[i]) (4) then Largest l else Largest i; (5) if (r Heap Size(A) & A[r] > A[Largest]) (6) then Largest r; (7) if (Largest i) (8) then {A[i] A[Largest]; heapify(a, Largest)} } prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 17 / 24
Binární halda Udržování H-vlastnosti Složitost algoritmu udržování H-vlastnosti Věta 16 Časová složitost operace heapify na podstromu o n uzlech (s kořenem A[i]) je t HP (n) t HP (2n/3) + Θ(1) (2) (což znamená t HP (n) = O(log n), viz BI-ZDM). Důkaz. Po provedení Θ(1) operací, procedura heapify se volá rekurzivně pro levý nebo pravý podstrom a ten má v nejhorším případě velikost 2n 3 (případ, kdy poslední hladina stromu je zaplněna přesně z jedné poloviny). prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 18 / 24
Binární halda Algoritmus konstrukce haldy Konstrukce haldy Algoritmus 17 Vstup: libovolné pole A[1,..., Length(A)]. procedure buildheap(a) { (1) Heap Size(A) Length(A); (2) for (i = length(a)/2 downto 1) (3) do heapify(a, i) } prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 19 / 24
Binární halda Algoritmus konstrukce haldy Složitost algoritmu konstrukce haldy Věta 18 Časová složitost t BH (n) = O(n). Důkaz. Protože se n/2 krát volá heapify, které trvá O(log n), je t BH (n) = O(n log n). Protože halda je ÚBS, platí, že ve výšce h je nejvýše n 2 uzlů. heapify haldy o výšce h trvá O(h). Tedy h+1 t BH (n) = log n h=0 n 2 h+1 O(h) = O n log n h=0 h = O(2n) = O(n). 2 h prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 20 / 24
HeapSort HeapSort Algoritmus 19 Vstup: libovolné pole A[1,..., Length(A)]. procedure HeapSort(A) { (1) buildheap(a); (2) for (i length(a) downto 2) (3) do { A[1] A[i]; (4) Heap Size(A) Heap Size(A) 1; (5) heapify(a, 1) } } Věta 20 Časová složitost t HS (n) = O(n log n). Důkaz. t HS (n) = t BH (n) + 2 i=n 1 (t HP(i) + Θ(1)) = O(n) + O( n 1 i=2 log i) = O(log(n!)) = O(n log n). prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 21 / 24
Prioritní fronta Prioritní fronta Definice 21 Prioritní fronta je dynamická množina umožňující efektivní vkládání libovolných nových prvků a jejich vybírání v pořadí jejich velikosti pomocí následujících operací: getmax(a), extractmax(a), insert(a, val). prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 22 / 24
Prioritní fronta Operace nad prioritní frontou function getmax(a) { return A[1] } procedure extractmax(a) { (1) if (Heap Size(A) < 1) (2) then error(heapunderflow); (3) max A[1]; (4) A[1] A[Heap Size[A]]; (5) Heap Size(A) Heap Size(A) 1; (6) heapify(a, 1); (7) return max} } prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 23 / 24
Prioritní fronta Operace nad prioritní frontou procedure insert(a, val) { (1) Heap Size(A) Heap Size(A) + 1; (2) i Heap Size(A); (3) while (i > 1 & A[parent(i)] < val) (4) do { (5) A[i] A[parent(i)]; (6) i parent(i); (7) } (8) A[i] val } prof. Pavel Tvrdík (FIT ČVUT) Stromy a haldy BI-EFA, 2010, Předn. 4 24 / 24