Cod sursa(job #2222653)

Utilizator bogdanpaunFMI Paun Bogdan Gabriel bogdanpaun Data 17 iulie 2018 17:08:08
Problema Trie Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 6.27 kb
#include <iostream>
#include <assert.h>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

/*
to do:
if it can be deleted -> traverse from head to leaf ( delete parent?? )
check https://infoarena.ro/job_detail/1666508?action=view-source

*/


template<typename counterType>
struct NodeTypeCatalog{

    struct TrieNodeBasic{
        counterType wordCount,prefixCount;
        TrieNodeBasic* child[26];
        TrieNodeBasic* parent;

        typedef counterType size_t;

        TrieNodeBasic() {
            char* _begin = (char*)(this);
            _memset( _begin, _begin + sizeof(TrieNodeBasic) );
        }
        TrieNodeBasic(TrieNodeBasic* parent) {
            char* _begin = (char*)(this);
            _memset( _begin, _begin + sizeof(TrieNodeBasic) );
            this->parent = parent;
        }

        TrieNodeBasic* push(char c){
            if( ! this->valid(c)){
                return nullptr;
            }
            c = position( repair(c) );
            if( this->child[c] == nullptr ){
                this->child[c] = new TrieNodeBasic(this);
            }
            this->child[c]->markPrefix();
            return this->child[c];
        }


        TrieNodeBasic* next(char c){
            if( ! this->valid(c)){
                return nullptr;
            }
            return  this->child[ position( repair(c) ) ];
        }

        void clean(const TrieNodeBasic* head, const string &word){
            TrieNodeBasic* current = this;
            uint64_t index = 0;

            while( current != head && current->prefixCount == 1){
                ++index;
                TrieNodeBasic* toBeDeleted = current;
                current = current->parent;
                delete toBeDeleted;
            }
            index = word.size() - index;
            current->child[ word[index] -'a' ] = 0;

            while( current != head ){
                current->unmark();
                current = current->parent;
            }
        }

        void forget(char c){
            if( ! this->valid(c)){
                return;
            }
            this->child[ position( repair(c) ) ] = nullptr;

        }

        void markWord(){
            ++wordCount;
        }
        void unmarkWord(){
            --wordCount;
        }
        void markPrefix(){
            ++prefixCount;
        }
        void unmarkPrefix(){
            --prefixCount;
        }
        counterType countWord(){
            return wordCount;
        }
        counterType countPrefix(){
            return prefixCount;
        }

    private:
        bool valid(const char key){
            return ( key >= 'a' && key <= 'z' );
        }

        char repair(const char c){
            return c;   //to be modified in derived classes
        }

        char position(const char c){
            return c - 'a';
        }

    };
private:
    void static _memset(char* _begin, const char *_end)
    {
        assert( _begin < _end );    //invalid call
        while(  _begin < _end )
        {
            *_begin = 0;
            ++_begin;
        }

    }



};



template<class NodeType>
class Trie
{

public:

    Trie(){
        this->head = new NodeType();
    }

    void pushWord(const string& word){
        NodeType* current = this->head;
        for( char c : word){
            assert( current = current->push(c) );
        }
        current->markWord();
    }

    int32_t popWord(const string& word){
        if( countWord(word) > 0 ){
            return unmarkWord(word);
        }
        else{
            return -1;
        }
    }

    int32_t unmarkWord(const string& word){

        NodeType* current = this->head;
        NodeType* older   = this->head;
        bool toDelete = false;
        for( char c : word){
            assert( current = current->next(c) );
            switch( toDelete ){

            case false:
                current->unmarkPrefix();
                if( current->countPrefix() == 0 ){
                    toDelete = true;
                    older->forget(c);
                }
                break;
            case true:
                delete older;
                break;
            default:
                assert( false );
            }
            older = current;
        }
        if( toDelete && older != this->head ){
            delete older;
        }else{
            current->unmarkWord();
        }

        return 0;
    }


    typename NodeType::size_t
    countWord(const string& word)
    {
        NodeType* current = this->head;
        for( char c : word)
        {
            current = current->next(c);
            if( current == nullptr )
            {
                return 0;
            }
        }
        return current->countWord();
    }

    uint64_t prefix(const string& word)
    {
        NodeType* current = this->head;
        uint64_t length = 0;
        for( char c : word)
        {
            current = current->next(c);
            if( current == 0 )
            {
                break;
            }
            ++length;
        }
        return length ;
    }



private:
    NodeType* head;
};


int main2()
{
    ios_base::sync_with_stdio(false);

    Trie<NodeTypeCatalog<unsigned>::TrieNodeBasic> trie;

    const string  inputFileName = "trie.in";
    const string outputFileName = "trie.out";

    ifstream input(inputFileName , std::ifstream::in);
    ofstream output(outputFileName, std::ofstream::out);
    while( input.good() )
    {
        int _case = -1;
        string word;
        input >> _case >> word;

        if( _case == -1 )
        {
            break;
        }

        switch (_case)
        {
            case 0:
                trie.pushWord(word);
                break;
            case 1:
                trie.popWord(word);
                break;
            case 2:

                output << (int)trie.countWord(word) << '\n';
                break;
            case 3:
                output << trie.prefix(word) <<  '\n';
                break;
            default:
                output << "Invalid operation\n";
        }
    }


    return 0;
}