Rozptylování, stromy - zákl. vlastnosti

Podobné dokumenty
Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Základní datové struktury III: Stromy, haldy

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Abstraktní datové typy

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

Rekurzivní algoritmy

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Abstraktní třídy, polymorfní struktury

Datové struktury 2: Rozptylovací tabulky

Stromy, haldy, prioritní fronty

Mělká a hluboká kopie

Programování v C++ 1, 16. cvičení

Jazyk C++, některá rozšíření oproti C

Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Algoritmy a datové struktury

Pole, množina, tabulka

5 Rekurze a zásobník. Rekurzivní volání metody

Volné stromy. Úvod do programování. Kořenové stromy a seřazené stromy. Volné stromy

Adresní vyhledávání (přímý přístup, zřetězené a otevřené rozptylování, rozptylovací funkce)

Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

NEJKRATŠÍ CESTY I. Doc. RNDr. Josef Kolář, CSc. Katedra teoretické informatiky, FIT České vysoké učení technické v Praze

Stromy. Jan Hnilica Počítačové modelování 14

bin arn ı vyhled av an ı a bst Karel Hor ak, Petr Ryˇsav y 23. bˇrezna 2016 Katedra poˇ c ıtaˇ c u, FEL, ˇ CVUT

Standardní algoritmy vyhledávací.

Přetěžování operátorů

Rekurze a zásobník. Jak se vypočítá rekurzivní program? volání metody. vyšší adresy. main(){... fa(); //push ret1... } ret1

Pokročilé haldy. prof. Ing. Pavel Tvrdík CSc. Fakulta informačních technologií České vysoké učení technické v Praze c Pavel Tvrdík, 2010

Programování v C++ 1, 17. cvičení

Red Black strom (Red Black Tree) Úvod do programování. Rotace. Red Black strom. Rotace. Rotace

Dynamické datové struktury II.

BINARY SEARCH TREE

Algoritmy výpočetní geometrie

Úvod do teorie grafů

Stromy. Jan Kybic.

Dynamické datové struktury IV.

2 Datové struktury. Pole Seznam Zásobník Fronty FIFO Haldy a prioritní fronty Stromy Hash tabulky Slovníky

Spojové struktury. Spojová struktura (linked structure):

PROHLEDÁVÁNÍ GRAFŮ. Doc. RNDr. Josef Kolář, CSc. Katedra teoretické informatiky, FIT České vysoké učení technické v Praze

Další příklady. Katedra softwarového inženýrství. Katedra teoretické informatiky, Fakulta informačních technologii, ČVUT v Praze. Karel Müller, 2011

a) b) c) Radek Mařík

BINARY SEARCH TREE

Dynamické datové struktury III.

Dynamické programování

Dynamické programování. Optimální binární vyhledávací strom

ALG 04. Zásobník Fronta Operace Enqueue, Dequeue, Front, Empty... Cyklická implementace fronty. Průchod stromem do šířky

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

R zné algoritmy mají r znou složitost

Šablony, kontejnery a iterátory

TGH07 - Chytré stromové datové struktury

bfs, dfs, fronta, zásobník, prioritní fronta, halda

Programování v C++ 2, 8. cvičení

1 Nejkratší cesta grafem

DobSort. Úvod do programování. DobSort Implementace 1/3. DobSort Implementace 2/3. DobSort - Příklad. DobSort Implementace 3/3

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

TGH07 - Chytré stromové datové struktury

bfs, dfs, fronta, zásobník, prioritní fronta, halda

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

STACK

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy

Základy algoritmizace. Hašování

součet cvičení celkem. známka. Úloha č.: max. bodů: skut. bodů:

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

Grafové algoritmy. Programovací techniky

DSA, První krok: máme dokázat, že pro left = right vrátí volání f(array, elem, left, right)

Datové struktury. alg12 1

Dědičnost. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 23.března

1. Převeďte dané číslo do dvojkové, osmičkové a šestnáctkové soustavy: a) b)

Spojové struktury. x, y, a, b. X1 y1 X2 y2 X3 y3. Grafické objekty bod. kružnice. obdélník. lomenáčára

