Úloha 4.1
Napíšte program, zdrojový kód, v jazyku C++ použitím štandardu C++17, ktorý realizuje nasledovnú činnosť.
Implementujte N-árny strom, t.j. strom ktorého uzol môže mať 0 až N detí. Každý uzol stromu má označenie ‘label’
typu string
. Deti uzla musia byť unikátne. Uzol implementujte ako triedu. Aplikujte princípy zaprúzdrenia (private
atribúty, getter, setter a ďalšie).
Pre uzol implementujte metódu:
bool add_child(Node*)
- Pridá do uzla nový detský uzol. Metóda pridá uzol ako dieťa len ak poskytnutý uzol ešte nie je medzi detskými uzlami. Metóda vráti true ak bol uzol úspešne pridaný medzi deti, inak vráti false.
Implementujte metódu string &traverse(Node*)
, ktorá bude implementovať prechádzanie stromu do hĺbky. Metódu
implementujte pomocou rekurzie. Metóda vráti string
, ktorý obsahuje označenie uzlov, cez ktoré algoritmus prechádzal
oddelené čiarkou.
Pre demonštráciu vypracovania vytvorte strom aspoň hĺbky 3 s ľubovolným počtom uzlov. Následne zavolajte metódu traverse()
a výstup metódy vypíšte na štandardný výstup (cout
).
Príklady vstupov / výstupov programu
Majme strom:
Ak je strom implementovaný podľa zadania, tak výstup metódy traverse je
1, 2, 5, 6, 7, 8, 4, 3
Rozbaľ pre ukážku riešenia
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Node {
private:
string label;
vector<Node*> children;
public:
// Konštruktor
explicit Node(const string& label) : label(label) {}
// Getter pre label
const string& get_label() const {
return label;
}
// Setter pre label
void set_label(const string& new_label) {
label = new_label;
}
// Getter pre deti
const vector<Node*>& get_children() const {
return children;
}
// Pridá dieťa, ak ešte nie je medzi deťmi (porovnáva pointer aj label)
bool add_child(Node* child) {
if (child == nullptr) return false;
for (size_t i = 0; i < children.size(); ++i) {
if (children[i] == child || children[i]->get_label() == child->get_label()) {
return false; // už existuje
}
}
children.push_back(child);
return true;
}
};
// Rekurzívna funkcia na DFS prechod stromom
string traverse(Node* node) {
if (node == nullptr) return "";
string result = node->get_label();
const vector<Node*>& children = node->get_children();
for (size_t i = 0; i < children.size(); ++i) {
string sub = traverse(children[i]);
if (!sub.empty()) {
result += "," + sub;
}
}
return result;
}
int main() {
// Vytvorenie uzlov
Node* root = new Node("A");
Node* b = new Node("B");
Node* c = new Node("C");
Node* d = new Node("D");
Node* e = new Node("E");
Node* f = new Node("F");
Node* g = new Node("G");
// Budovanie stromu
root->add_child(b);
root->add_child(c);
root->add_child(d);
b->add_child(e);
b->add_child(f);
d->add_child(g);
// Prechod stromu
string output = traverse(root);
cout << "DFS Traversal: " << output << endl;
// Uvoľnenie pamäte (keďže nepoužívame smart pointery)
delete root;
delete b;
delete c;
delete d;
delete e;
delete f;
delete g;
return 0;
}
Vysvetlenie kódu
1. Trieda Node
Predstavuje jeden uzol stromu. Obsahuje:
label
– názov/označenie uzla (napr."A"
,"B"
, atď.)children
– zoznam (vektor) ukazovateľov na detské uzly
Dôležité metódy:
get_label()
aset_label()
– prístup k názvu uzlaget_children()
– prístup k zoznamu detíadd_child(Node*)
– pridanie dieťaťa, len ak ešte neexistuje (podľa pointera alebo mena)
2. Funkcia traverse(Node*)
Implementuje pre-order (do hĺbky) prechod stromom:
- Najprv navštívi aktuálny uzol
- Potom rekurzívne prechádza všetky deti uzla
- Výsledok je jeden reťazec s názvami uzlov oddelenými čiarkou
3. Funkcia main()
- Vytvorí uzly stromu
- Poskladá strom pomocou
add_child()
- Zavolá
traverse()
na koreň - Vypíše výsledok na štandardný výstup
- Uvoľní alokovanú pamäť (
delete
)
Vizualizácia stromu
Strom vyzerá takto (každý uzol je označený písmenom):
A
/ | \
B C D
/ \ \
E F G
- Koreň je
A
A
má 3 deti:B
,C
,D
B
má 2 deti:E
,F
D
má 1 dieťa:G
C
,E
,F
,G
sú listy (nemajú deti)
Výstup funkcie traverse(root)
Prechod do hĺbky (pre-order) navštívi uzly v tomto poradí:
A → B → E → F → C → D → G
Čiže:
DFS Traversal: A,B,E,F,C,D,G