Cod sursa(job #2281595)

Utilizator petru.ciocirlanPetru Ciocirlan petru.ciocirlan Data 12 noiembrie 2018 15:42:36
Problema Trie Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.43 kb
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

struct trie
{
    /// Numarul de cuvinte prezente
    int number;

    /// Numarul de cuvinte care contin acest cuvant (fara number)
    int children;

    /// Vector din cupluri < caracter, pointer > pentru muchii
    vector < pair < char, trie* > > next;

    /// Constructor (initializeaza variabilele cu 0 la creare)
    trie()
    {
        number = children = 0;
    }
} *start;

void trie_insert(trie*, char*);
bool trie_delete(trie*, char*);
int trie_count(trie*, char*);
int trie_prefix(trie*, char*);

int main()
{
    freopen("trie.in", "r", stdin);
    freopen("trie.out", "w", stdout);

    /// Radacina arborelui (reprezinta cuvantul null "")
    start = new trie;

    char str[32];
    while(fgets(str, 32, stdin))
    {
        switch(str[0])
        {
            case '0': trie_insert(start, str+2); break;
            case '1': trie_delete(start, str+2); break;
            case '2': printf("%i\n", trie_count(start, str+2)); break;
            case '3': printf("%i\n", trie_prefix(start, str+2)); break;
            default: return 0;
        }
    }

    return 0;
}


/// Calculeaza lungimea celui mai lung prefix cu orice alt cuvant din lista
/// (cuvantul complet poate exista deja in lista)
int trie_prefix(trie *nod, char *str)
{
    int pos = 0;
    while(*str != '\n')
    {
        /// Cautam muchia cu caracterul (*str)
        vector < pair < char, trie* > > :: iterator it;
        for(it = nod->next.begin(); it != nod->next.end(); ++it)
            if(it->first == *str)
                break;


        /// Daca am ajuns la pozitia dupa elementele vectorului ( .end() )
        /// inseamna ca nu am gasit muchia (iteratorul a continuat pana la sfarsit)
        if(it == nod->next.end())
            break;

        /// Sarim (prin muchia it) la urmatorul nod
        nod = it->second;
        str++;
        pos++;
    }
    return pos;
}

/// Returneaza numarul de aparitii a cuvantului str
int trie_count(trie *nod, char *str)
{
    while(*str != '\n')
    {
        /// Cautam muchia cu caracterul (*str)
        vector < pair < char, trie* > > :: iterator it;
        for(it = nod->next.begin(); it != nod->next.end(); ++it)
            if(it->first == *str)
                break;

        /// Daca am ajuns la pozitia dupa elementele vectorului ( .end() )
        /// inseamna ca nu am gasit muchia (iteratorul a continuat pana la sfarsit)
        /// si suntem in cazul in care nu exista cuvantul in arbore (numarul de aparitii este 0)
        if(it == nod->next.end())
            return 0;

        /// Sarim (prin muchia it) la urmatorul nod
        nod = it->second;
        str++;
    }

    return nod->number;
}

/**
    Scadem numarul de aparitii a cuvantului str
    si stergem nodul daca numarul de aparitii devine 0
    (stergem si parintii ramasi frunze pana cand unul din ei nu este parte
     dintr-un cuvant prezent (nu are fii si nici nu reprezinta sfarsitul unui cuvant)
**/
bool trie_delete(trie *nod, char *str)
{
    /// Daca am ajuns la capatul cuvantului, scadem numarul de aparitii cu 1
    if(*str == '\n')
        nod->number--;
    else
    {
        /// Cautam muchia cu caracterul (*str)
        /// Problema asigura ca cuvantul sters este prezent
        vector < pair < char, trie* > > :: iterator it;
        for(it = nod->next.begin(); it != nod->next.end(); ++it)
            if(it->first == *str)
                break;

        /// Continuam stergerea
        if(trie_delete(it->second, str+1))
        {
            /// Daca nodul urmator a fost sters,
            /// actualizam nodul curent
            nod->children--;
            nod->next.erase(it);
        }
    }

    /**
        Daca nodul nu face parte din alte cuvinte prezente,
        nu reprezinta sfarsitul unui cuvant si nu coincide cu radacina
        stergem nodul (eliberam memoria) si returnam true pentru a semnala
        nodului parinte la intoarcerea pe stiva ca nodul acesta a fost sters
    **/
    if(nod->children == 0 && nod->number == 0 && nod != start)
    {
        delete nod;
        return true;
    }

    return false;
}

/// Crestem numarul de aparitii a cuvantului str
/// si creeam lantul de muchii in caz ca nu a fost creat inca
void trie_insert(trie *nod, char *str)
{
    while(*str != '\n')
    {
        /// Cautam muchia cu caracterul (*str)
        vector < pair < char, trie* > > :: iterator it;
        for(it = nod->next.begin(); it != nod->next.end(); ++it)
            if(it->first == *str)
                break;

        /**
            Daca am ajuns la pozitia dupa elementele vectorului ( .end() )
            inseamna ca nu am gasit muchia (iteratorul a continuat pana la sfarsit),
            astfel, alocam spatiu pentru nodul copil si ii tinem minte adresa
            in vectorul de muchii al nodului curent
        **/
        if(it == nod->next.end())
        {
            nod->next.push_back(make_pair(*str, new trie));

            /// Pentru ca nu am ajuns inca la sfarsit,
            /// inseamna ca nodul curent face parte dintr-un cuvant
            nod->children++;

            nod = nod->next.back().second;
        }
        else
            nod = it->second;

        str++;
    }

    /// La sfarist nodul va reprezenta cuvantul complet str (crestem numarul de aparitii)
    nod->number++;
}