6. Tahy / Kostry / Nejkratší cesty

Vyhledávací stromy. Slouží jako pomůcka pro organizaci dat umožňující efektivní vyhledávání.

STROMY A KOSTRY. Doc. RNDr. Josef Kolář, CSc. Katedra teoretické informatiky, FIT České vysoké učení technické v Praze. BI-GRA, LS 2010/2011, Lekce 6

Select sort: krok 1: krok 2: krok 3: atd. celkem porovnání. výběr nejmenšího klíče z n prvků vyžaduje 1 porovnání

V případě jazyka Java bychom abstraktní datový typ Time reprezentující čas mohli definovat pomocí třídy takto:

Dynamické datové struktury I.

Algoritmy na ohodnoceném grafu

C++ Akademie SH. 2. Prom nné, podmínky, cykly, funkce, rekurze, operátory. Michal Kvasni ka. 20. b ezna Za áte níci C++

ORIENTOVANÉ GRAFY, REPREZENTACE GRAFŮ

Grafové algoritmy. Programovací techniky

Dynamické struktury a Abstraktní Datový Typy (ADT)

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Lineární datové struktury

Šablony, kontejnery a iterátory

Část 1 Spojové struktury (stromy) Dynamické struktury a Abstraktní Datový Typy (ADT) Část 2 Abstraktní datový typ. Část 3 Příklad ADT Prioritní fronta

Dynamické programování

Algoritmy II. Otázky k průběžnému testu znalostí

Zápis programu v jazyce C#

Vyvažování a rotace v BVS, všude se předpokládá AVL strom

Binární vyhledávací stromy II

Základy C++ I. Jan Hnilica Počítačové modelování 18

AVL stromy. pro každý uzel u stromu platí, že rozdíl mezi výškou jeho levého a pravého podstromu je nejvýše 1 stromy jsou samovyvažující

Datové struktury. Obsah přednášky: Definice pojmů. Abstraktní datové typy a jejich implementace. Algoritmizace (Y36ALG), Šumperk - 12.

Jazyk C++ II. Šablony a implementace

Transkript:

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 1/55 Rozptylování, stromy - zákl. vlastnosti Ing. Josef Vogel, CSc Katedra softwarového inženýrství Katedra teoretické informatiky, Fakulta informačních technologii, ČVUT v Praze Karel Müller, Josef Vogel, 2011 Programování a algoritmizace 2, BI-PA2, 2011, Přednáška 12 BI-PA2 Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti

Témata Rozptylování princip otevřené rozptylování (open hashing) řetězení (chaining) = interpolační rozptylování uzavřené rozptylování (closed hashing) = otevřené adresování (open addressing) Stromy základní vlastnosti Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 2/55

Rozptylování Připomeňme si nejefektivnější metodu implementace množiny a tabulky: jsou-li hodnotami klíčů celá čísla z intervalu 0 až max, lze pro implementaci použít pole, jehož indexy jsou klíče a hodnotou prvku je v případě množiny true nebo false, v případě tabulky to jsou hodnoty odpovídající klíčům vyhledávání se v tomto případě nazývá adresním vyhledáváním (z klíče lze určit adresu umístění prvku v datové struktuře) a jeho složitost je O(1) Jestliže nelze stanovit vzájemně jednoznačné zobrazení mezi klíči a adresami umístění v datové struktuře, lze použít techniku rozptylování (hashing) Princip rozptylování (patří mezi adresní vyhledávání): pro klíč se vypočte adresa, zobrazení mezi klíči a adresami však není vzájemně jednoznačné (několika různým klíčům odpovídá stejná adresa) klíče, kterým odpovídá stejná adresa, se nazývají synonyma, a je pro ně třeba stanovit náhradní způsob umístění Funkce pro výpočet (základní) adresy umístění klíče se nazývá rozptylovací funkce (hash function) Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 3/55

