Search code examples
c++algorithmdata-structurestrie

Autocomplete using Trie


I'm attempting to make some sort of autocomplete feature in c++. First by using a Trie and once that works (and most importantly, I know HOW it all works) I'll try it using a Ternary tree. But as for now I get a segmentation fault when ever I add words starting with a different characte than those already in the Trie.

Eg. we add "abc", "abcd" and "abcde" this is no problem. Later when I want to add (while the "abc" etc are still in the Trie) "xfce", "xfced" a segmentation fault occurs.

I've been debugging this for some while now and can't seem to find the problem.

I think the problem resides somewhere in Trie.cpp so that's the file I'll provide here. However it might be in the main function aswell but I don't wanna get yelled at for posting to much code...

#include "Trie.h"
#include <iostream>

Trie::Trie()
{
    this->root = new Node(false);
}

Trie::~Trie()
{

}

Trie::Node::Node(bool isLeaf)
{
    this->isLeaf = isLeaf;
}

void Trie::insert(const std::string& word)
{
    Node* crawler = this->root;
    int index; 

    for(int i = 0; i < word.length(); ++i)
    {
        index = CHAR_TO_INDEX(word.at(i));

        if(!crawler->children[index])
        {
            crawler->children[index] = new Node(false); 
        }
        crawler = crawler->children[index];
    }
    crawler->isLeaf = true;
}

int Trie::contains(const std::string& word)
{
    int index;
    Node* crawler = this->root;

    for(int i = 0; i < word.length(); ++i)
    {
        index = CHAR_TO_INDEX(word.at(i));

        if(!crawler->children[index])
        {
            return -1; 
        }
        crawler = crawler->children[index];
    }

    return (crawler != NULL && crawler->isLeaf);
}

std::vector<std::string> Trie::possibleSuffixes(std::string& prefix)
{
    Node* crawler = this->root;
    int index;
    std::vector<std::string> result;

    for(int i = 0; i < prefix.length(); ++i)
    {
        index = CHAR_TO_INDEX(prefix.at(i));
        crawler = crawler->children[index];  
    }

    traverse(prefix, crawler, result);

    return result;
}

void Trie::traverse(std::string prefix, Node* node, std::vector<std::string>& v)
{
    if(node->isLeaf)
    {
        v.push_back(prefix); 
    }

    for(int i = 0; i < ALPHABET; ++i)
    {
        if(node->children[i])
        {
            traverse(prefix + (char)('a' + i), node->children[i], v);
        }
    }
}

Entire Trie class:

#ifndef TRIE_H
#define TRIE_H

#include <string>
#include <vector>

#define ARRAYSIZE(a) sizeof(a / sizeof(a[0]))
#define ALPHABET 26
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')

class Trie
{
    private:
        struct Node
        {
            Node(bool isLeaf);
            struct Node *children[ALPHABET];
            bool isLeaf;
        };

        Node *root;
        void traverse(std::string prefix, Node* node, std::vector<std::string>& v);

    public:
        Trie();
        ~Trie();
        int contains(const std::string& word);    //Checks the existance of a specific word in the trie
        void insert(const std::string& word);     //Inserts new word in the trie if not already there
        std::vector<std::string> possibleSuffixes(std::string& prefix);

};

Solution

  • Though you didn't mention about your Node class, I am assuming this -

    class Node {
    public:
        bool isLeaf;
    
        // must be >= 25 as you're inserting lowercase letters
        // assuming your CHAR_TO_INDEX(ch) returns 0 based index 
        // e.g. 'a' => 0, 'b' => 1 ... 'z' => 25
        Node* children[30];
    
        // default constructor should be like this
        Node(): isLeaf(false) {
              for(int i = 0; i < 26; i++) {
                  children[i] = NULL;
              }
        }
    
        ~Node() {
            for(int i = 0; i < 26; i++) {
                if(children[i]) {
                    delete children[i];
                    children[i] = NULL;
                }
            }
            delete this;
        }
    };
    

    Please compare your Node class/struct whether its something like this.