Programovanie (1) v C/C++
1-INF-127, ZS 2024/25
Prednáška 21: Rozdiel medzi revíziami
(→Oznamy) |
|||
Riadok 15: | Riadok 15: | ||
[[Image:P22-BST.png|200px|right|thumb|Príklad binárneho vyhľadávacieho stromu.]] | [[Image:P22-BST.png|200px|right|thumb|Príklad binárneho vyhľadávacieho stromu.]] | ||
− | Stromy sa v informatike | + | Stromy sa v informatike používajú na veľa účelov. Ďalším príkladom sú binárne vyhľadávacie stromy, ktoré môžu slúžiť na implementovanie abstraktného dátového typu dynamická množina, ktorý sme videli na [[Prednáška 14#Dynamick.C3.A1_mno.C5.BEina_2|prednáške 14]]. Prvky množiny nebudeme ukladať do poľa, ani v spájaného zoznamu, ale do vrcholoch binárneho stromu. |
* V binárnom vyhľadávacom strome má každý vrchol 0,1 alebo 2 deti | * V binárnom vyhľadávacom strome má každý vrchol 0,1 alebo 2 deti | ||
* V každom vrchole máme položku s dátami (pre jednoduchosť typu <tt>int</tt>) | * V každom vrchole máme položku s dátami (pre jednoduchosť typu <tt>int</tt>) | ||
Riadok 23: | Riadok 23: | ||
* Z toho vyplýva, že ak vypíšeme strom v inorder poradí, dostaneme prvky usporiadané | * Z toho vyplýva, že ak vypíšeme strom v inorder poradí, dostaneme prvky usporiadané | ||
* Pre danú množinu kľúčov existuje veľa vyhľadávacích stromov | * Pre danú množinu kľúčov existuje veľa vyhľadávacích stromov | ||
− | |||
''Cvičenie'': nájdite všetky binárne vyhľadávacie stromy pozostávajúce z troch uzlov s kľúčmi ''1, 2, 3''. | ''Cvičenie'': nájdite všetky binárne vyhľadávacie stromy pozostávajúce z troch uzlov s kľúčmi ''1, 2, 3''. | ||
Riadok 43: | Riadok 42: | ||
}; | }; | ||
− | /* Samotná | + | /* Samotná dynamická množina (obal pre používateľa). */ |
− | struct | + | struct set { |
node *root; /* koreň stromu, NULL pre prázdny strom */ | node *root; /* koreň stromu, NULL pre prázdny strom */ | ||
}; | }; | ||
Riadok 52: | Riadok 51: | ||
<syntaxhighlight lang="C++"> | <syntaxhighlight lang="C++"> | ||
/** Funkcia inicializuje prázdny binárny vyhľadávací strom */ | /** Funkcia inicializuje prázdny binárny vyhľadávací strom */ | ||
− | void | + | void init(set &s) { |
− | + | s.root = NULL; | |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Riadok 59: | Riadok 58: | ||
=== Likvidácia binárneho vyhľadávacieho stromu === | === Likvidácia binárneho vyhľadávacieho stromu === | ||
− | Likvidáciu podstromu zakoreneného v danom uzle <tt>root</tt> realizujeme funkciou <tt>destroy</tt>, obdobne ako pri všeobecných binárnych stromoch. Používateľovi navyše dáme k dispozícii aj funkciu <tt> | + | Likvidáciu podstromu zakoreneného v danom uzle <tt>root</tt> realizujeme funkciou <tt>destroy</tt>, obdobne ako pri všeobecných binárnych stromoch. Používateľovi navyše dáme k dispozícii aj funkciu <tt>destroy</tt>, ktorá dostane množinu implementovanú ako strom a tento strom zlikviduje. |
<syntaxhighlight lang="C++"> | <syntaxhighlight lang="C++"> | ||
Riadok 71: | Riadok 70: | ||
} | } | ||
− | /* Zlikviduje | + | /* Zlikviduje množinu s (uvolni pamat). */ |
− | void | + | void destroy(set &s) { |
− | destroy( | + | destroy(s.root); |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Riadok 87: | Riadok 86: | ||
* Dá sa zapísať rekurzívne alebo cyklom, lebo vždy ideme iba do jedného podstromu | * Dá sa zapísať rekurzívne alebo cyklom, lebo vždy ideme iba do jedného podstromu | ||
− | Funkcia <tt> | + | Funkcia <tt>contains</tt> zavolá funkciu <tt>findNode</tt> pre koreň daného binárneho vyhľadávacieho stromu <tt>t</tt> a pomocou nej zistí, či tento strom obsahuje uzol s kľúčom <tt>key</tt>. |
<syntaxhighlight lang="C++"> | <syntaxhighlight lang="C++"> | ||
Riadok 104: | Riadok 103: | ||
} | } | ||
− | / | + | /* Rekurzívna verzia */ |
node *findNodeR(node *root, int key) { | node *findNodeR(node *root, int key) { | ||
if (root == NULL || key == root->data) { | if (root == NULL || key == root->data) { | ||
Riadok 115: | Riadok 114: | ||
} | } | ||
− | /* Zisti, ci strom | + | /* Zisti, ci strom reprezentujuci mnozinu s |
− | bool | + | * obsahuje uzol s klucom key. */ |
− | return findNode( | + | bool contains(set &s, int key) { |
+ | return findNode(s.root, key) != NULL; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Čas výpočtu je v najhoršom prípade úmerný výške stromu. | Čas výpočtu je v najhoršom prípade úmerný výške stromu. |
Verzia zo dňa a času 19:24, 3. december 2022
Obsah
Oznamy
Binárne vyhľadávacie stromy
Stromy sa v informatike používajú na veľa účelov. Ďalším príkladom sú binárne vyhľadávacie stromy, ktoré môžu slúžiť na implementovanie abstraktného dátového typu dynamická množina, ktorý sme videli na prednáške 14. Prvky množiny nebudeme ukladať do poľa, ani v spájaného zoznamu, ale do vrcholoch binárneho stromu.
- V binárnom vyhľadávacom strome má každý vrchol 0,1 alebo 2 deti
- V každom vrchole máme položku s dátami (pre jednoduchosť typu int)
- Pre každý vrchol v stromu platí:
- Každý vrchol v ľavom podstrome v má hodnotu data menšiu ako vrchol v
- Každý vrchol v pravom podstrome v má hodnotu data väčšiu ako vrchol v
- Z toho vyplýva, že ak vypíšeme strom v inorder poradí, dostaneme prvky usporiadané
- Pre danú množinu kľúčov existuje veľa vyhľadávacích stromov
Cvičenie: nájdite všetky binárne vyhľadávacie stromy pozostávajúce z troch uzlov s kľúčmi 1, 2, 3.
Definícia dátových štruktúr
Vrchol typu node
- Položka data typu int
- Smerník na ľavé a pravé dieťa
- Na niektoré úlohy (napr. mazanie vrcholu) sa hodí aj smerník na rodiča (ten má hodnotu NULL v koreni)
Celý strom je štruktúra obsahujúca iba smerník na koreň
- Pre prázdny strom je to NULL.
struct node {
/* vrchol binárneho vyhľadávacieho stromu */
int data; /* hodnota */
node * parent; /* rodič vrchola, NULL v koreni */
node * left; /* ľavé dieťa, NULL ak neexistuje */
node * right; /* pravé dieťa, NULL ak neexistuje */
};
/* Samotná dynamická množina (obal pre používateľa). */
struct set {
node *root; /* koreň stromu, NULL pre prázdny strom */
};
Inicializácia prázdneho binárneho vyhľadávacieho stromu
/** Funkcia inicializuje prázdny binárny vyhľadávací strom */
void init(set &s) {
s.root = NULL;
}
Likvidácia binárneho vyhľadávacieho stromu
Likvidáciu podstromu zakoreneného v danom uzle root realizujeme funkciou destroy, obdobne ako pri všeobecných binárnych stromoch. Používateľovi navyše dáme k dispozícii aj funkciu destroy, ktorá dostane množinu implementovanú ako strom a tento strom zlikviduje.
/* Uvolni pamat pre podstrom s korenom *root. */
void destroy(node *root) {
if (root != NULL) {
destroy(root->left);
destroy(root->right);
delete root;
}
}
/* Zlikviduje množinu s (uvolni pamat). */
void destroy(set &s) {
destroy(s.root);
}
Hľadanie v binárnom vyhľadávacom strome
Funkcia findNode v podstrome s koreňom root hľadá uzol, ktorého položka dáta obsahuje hľadaný kľúč key. Vráti takýto uzol alebo NULL ak neexistuje
- Najskôr porovná hľadaný kľúč s dátami v koreni
- Ak sa rovnajú, končíme (našli sme, čo hľadáme)
- Ak je hľadaná hodnota menšia ako dáta v koreni, musí byť v ľavom podstrome, ak je väčšia v pravom
- V príslušnom podstrome sa rozhodujeme podľa tých istých pravidiel
- Keď narazíme na prázdny podstrom, dáta sa v strome nenachádzajú
- Dá sa zapísať rekurzívne alebo cyklom, lebo vždy ideme iba do jedného podstromu
Funkcia contains zavolá funkciu findNode pre koreň daného binárneho vyhľadávacieho stromu t a pomocou nej zistí, či tento strom obsahuje uzol s kľúčom key.
/* Ak v strome s korenom root existuje uzol s klucom key,
* vrati ho na vystupe. Inak vrati NULL. */
node * findNode(node *root, int key) {
node * v = root;
while (v != NULL && v->data != key) {
if (key < v->data) {
v = v->left;
} else {
v = v->right;
}
}
return v;
}
/* Rekurzívna verzia */
node *findNodeR(node *root, int key) {
if (root == NULL || key == root->data) {
return root;
} else if (key < root->data) {
return findNodeR(root->left, key);
} else { // key > root->data
return findNodeR(root->right, key);
}
}
/* Zisti, ci strom reprezentujuci mnozinu s
* obsahuje uzol s klucom key. */
bool contains(set &s, int key) {
return findNode(s.root, key) != NULL;
}
Čas výpočtu je v najhoršom prípade úmerný výške stromu.