Rozptylovací funkce Předpokládejme, že klíče chceme transformovat na indexy pole z intervalu 0 až m-1 (pole obsahuje m prvků) Příklad 1: klíče jsou kladná celá čísla int hash(int k, int m) {return k % m; Příklad 2: klíče jsou C-čkovské řetězce int hash(const char* s, int m) { int h = 0, len = strlen(s); for (int i=0; i<len; i++) h += s[i]; return h % m; Příklad 3: klíče jsou řetězce typu string int hash(string s, int m) { int h = 0, len = s.length(); for (int i=0; i<len; i++) h += s[i]; return h % m; Pozor: funkci hash nelze zavést pomocí šablony Podrobněji se bude rozptylovací funkcí zabývat předmět BI-EFA Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 4/55

Otevřené rozptylování Pole tvořené m prvky obsahuje m dílčích tabulek, v tabulce s indexem i jsou synonyma, pro které rozptylovací funkce dá výsledek i 0 1 tabulka pro hash(k,m)=0 tabulka pro hash(k,m)=1 Key hash(k, m)...... m-1 tabulka pro hash(k,m)=m-1 Dílčí tabulku lze realizovat různým způsobem, např. spojovým seznamem rozšiřitelným polem atd. Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 5/55

p12\hashset1\lnklst.h Otevřené rozptylování - řetězení Realizace dílčích tabulek pomocí spojového seznamu Šablona pro spojový seznam: // lnklst.h #include <iostream> using namespace std; template <class T> class LinkList { struct Elem { T key; Elem *next; Elem(T v, Elem *n) { key = v; next = n; ; Elem *head; Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 6/55

p12\hashset1\lnklst.h Otevřené rozptylování - řetězení Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 7/55 Pokračování šablony pro spojový seznam: public: LinkList() {head = NULL; bool isempty() const { return head == NULL; void add(t x) { if (!incl(x)) head = new Elem(x, head); void del(t x) { Elem *p=head, *pp=null; while (p && p->key!=x) { pp = p; p = p->next; if (p==null) return; if (pp==null) head = p->next; else pp->next = p->next; delete p;

p12\hashset1\lnklst.h Otevřené rozptylování - řetězení Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 8/55 Pokračování šablony pro spojový seznam: bool incl(t x) { Elem *p = head; while (p) if (p->key==x) return true; else p = p->next; return false; friend ostream& operator<<(ostream& s, const LinkList& l) { Elem *p = l.head; while (p) { s << p->key << ' '; p = p->next; return s; ;

p12\hashset1\hashset.h Otevřené rozptylování - řetězení Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 9/55 Deklarace třídy HashSet: // hashset.h #include "hash.h" #include "lnklst.h" #include <iostream> using namespace std; template <class Key> class HashSet { int m; LinkList<Key> *keys; public: HashSet(int m); ~HashSet(); void ins(key); bool incl(key) const; void del(key); void print() const; ;

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 10/55 Metody třídy HashSet: p12\hashset1\hashset.h Otevřené rozptylování - řetězení template <class Key> HashSet::HashSet(int m) { this->m = m; keys = new LinkList<Key>[m]; template <class Key> HashSet::~HashSet() { delete [] keys; template <class Key> void HashSet::ins(Key k) { int i = hash(k, m); keys[i].add(k); template <class Key> bool HashSet::incl(Key k) const { int i = hash(k, m); return keys[i].incl(k);

p12\hashset1\hashset.h Otevřené rozptylování - řetězení Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 11/55 Metody třídy HashSet (pokračování): template <class Key> void HashSet::del(Key k) { int i = hash(k, m); keys[i].del(k); template <class Key> void HashSet::print() const { for (int i=0; i<m; i++) if (!keys[i].isempty()) { cout << setw(3) << i << ": "; cout << keys[i] << endl; cout << endl;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 12/55 Klíče (včetně případné hodnoty) se ukládají do pole, jehož velikost omezuje počet prvků množiny (tabulky) Synonyma se ukládají do dalších prvků pole, např.s krokem 1 Podobně se postupuje při hledání Příklad: template <class Key> class HashSet { int m; int n; Key *keys; Key none; int search(key) const; public: HashSet(int m); ~HashSet(); bool incl(key) const; void ins(key); void del(key); void print() const; ;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 13/55 Příklad: template <class Key> HashSet::HashSet(int m) { this->m = m; n = 0; none = Key(); // co bude hodnotou pro int a string? keys = new Key[m]; for (int i=0; i<m; i++) keys[i] = none; template <class Key> HashSet::~HashSet() { delete [] keys;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 14/55 Příklad: template <class Key> int HashSet<Key>::search(Key k) const { int i = hash(k, m); while (keys[i]!=none) { if (keys[i]==k) return i; i = (i+1) % m; return i; template <class Key> bool HashSet<Key>::incl(Key k) const { int i = search(k); if (keys[i]==k) return true; return false;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 15/55 Příklad: template <class Key> void HashSet<Key>::ins(Key k) { cout << "vklada se klic " << k; int i = search(k); if (keys[i]==none) { int j = hash(k,m); cout << " s hash-kodem " << j; if (j!=i) cout << " - synonymum " << i; cout << endl; else { cout << " - klic uz v tabulce existuje" << endl; return; n++; if (n==m) { n--; throw "Ins: Hash table full!"; keys[i]=k;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 16/55 Příklad: template <class Key> void HashSet<Key>::del(Key k) { int i = hash(k, m); cout << "odebira se klic " << k << " s hash-kodem " << i << endl; i = search(k); if (keys[i]==none) return; n--; keys[i]=none; i = (i+1) % m; while (keys[i]!=none) { k = keys[i]; n--; keys[i] = none; ins(k); i = (i+1) % m;

p12\hashset2\hashset.h Uzavřené rozptylování Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 17/55 Příklad: template <class Key> void HashSet::print() const { cout << "n= << n << " faktor zaplneni << setprecision(2) << (float)n/m << endl; for (int i=0; i<m; i++) if (keys[i]!=none) cout << keys[i] << ' '; cout << endl;

Stromy Podle teorie grafů: Strom je souvislý neorientovaný graf bez kružnic Kořenový strom je orientovaný strom, ve kterém jeden uzel kořen je spojen s každým jiným uzlem jedinou orientovanou cestou V informatice se obvykle rozumí: Příklad grafického vyjádření: strom = kořenový strom Orientaci hran obvykle nekreslíme ale předpokládáme shora dolů Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 18/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 19/55 Stromy Strom bývá obvykle uzlově ohodnocený každý uzel obsahuje hodnotu určitého typu hodnota uzlu (případně její část, jde-li o strukturovanou hodnotu) je klíčem uzlu Příklad: 10 9 8 7 6 5 7

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 20/55 Stromy Některé pojmy: předchůdce (rodič) následník (potomek) kořen (nemá předchůdce) vnitřní uzel (má následníky) list (nemá následníky)

Stromy Stromy chápeme jako uspořádané, tzn. následníci každého vnitřního uzlu jsou pevným způsobem uspořádáni (první, druhý,..., v grafickém vyjádření zleva doprava) Příklad: následující dva stromy jsou různé Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 21/55

Stromy Hloubka uzlu délka (počet hran) cesty z kořene do uzlu Uzly, které mají stejnou hloubku, jsou na stejné úrovni (někdy se úrovně uzlů číslují od 1, tj. úroveň uzlu = hloubka uzlu + 1) Hloubka stromu (= výška stromu) délka nejdelší cesty hloubka uzlu 0 hloubka stromu 1 2 3 4 4 Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 22/55

Stromy výška stromu hloubka uzlu úroveň uzlu H 0 1 C M 1 2 3 K P 2 3 J 3 4 kořen stromu: H C M K J P výška stromu: 3 0 2 1 0 0 Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 23/55

Stromy Pravidelný strom stupně r (r>0): každý uzel má 0 nebo r následníků Úplný pravidelný strom stupně r (r>0): všechny listy mají hloubku stromu pravidelný strom stupně 3 úplný pravidelný strom stupně 3 Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 24/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 25/55 Binární stromy Binární strom: každý uzel má nanejvýš dva následníky levý následník pravý následník levý podstrom pravý podstrom

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 26/55 Binární stromy Pravidelný binární strom: každý uzel má 0 nebo 2 následníků Vyvážený binární strom: hloubky všech listů se liší nanejvýš o 1

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 27/55 Hloubka a počet uzlů vyváženého binárního stromu Úplný pravidelný binární strom (je vyvážený) hloubka uzlů 0 1 1 2 2 4 3 8 4 16 počet uzlů N = 2 H+1-1 hloubka H = log 2 (N + 1) - 1 k 2 k 2 k+1-1

Hloubka a počet uzlů extrémně nevyváženého binárního stromu Extrémně nevyvážený pravidelný binární strom hloubka uzlů 0 1 1 2 2 2 3 2 4 2 k-1 2 k 2 2k+1 počet uzlů N = 2H + 1 Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 28/55

Haldově uspořádaný strom Haldově uspořádaný strom je binární strom, ve kterém klíč každého uzlu je větší nebo roven klíčům následníků (max-heap) 10 9 8 7 6 5 7 Alternativní definice: Haldově uspořádaný strom je binární strom, ve kterém klíč každého uzlu je menší nebo roven klíčům následníků (min-heap) Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 29/55

Vyhledávací strom Vyhledávací strom je binární strom, ve kterém klíč každého vnitřního uzlu je větší než klíče uzlů v levém podstromu a menší než klíče uzlů v pravém podstromu 6 4 8 3 5 7 9 Alternativní definice: Vyhledávací strom je binární strom, ve kterém klíč každého vnitřního uzlu je menší než klíče uzlů v levém podstromu a větší než klíče uzlů v pravém podstromu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 30/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 31/55 Programová realizace stromu Kořenový strom, jehož uzly mohou mít libovolný počet následníků, lze realizovat pomocí spojového seznamu, jehož prvky jsou zase spojové seznamy Nelineární spojová struktura

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 32/55 Programová realizace stromu Pro uzly zavedeme třídu potomek bratr class Node { public: Node *child; T info; Node *brother; Node(Node *c, T x, Node *b) { child =c; info = x; brother = b; ;

Programová realizace stromu Jestliže strom je pravidelný stupně r nebo každý uzel má nanejvýš r následníků, můžeme spojový seznam nahradit objektem, který obsahuje pole ukazatelů na následníky Například: class Node { enum {R = 6;; T info; Node* childs[r]; Node(T x) { info = x; for (int i=0; i<r; i++) childs[i] = NULL; ; Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 33/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 34/55 Programová realizace binárního stromu Binární strom lze realizovat pomocí nelineární spojové struktury, jejíž uzly budou obsahovat ukazatele na levého a pravého následníka

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 35/55 Programová realizace binárního stromu Pro uzly zavedeme třídu levý následník pravý následník class Node { public: T info; Node *left; Node *right; Node(T i, Node l=null; Node r=null) { info = i; left = l; right = r; ;

p12\btree\binstrom1.cpp Programová realizace binárního stromu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 36/55 Příklad: funkce pro vytvoření náhodného binárního stromu dané maximální hloubky inline int random(int m) { // vysledkem je pseudonahodne cislo z intervalu 0 az m-1 return rand()%m; Node *randtree(int depth) { if (depth<=0 random(10)>7) return NULL; return new Node(random(100), randtree(depth-1), randtree(depth-1)); pokud tento test vypustíme, bude vytvořený strom vždy pravidelný a úplný

p12\btree\binstrom2.cpp Výpis binárního stromu Předchozí program vytvořil náhodný binární strom (pomocí rekurzívní funkce), ale jak ho vypsat? Pomocí rekurzívní funkce, která: vypíše hodnotu v uzlu, na který ukazuje parametr funkce, rekurzívním voláním vypíše uzly v levém podstromu rekurzívním voláním vypíše uzly v pravém podstromu Parametrem funkce bude kromě ukazatele na uzel také číslo udávající, kolik mezer má být vypsáno před hodnotou uzlu (odsazení podle hloubky uzlu) void print(node *p, int s) { if (p) { cout << setw(s) << ' ' << p->info << endl; print(p->left, s+1); print(p->right, s+1); else cout << setw(s) << ' ' << "null" << endl; Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 37/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 38/55 Výpis binárního stromu Program binstrom2.cpp např. vypíše: 67 0 null 78 null 64 null null 45 27 91 null null 42 null null 36 4 null null 53 null null 67 0 45 78 27 36 64 91 42 4 53 grafické vyjádření vytvořeného stromu

Průchody binárním stromem Funkce print v programu binstrom2.cpp je příkladem průchodu binárním stromem shora dolů v pořadí Preorder Další způsoby průchodu binárním stromem jsou Inorder a Postorder Preorder: pro každý uzel se provede: operace s hodnotou uzlu vyvolání průchodu pro levého následníka vyvolání průchodu pro pravého následníka Inorder: pro každý uzel se provede: vyvolání průchodu pro levého následníka operace s hodnotou uzlu vyvolání průchodu pro pravého následníka Postorder: pro každý uzel se provede: vyvolání průchodu pro levého následníka vyvolání průchodu pro pravého následníka operace s hodnotou uzlu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 39/55

p12\btree\binstrom3.cpp Výpis binárního stromu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 40/55 Průchodem Inorder: void printinorder(node *p, int s) { if (p) { printinorder(p->left, s+1); cout << setw(s) << ' ' << p->info << endl; printinorder(p->right, s+1); else cout << setw(s) << ' ' << "null" << endl; Průchodem Postorder: void printpostorder(node *p, int s) { if (p) { printpostorder(p->left, s+1); printpostorder(p->right, s+1); cout << setw(s) << ' ' << p->info << endl; else cout << setw(s) << ' ' << "null" << endl;

p12\btree\pocetuzlu.cpp Počet uzlů binárního stromu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 41/55 Funkce pro výpočet počtu uzlů binárního stromu int count(node *p) { if (p) return count(p->left)+count(p->right)+1; else return 0;

p12\btree\hloubkastromu.cpp Hloubka binárního stromu Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 42/55 inline int max(int x, int y) { return x>y? x : y; int depth(node *p) { if (p) return max(depth(p->left), depth(p->right)) + 1; else return -1;

p12\btree\pocetuzlu2.cpp Implementace rekurze pomocí zásobníku Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 43/55 Funkci pro výpočet počtu uzlů binárního stromu napíšeme nerekurzívně Postup: požijeme zásobník ukazatelů na uzly stromu opakovaně, dokud se zásobník nevyprázdní, odebereme z vrcholu ukazatel a pokud není NULL, zvětšíme počítadlo uzlů a a do zásobníku vložíme ukazatele na levého a pravého potomka na začátku do zásobníku vložíme ukazatel na kořen stromu int count2(node *p) { Stack<Node*> stc; int cnt = 0; stc.push(p); while (!stc.empty()) { Node *q = stc.pop(); if (q) { cnt++; stc.push(q->right); stc.push(q->left); return cnt;

Implementace rekurze pomocí zásobníku Proceduru pro výpis stromu metodou preorder napíšeme nerekurzívně Postup: do zásobníku budeme ukládat dvojice <ukazatel na uzel, počet mezer> opakovaně, dokud se zásobník nevyprázdní, odebereme z vrcholu dvojici, vypíšeme počet mezer, a pokud ukazatel není NULL, vložíme do zásobníku ukazatel na pravého následníka a pak ukazatel na levého následníka (pořadí je důležité); pokud je ukazatel null, vypíšeme null na začátku vložíme do zásobníku dvojici obsahující ukazatel na kořen a 1 Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 44/55

p12\btree\binstrom4.cpp Implementace rekurze pomocí zásobníku struct Pair { Node *ptr; int spc; Pair(Node *p, int s) { ptr = p; spc = s; ; void print2(node *p, int s) { Stack<Pair> stc; stc.push(pair(p,s)); while (!stc.empty()) { Pair pair = stc.pop(); cout << setw(pair.spc) << ' '; if (pair.ptr) { cout << pair.ptr->info << endl; stc.push(pair(pair.ptr->right, pair.spc+1)); stc.push(pair(pair.ptr->left, pair.spc+1)); else cout << "null" << endl; Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 45/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 46/55 Binární vyhledávací strom Připomenuti: Binární vyhledávací strom je binární strom, ve kterém klíč každého vnitřního uzlu je větší než klíče uzlů v levém podstromu a menší než klíče uzlů v pravém podstromu (ostrá nerovnost může být nahrazena neostrou) 6 4 8 3 5 7 9 Alternativní definice: Vyhledávací strom je binární strom, ve kterém klíč každého vnitřního uzlu je menší než klíče uzlů v levém podstromu a větší než klíče uzlů v pravém podstromu (ostrá nerovnost může být nahrazena neostrou)

p12\bstree\node.h, bstree.h Programová realizace BVS Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 47/55 BVS je tvořen uzly, každý uzel obsahuje: klíč (případně další data) ukazatele na levého a pravého potomka class Node { key Key key; Node *left; left right Node *right; public: Node(... ); key key Key getkey() const; Node *getleft() const; left right left right Node *getright() const; ; Objekt typu BVS obsahuje ukazatel na kořen stromu class BSTree { Node *root; public: BSTree() {root = NULL;... ;

Programová realizace BVS Pro některé operace s BVS je třeba k uzlu najít rodiče Pro určení rodiče uzlu lze zavést metodu stromu (časově náročné), nebo doplnit ukazatel na rodiče do každého uzlu class Node { Node *parent; Key key; Node *left; Node *right; public: Node(... ); Node *getparent() const; Key getkey() const; Node *getleft() const; Node *getright() const; ; parent key left right parent parent key key left right left right Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 48/55

Počet uzlů ~ hloubka stromu Pro hloubku h BVS s n uzly platí: v nejhorším případě je h = n 1 v nejlepším případě je h = Příklad pro n = 5 nejlepší případ (h=2) nejhorší případ (h=4) vyvážený strom nevyvážený strom Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 49/55

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 50/55 Výpis BVS průchodem Inorder Vypíšeme-li uzly BVS průchodem Inorder, dostaneme vzestupnou posloupnost klíčů všech uzlů void printio(node *p) { if (p) { printio(p->getleft()); cout << ' ' << p->getkey(); printio(p->getright());

Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 51/55 Výpis BVS průchodem Inorder Pro strom H D N B F J S A C E G I M P bude výstupem A B C D E F G H I J M N P S

p12\bstree\node.cpp Vyhledávání v BVS Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 52/55 Rekurzivní: Node *searchr(node *x, Key k) { if (x==null x->key==k) return x; if (k<x->key) return searchr(x->left, k); else return searchr(x->right, k); Iterační: Node *search(node *x, Key k) { while (x && x->key!= k) if (k < x->key) x = x->left; else x = x->right; return x; Realizace pomocí šablon je v adresáři bstree-s

p12\bstree1\bstree.cpp Vložení uzlu do BVS Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 53/55 Najde se rodič pp pro nový uzel n Nový uzel n (je to list) se stane potomkem uzlu pp H ins( F ) H D pp N D N B F n B F void BSTree::ins(Key k) { Node *p = root, *pp = NULL; if (p==null) {root = new Node(k); return; do { pp = p; if (k < p->key) p = p->left; else if (k > p->key) p = p->right; else return; while (p); Node *n = new Node(k); if (k < pp->key) pp->left = n; else pp->right = n;

p12\bstree1\main.cpp Vložení uzlu do BVS Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 54/55 Jaký strom vznikne, vkládáme-li uzly v pořadí daném následujícím polem: char a[] = {'H','D','N','B','F','J','S','A','C','E','G','I','M','P'; int na = sizeof(a)/sizeof(char); BSTree t; for (int i=0; i<na; i++) t.ins(a[i]); H D N B F J S A C E G I M P

p12\bstree1\main.cpp Vložení uzlu do BVS Karel Müller, Josef Vogel (ČVUT FIT) Rozptylování, stromy - zákl. vlastnosti BI-PA2, 2011, Přednáška 12 55/55 Jaký strom vznikne, vkládáme-li uzly v pořadí daném následujícím polem: char b[] = {'A','B','C','D','E','F','G','H','I','J','M','N','P','S'; int nb = sizeof(b)/sizeof(char); BSTree tb; for (int i=0; i<nb; i++) tb.ins(a[i]); A B C D P S