Dynamické datové struktury II. Stromy. Binární vyhledávací strom. DFS. BFS. Tomáš Bayer bayertom@natur.cuni.cz Katedra aplikované geoinformatiky a kartografie, Přírodovědecká fakulta UK. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 1 / 56
Obsah přednášky 1 Strom 2 Binární vyhledávací strom Binární strom 3 Vyvážené BST stromy Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 2 / 56
Strom 1. Strom Patří mezi rekurzivní datové struktury. Takové uspořádání dat, kdy každý prvek má nejvýše jednoho předchůdce a může mít více než jednoho následníka. Jedna z nejčastěji používaných dynamických datových struktur. Mnoho typů stromů: binární stromy, ternární stromy, kořenové stromy, volné stromy... Neorientovaný graf G = H, U, ρ, H = {h i n h i=1, U = {u i nu i=1, ρ(h) = [u 1, u 2 ]. G stromem T, T G, pak právě jedna cesta C C(u, v) = {h 1,..., h k, ρ(h 1 ) = [u, ], ρ(h 1 ) = [, v], u, v U. Pozn.: každá hrana h se v cestě C vyskytuje pouze 1x. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 3 / 56
Strom 2. Typy uzlů 3 typy uzlů: Listy: Uzly bez následníka, u l. Není k nim připojen žádný podstrom. Kořen: Uzel bez předchůdce = kořen. Existuje právě 1, u 0. Vnitřní uzly: Uzly, které nejsou listem ani kořenem. Kořenové stromy: Každý uzel je současně kořenem stromu a zároveň listem stromu vyšší úrovně. Volné stromy: Nedisponují kořenem, obecnější datové struktury (seznam). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 4 / 56
Strom 3. Stromy, základní vztahy Stupeň uzlu m: maximální počet potomků uzlu (m = 2, binární; m = 3, ternární). Vztah počtu uzlů a hran n u = n h 1. Výška uzlu x: Délka cesty od kořene k uzlu Výška stromu h: Představuje úroveň nejnižšího uzlu x = C(u 0, v) x l = C(u 0, u l ). h = max (x i) = max C(u 0, u l ). T u l U Ovlivňuje rychlost operací nad stromem (odpovídá hloubce rekurze). Snaha vytvářet stromy s h, cesty do všech uzlů stejně dlouhé: x l = x l Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 5 / 56
Strom 4. Stromy, základní vztahy Vztah mezi počtem uzlů a úrovní x n u (x) = m x 1. Vztah mezi počtem uzlů a výškou stromu: h n u m 0 + m 1 +... + m h = m h = 1 mh+1 1 m. Binární strom: n u 2 h 1. i=0 Vztah mezi výškou h a počtem uzlů n u : ln(nu ) h ln(m), n u 1. = log m (n u ), n u 1 Pozor na stromy h sup(n u 1), neefektivní! Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 6 / 56
Strom 5. Ukázky stromů pro různá n Unární strom: n = 1 seznam, fronta zásobník. Binární strom: n = 2. Ternární strom: n = 3. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 7 / 56
Strom 6. Vyvážené a degenerované stromy Vyvážený strom: Každý uzel má podobný počet potomků nebo výšku. Pro konstrukci vyvážených stromů existuje řada různých algoritmů. Využití při práci s daty, teorii grafů, indexování. Nevyvážený (degenerovaný) strom: Nerovnoměrné rozložení uzlů, větší výška. Nebezpečí používání: značná hloubka rekurzivního volání, při provádění může dojít pamět. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 8 / 56
Binární strom 7. Binární strom Nejčastěji používané typy stromů v informatice, m = 2. Každý uzel (rodič) má dva podstromy (potomky): levý podstrom a pravý podstrom. Využití pro rychlé vyhledávání, indexace, komprese,... Vyvážené binární stromy: Rovnoměrné rozložení uzlů, neobsahuje příliš dlouhé či krátké větve. Všechny listy se nacházejí na přibližně stejné úrovni. Hloubka vyváženého binárního stromu: h = log 2 (n u ). Důsledek: Operace nad tímto stromem mají příznivou asymptotickou složitost. Procházení, vyhledávání se stávají efektivní, méně efektivní přidávání či mazání uzlů. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 9 / 56
Binární strom 8. Vyvážené binární stromy Dokonale vyvážený binární strom: Počet vrcholu v levém a pravém podstromu se liší maximálně o 1. Obtížné na implementaci při přidávání a odebírání vrcholu. Nutné jeho převažování (LL, LP, PL, PP rotace). Absolutně vyvážený binární strom: Výška levého podstromu se rovná výšce pravého podstromu nebo se liší právě o 1 (Adelson, Velskii, Landis) AVL stromy. Snadnější zajištění vyváženosti než v předchozí variantě, používány v praxi. h AVL 2 log(n u ). Převažování stromu O(log(n u ). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 10 / 56
9. Ukázky binárních stromů Binární strom Dokonale vyvážený strom (1,2), absolutně vyvážený strom (3). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 11 / 56
Binární strom 10. Binární vyhledávací strom (BST) Pro každý uzel u U, a jeho potomky u left, u right U platí: u left < u u right > u, u U. Všechny prvky v levém podstromu jsou menší než u, Všechny prvky v pravém podstromu větší než u. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 12 / 56
11. Operace nad BST stromy Základní operace: Přidání uzlu: O(log(N)), Odstranění uzlu: O(log(N)), Nalezení uzlu: O(log(N)), Průchod stromem: O(N). Smazání stromu: O(N). Pokud stromy nejsou vyvážené, složitost O(log(N)) O(N)!!! Operace probíhají ve směru shora-dolů: od kořene k listům (přidání uzlu), od listům ke kořeni (mazání). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 13 / 56
12. Procházení BST stromu 3 základní metody procházení stromu, složitost O(N): 1 Přímé zpracování: PREORDER. 2 Vnitřní zpracování: INORDER. 3 Zpětné zpracování: POSTORDER. Přímé zpracování: Nejprve zpracován kořen, poté levý podstrom, nakonec pravý podstrom. Vnitřní zpracování: Nejprve zpracován levý podstrom, poté kořen, nakonec pravý podstrom. Zpětné zpracování: Nejprve zpracován levý podstrom, poté pravý podstrom, nakonec kořen. Princip zpracování stejný, liší se však pořadím prováděných operací. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 14 / 56
13. Procházení stromu PREORDER 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 15 / 56
14. Procházení stromu INORDER 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 16 / 56
15. Implementace třídy Uzel v BST stromu public class Uzel { int data; //Datova polozka Uzel levy; //Odkaz na levy podstrom Uzel pravy; //Odkaz na pravy podstrom public Uzel(int data_) { //Konstruktor data=data_; //Pouze inicializace dat, zarazeni pozde null; pravy=null; Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 17 / 56
16. Vytvoření prázdného stromu, ukázka Složitost O(1). Postup vytvoření prázdného stromu: Vytvoření odkazu na kořen. Inicializace odkazu na null: koren=null. public class Strom { private Uzel koren; public Strom (){ koren=null; Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 18 / 56
17. Procházení stromu PREORDER: rekurze Záměnou pořadí tisku můžeme ilustrovat varianty INORDER, PREORDER, POSTORDER. Rekurzivní varianta: Strom.java public void preorder(uzel u) { if (u==null) return; else { System.out.println(u.data); //1. koren preorder(u.levy); //2. L podstrom preorder(u.pravy); //3. P podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 19 / 56
18. Procházení stromu PREORDER: zásobník Nekurzivní varianta s využitím zásobníku. public void preorder(uzel u) { Stack S = new Stack(); S.push (u); while (!S.empty()){ Uzel v = S.pop() System.out.println(v.data); //1. koren if (v.levy!= null) S.push(v.levy); //2. L podstrom if (v.pravy!= null) S.push(v.levy); //3. P podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 20 / 56
19. Procházení stromu INORDER: rekurze public void inorder(uzel u) { if (u==null) return; else { inorder(u.levy); //1. L podstrom System.out.println(u.data); //2. koren inorder(u.pravy); //3. P podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 21 / 56
20. Procházení stromu INORDER: zásobník public void inorder(uzel u) { Stack S = new Stack(); S.push (u); while (!S.empty()){ Uzel v = S.pop() if (v.levy!= null) S.push(v.levy); //1. L podstrom System.out.println(v.data); //2. koren if (v.pravy!= null) S.push(v.levy); //3. P podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 22 / 56
21. Procházení stromu POSTORDER: rekurze public void postorder(uzel u) { if (u==null) return; else { postorder(u.levy); //1. L podstrom postorder(u.pravy); //2. P podstrom System.out.println(u.data); //3. koren Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 23 / 56
22. Procházení stromu POSTORDER: zásobník public void postorder(uzel u) { Stack S = new Stack(); S.push (u); while (!S.empty()){ Uzel v = s.pop() if (v.levy!= null) S.push(v.levy); //1. L podstrom if (v.pravy!= null) S.push(v.levy); //2. P podstrom System.out.println(v.data); //3. koren Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 24 / 56
23. Přidání nového uzlu Složitost O(1.4 log(n)). Postup využívá rekurzivní prohledávání stromu ve směru od kořene k listům: nalezení vhodného uzlu a zařazení položky. Využijeme přístup PREORDER (nejprve zpracujeme kořen, poté levý podstrom, následně pravý podstrom) Postup přidání nového uzlu: 1 Otestujeme, zda je přidávaný uzel v kořenem 2 Pokud ano (v=null), vytvořen nový uzel. 3 Jinak: Je-li data < v.data (tj. kořen podstromu), přidáme v do levého podstromu V opačném případě přidáme v do pravého podstromu 4 Vrátíme odkaz na nově vytvořený kořen. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 25 / 56
24. Přidání nového uzlu: rekurze Strom.java private Uzel pridej(uzel v, int data) { //Rekurzivni metoda if (v==null) v=new Uzel(data); //Prazdny strom else { if(data<v.data) { //Pridani do L podstromu v.levy=pridej(v.levy, data); //Vrati odkaz na L podstrom else if(data>v.data) { //Pridani do P podstromu v.pravy= pridej(v.pravy,data); //Vrati odkaz na P podstrom else return null; //Prvek uz ve stromu je return v; //Odkaz na nove vytvoreny prvek public void pridejuzel(int data){ //Pridani, nerekurzivni metoda koren=pridej(koren, data); //Volani privatni rekurzivni metody Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 26 / 56
25. Přidání nového uzlu: nerekurzivní řešení void pridej(int data) { //Nekurzivni reseni if (root==null) { //Prazdny strom root=new Uzel(data); return; Uzel u = koren, p = u; //Urceni uzlu a jeho predchudce while (u!= null) //Opakuj, dokud nedojdeme do listu p = u; //Zapamatuj si predchudce if(data<u.data) u = u.levy; //Prohledavani L podstromu else if(data>u.data) u = u.pravy; //Prohledavani P podstromu else return; //Uz je ve stromu u = new Uzel (data); if (data < p.data) p.levy = u; //Pridani do L podstromu else p.pravy = u; //Pridani do P podstromu Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 27 / 56
26. Nalezení uzlu ve stromu Složitost C aver = 1.4 log(n). 1 Pokud je strom prázdný, ukončíme jeho prohledávání. 2 Jinak testujeme shodu uzlu a hledané položky. V případě shody ukončíme prohledávání. 3 Pokud hledaná položka menší než hodnota v L podstromu, hledáme v L podstromu. 4 Jinak prohledáme P podstrom. Poznámka k implementaci: Využití rekurze. Pokud je uzel nalezen, vracíme odkaz na něj. V opačném případě vracíme null. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 28 / 56
27. Nalezení uzlu v BST stromu, ukázka private Uzel najdi(int data, Uzel u) { //Rekurzivni metoda //Prazdny strom if (u==null) return null; //Rovnost s prvkem if (data==u.data) return u; //Vraceni uzlu //Prohledavani L podstromu if (data<u.data) return najdi (data,u.levy); //Prohledavani P podstromu else return najdi(data,u.pravy); public Uzel nalezeni(int data) { //Nerekurzivni metoda return najdi (data, koren); //Volani privatni rekurzivni met Na tomto principu založeno tzv. binární vyhledávání. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 29 / 56
28. Smazání stromu Složitost O(N). Mazání probíhá od kořene k uzlům. Nejprve mažeme levý podstrom, poté mažeme pravý podstrom. Jako poslední mažeme kořen. Postup mazání stromu: 1 Pokud je strom prázdný, ukončíme mazání. 2 Smažeme levý podstrom připojený k aktuálnímu uzlu u. 3 Smažeme pravý podstrom připojený k aktuálnímu uzlu u. 4 Smažeme uzel u. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 30 / 56
29. Smazání stromu, ukázka Strom.java public void smaz(uzel u) { if (u!=null) { //Neni strom prazdny? smaz(u.levy); //Smazani L podstromu smaz(u.pravy); //Smazani P podstromu u=null; //Prirazeni null korenu Využití POSTORDER procházení. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 31 / 56
30. Smazání uzlu Binární vyhledávací strom Složitost O(1.4 log(n)). Smazání uzlu představuje zřejmě implementačně nejtěžší operaci nad binárním stromem. Cílem je odstranění uzlu zadaného hodnotou ze stromu. Při mazání uzlu dochází ke třem situacím: Mazaný uzel je list. Mazaný uzel má jednoho následníka. Mazaný uzel má dva následníky. Varianty (1) (2) jednoduché, varianta (3) obtížnější. Postup mazání uzlu: 1 Test, zda se ve stromu vyskytuje uzel se zadaným klíčem. 2 Pokud se uzel ve stromu nevyskytuje, proces mazání je ukončen. 3 V opačném případě mohou nastat 3 situace (viz výše). Detekce, o jakou variantu se jedná. 4 Smazání uzlu. 5 Rekonstrukce sousedských vztahů (odkazy na L a P podstrom). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 32 / 56
31. Upravené prohledávání stromu Při hledání si zapamatujeme předchůdce p nalezeného uzlu u. Uzlu p následně upravíme odkaz na levý či pravý uzel (následník mazaného). private Uzel najdi(int data, Uzel u, Uzel p){ //Rekurzivni metoda //Prazdny strom if (u==null) return null; //Rovnost s prvkem if (data==u.data) return u; p=u; //Zapamatovani predchudce //Prohledavani L podstromu if (data<u.data) return najdi (data,u.levy,p); //Prohledavani P podstromu else return najdi(data,u.pravy,p); public Uzel hledej(int data) { //Nerekurzivni metoda Uzel n=null; return najdi(data, koren, n); //Volani rekurzivni privatni metody Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 33 / 56
32. Smazání uzlu, ukázka Strom.java public void smaz(int data) { //Rekurzivni metoda Uzel p; //Predchudce mazaneho uzlu //Upravene prohledavani, vraci predchudce Uzel u=najdi(data,p); if (u==null) return; //Uzel nenalezen else { //Uzel nalezen if ((u.levy==null)&&(u.pravy==null)) { //List smazlist(u,p); else if(u.levy==null u.pravy==null) { //1 potomek smaz1vetev(u,p); else smaz2vetve(u,p); //2 potomci Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 34 / 56
33. Smazání listu Metodě předáváme jako parametr předchůdce p uzlu u. Při mazání listu u mohou nastat dva případy: Mazaný list u je kořenem. Předchůdce listu u má adresu null. Uzel u smažeme. Mazaný list u není kořenem. Předchůdce uzlu u nemá adresu null. Otestujeme, zda na u ukazuje levý nebo pravý podstrom. Nastavíme p.levy=null nebo p.pravy=null. Nejjednodušší varianta, obejde se bez použití rekurze. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 35 / 56
34. Mazání uzlu (list) Odstranění uzlu a přesměrování odkazu z jeho předchůdce na null. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 36 / 56
35. Smazání listu, ukázka public void SmazList(Uzel u, Uzel p) { if (p==null) { //Koren koren=null; else { //Neni koren //L podstrom, smazani if (p.levy==u) p.levy=null; //P podstrom, smazani else p.pravy=null; Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 37 / 56
36. Smazání uzlu s jedním potomkem Metodě předáváme jako parametry uzel u a jeho předchůdce p. Zavádíme pomocnou proměnnou w, která představuje následníka u. Postup bez použití rekurze. Postup mazání uzlu: 1 Rozhodneme, zda je následník w mazaného uzlu u v jeho levém či pravém podstromu: w=u.levy nebo w=u.pravy. 2 Otestujeme, zda je mazaný prvek u kořenem: Pokud ano: bude w novým kořenem. V opačném případě zjistíme, zda je u levým či pravým následníkem p. Nastavíme uzlu p jako následníka uzel w. 3 Smazání uzlu u. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 38 / 56
37. Mazání uzlu (jeden následník) Přesměrování odkazu z předchůdce na následníka mazaného uzlu s následným smazáním uzlu. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 39 / 56
38. Smazání uzlu s jedním potomkem, ukázka Strom.java public void smaz1vetev(uzel u, Uzel p) { Uzel w; //Je naslednik mazaneho prvku L ci P naslednikem? if (u.levy!=null) w=u.levy; else w=u.pravy; //Je predchudce mazaneho prvek korenem? if(p==null) koren=w; else { if (p.levy!=u) p.levy=w; else p.pravy=w; u=null; //Smazani uzlu Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 40 / 56
39. Mazání uzlu (2 následníci) Implementačně nejtěžší varianta. Který uzel bude novým rodičovským uzlem po smazání rodiče? Vede k přeuspořádání stromu. Dvě možnosti: Metoda PL: pracuje s největší nižší hodnotou, než je hodnota v mazaném uzlu (list). Metoda LP: pracuje s nejmenší vyšší hodnotou, než je hodnota v mazaném uzlu (list). Postup mazání uzlu tvořen 3 kroky: 1 Nalezení nejpravějšího uzlu n v levém podstromu (je to list). Jde o uzel s největší hodnotou menší než hodnota rušeného uzlu (PL). [Nebo: Nalezení nejlevějšího uzlu n v pravém podstromu. (LP).] 2 Hodnotu n přesuneme do rušeného uzlu. 3 Zrušíme uzel n. Tomáš Řešení Bayer bayertom@natur.cuni.cz s rekurzí či bez (Katedra rekurze. aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 41 / 56
40. Mazání uzlu (2 následníci), varianta PL Nalezení nejpravějšího prvku v levém podstromu (list). Prohození pozice s mazaným prvkem. Zrušení listu. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 42 / 56
41. Mazání uzlu (2 následníci), varianta LP Nalezení nejlevějšího prvku v pravém podstromu (list). Prohození pozice s mazaným prvkem. Zrušení listu. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 43 / 56
42. Varianta PL Postup mazání uzlu: 1 Nalezení uzlu w v levém podstromu, který je následníkem u. 2 Nalezení nejpravějšího w uzlu a jeho předchůdce p: Inicializace p=u. Dokud existuje pravý podstrom (w.pravy!=null), tak: (1) zapamatuj si uzel w: p=w (2) inkrementuj w: w=w.pravy. 3 Prohození obsahu uzlů u a w. 4 Smazání uzlu w, 2 varianty: w je list: smaž list (w). w není list: smaž uzel s jedním následníkem (w). Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 44 / 56
43. Varianta PL: nerekurzivní varianta Strom.java public void smaz2vetve(uzel u) { Uzel w=u.levy; //Levy naslednik //Nejpravejsi uzel v L podstromu Uzel p=u; //Inicializace predchudce while (w.pravy!=null) { //Dokud existuje P uzel p=w; //Predchuce nejpravejsiho uzlu w=w.pravy; //Zamena uzlu u <-> w u.data=w.data; //presun dat mezi uzly //Smazani uzlu if (w.levy!=null w.pravy!=null) smaz1vetev(w,p); else smazlist(w,p); Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 45 / 56
44. Prohledávání stromu Strom lze procházet dvěma způsoby: Prohledávání do hloubky (Depth First Search). Postup stromem dolů tak dlouho, dokud je to možné. Jakmile narazí na list, couvá a do první neprozkoumané větve a postup opakuje. Analogie procházení bludištěm. Implementace zásobníkem. Prohledávání do šířky (Breadth First Search). Postup stromem do stran od kořene. Přechod na následující úroveň až po zpracování předchozí. Implementace frontou. Oproti obecným grafům odpadá nutnost značkovat vrcholy neexistence cyklu. Základní paradigmata používaná při řešení problémů, prohledávání stavového prostoru. Projdeme -li celý strom, nemůžeme minout řešení pozor, vede k exponenciálnímu nárůstu složitosti. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 46 / 56
45. Procházení stromu do hloubky DFS, tzv. backtracking. Postup od kořene stromem směrem dolů. V každém uzlu postupujeme vlevo, tj. zpracováváme levý podstrom, dokud nedorazíme do listu. Poté se vrátíme se do nejbližšího uzlu vyšší úrovně a pokračujeme pravým stromem. Pokud u uzlu prohledány oba podstromy, uzel opouštíme a vracíme se do nejbližšího uzlu vyšší úrovně. Každý uzel navštíven celkem 3x: od předchůdce, zpět z levého podstromu zpět z pravého podstromu. Tento průchod binárním stromem odpovídá metodě preorder. Implementace s využitím zásobníku. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 47 / 56
46. Ukázka procházení stromu DFS 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 48 / 56
47. Implementace DFS: zásobník Metoda bez použití značkování. public void dfs() { Stack s = new Stack(); s.push (root); while (!s.empty()){ Uzel v = s.pop(); //Udelej nejakou operaci s v if (v.pravy!= null) s.push(v.levy); //P podstrom if (v.levy!= null) s.push(v.levy); // L podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 49 / 56
48. Procházení stromu do šířky BFS. Postup od kořene stromu k listům po jednotlivých úrovních. Dokud nejsou zpracovány všechny uzly jedné úrovně, nepřesouváme se na úroveň další. Každá úroveň procházena postupně ve směru od nejlevějšího uzlu k nejpravějšímu. Na rozdíl od DFS se stromem nevracíme zpět. Implementace velmi podobná předchozí, místo zásobníku použita fronta. Uzly opět není nutné značkovat, graf neobsahuje cyklus. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 50 / 56
49. Ukázka procházení stromu do šířky 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 4 4 4 2 6 2 6 2 6 1 3 5 7 1 3 5 7 1 3 5 7 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 51 / 56
50. Implementace BFS: fronta Metoda bez použití značkování. public void dfs() { Query q = new Query(); q.push (root); while (!q.empty()){ Uzel v = q.pop(); //Udelej nejakou operaci s v if (v.levy!= null) q.push(v.levy); //L podstrom if (v.pravy!= null) q.push(v.levy); //P podstrom Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 52 / 56
51. Vyvážené stromy Vyvážené BST stromy BST stromy mají dobré výkonnostní charakteristiky, pozor na Worst case (degenerované stromy). O(N) O(N 2 ): tvorba stromu O(1.4 log(n)) O(N): hledání Způsobeny nevhodnou konfigurací vstupních množin: setříděné množiny, reverzně setříděné množiny, Střídání velkých a malých hodnot. Možnosti řešení: randomizace vstupních dat randomizované BST. průběžná optimalizace tvaru stromu převažování. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 53 / 56
Vyvážené BST stromy 52. Degenerovaný strom, setříděná množina Setříděná množina X 1 = {1, 2, 3, 4, 5, 6, reverzně setříděná množina X 2 = {6, 5, 4, 3, 2, 1. 1 6 2 5 3 4 4 3 5 2 6 1 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 54 / 56
Vyvážené BST stromy 53. Randomizované BST stromy Zavedení prvku náhodnosti při konstrukci stromu. Výhodou jednoduchost implementace a rychlost. Metody: Randomizace vstupní množiny Vytvoření počáteční permutace. Výběr náhodného uzlu s cílem zamezit vzniku degenerovaného stromu pro nevhodné množiny. Randomizované vkládání Modifikace standardního vkládání do BST stromu. Každý prvek může být se stejnou pravděpodobností p = 1/(n+1) kořenem stromu. Nový uzel může být vložen na libovolnou pozici mezi kořenem a cílovou pozicí pro nerandomizované vkládání. S pravděpodobností p rozhodneme o určitém prvku, zda bude/nebude kořenem. Oba postupy ekvivalentní. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 55 / 56
Vyvážené BST stromy 54. Ukázka randomizovaného vkládání: x=80 85 85 81 93 81 93 78 83 90 95 78 83 90 95 75 82 84 75 82 84 85 85 81 93 81 93 78 83 90 95 78 83 90 95 75 82 84 75 82 84 Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované Dynamické geoinformatiky datové struktury a kartografie, II. Přírodovědecká fakulta UK.) 56 / 56