Kreirati strukturu za predstavljanje čvora prefiksnog stabla. Napisati funkcije za umetanje reči u stablo i proveru da li se data reč nalazi u stablu.
/
/
Rešenje koristi prefiksno stablo čiji svaki čvor sadrži informaciju
da li predstavlja kraj neke reči i niz pokazivača na potomke za sve
ASCII karaktere. Funkcija za umetanje prolazi kroz slova reči, po
potrebi kreira nedostajuće čvorove i na kraju označava završni čvor kao
list. Funkcija za proveru prati istu putanju kroz stablo i vraća
true samo ako posle prolaska kroz celu reč stigne do čvora
koji je označen kao kraj reči.
Ako je dužina reči L, i umetanje i pretraga rade u
vremenu O(L). Memorijska složenost je proporcionalna
ukupnom broju kreiranih čvorova u stablu.
#include <iostream>
#include <vector>
#include <cstdlib>
// Moguci broj potomaka, ASCII tabela ima 128 karaktera
#define CHAR_SIZE 128
// Struktura cvor u kojoj cuvamo jedan cvor prefiksnog stabla
struct Node
{
// Zbog specificnosti prefiksnog stabla, i cvor koji ima potomke moze da bude list (vazno je samo da predstavlja kraj reci), cuvamo informaciju o tome da li je cvor list, odnosno
// da li se u njemu zavrsava neka rec
bool is_leaf;
// Niz u kome cem o cuvati potomke datog cvora, ukoliko potomak na nekoj poziciji ne postoji, imacemo nullptr na toj poziciji
Node *nodes[CHAR_SIZE];
};
Node *create_node()
{
// Ovde alokacija moze pomocu malloc() posto imamo niz fiksne duzine (128)
Node *new_node = (Node *)malloc(sizeof(Node));
// Inicijalno nijedan cvor nije list
new_node->is_leaf = false;
// Za svaki cvor kazemo da nema nijednog potomka na pocetku, a onda kasnije kreiramo potomke po potrebi
for (int i = 0; i < CHAR_SIZE; i++)
// Ne postoji nijedan potomak, tj svi su null
new_node->nodes[i] = nullptr;
return new_node;
}
// Funkcija za dodavanje reci u stablo, root je koren stabla, word rec koja se dodaje
void add_word(Node *root, std::string &word)
{
// Duzina reci
int n = word.length();
// Prolazimo kroz celu rec i proveravamo da li postoji potomak ka kome vodi grana sa oznakom i-tog karaktera niske word
for (int i = 0; i < n; i++) {
// Ukoliko nema grane kojom void i-ti karakter niske word (samim tim nema ni tog potomka) dodajemo granu (cvor)
if (root->nodes[(int)word[i]] == nullptr)
root->nodes[(int)word[i]] = create_node();
// Krecemo se niz odgovarajucu granu, tj preko odgovarajuceg cvora
root = root->nodes[(int)word[i]];
}
// Na kraju, dosli smo do kraja reci, pa nam bas ovaj cvor predstavlja list
root->is_leaf = true;
}
// Funckija koja proverava da li se rec nalazi u stablu. Vraca true ukoliko se nalazi, false inace. Funkcija je slicna funkciji za dodavanje reci
bool find_word(Node *root, std::string &word)
{
// Ukoliko trazimo u praznom stablu vracamo odmah false
if (root == nullptr)
return false;
// Duzina reci
int n = word.length();
// Idemo kroz rec i krecemo se niz odgovarajuce grane, ukoliko one postoje, ukoliko neka grana ne postoji to znaci da se i-ti karakter reci ne nalazi u stablu, tj nema ni reci,
// pa vracamo false
for (int i = 0; i < n; i++) {
root = root->nodes[(int)word[i]];
if (root == nullptr)
return false;
}
// Na kraju kada prodjemo kroz celu rec koju smo trazili
return root->is_leaf;
}
void free_tree(Node *root)
{
if (root == nullptr)
return ;
// Prvo oslobadjamo sva podstabla datog korena
for (auto &node : root->nodes)
free_tree(node);
// A nakon toga i sam koren. Alokacija je vrsena pomocu malloc() pa oslobadjanje mora pomocu free()
free(root);
}
int main ()
{
std::vector<std::string> words = {"cod", "coder", "coding", "codecs"};
Node *root = create_node();
for (std::string &s : words)
add_word(root, s);
std::string s = "code";
// boolalpha nam omogucava da pisemo true i false a ne 0 ili 1
std::cout << std::boolalpha << find_word(root, s) << std::endl;
free_tree(root);
return 0;
}