I think there's something wrong in my implement of trie. I use the word apple to test it. Although my test file dict.txt contains the word apple, it returns false. What's bug?
class Trie{
private:
class Node{
public:
Node* next[26];
bool isWord;
Node(){ isWord = false; }
};
Node* root;
public:
Trie() {
root = new Node();
}
void load(const string& line) {
Node* node = root;
for(int i = 0; i < line.size(); i++){
char x = line[i];
if(node->next[x-'a'] == nullptr)
node->next[x-'a'] = new Node();
node = node->next[x-'a'];
}
node->isWord = true;
}
bool contains(const string& word) {
Node* node = root;
for(int i = 0; i < word.size(); i++){
char x = word[i];
if(node->next[x-'a'] == nullptr)
return false;
else
node = node->next[x-'a'];
}
return node->isWord;
}
bool startWith(const string& prefix) {
Node* node = root;
for(int i = 0; i < prefix.size(); i++){
char x = prefix[i];
if(node->next[x-'a'] == nullptr)
return false;
else
node = node->next[x-'a'];
}
return true;
}
};
int main() {
Trie trie;
ifstream inFile;
string line;
while(getline(inFile, line)){
trie.load(line);
}
cout << trie.contains("apple") << endl;
cout << trie.startWith("cata") << endl;
return 0;
}
You forgot to initialize pointers Node* next[26] to nullptrs. And, because of that, words may be added incorrectly. Not sure though.
Related
#include<iostream>
using namespace std;
class trieNode{
public:
int data;
bool isTerminal;
trieNode ** children;
trieNode(int data){
this->data = data;
children = new trieNode*[26];
for(int i=0;i<26;i++){
children[i] = NULL;
}
isTerminal = false;
}
};
class Pair{
public:
bool exist;
trieNode* address;
Pair(){
exist = false;
address = NULL;
}
};
class Trie{
public:
trieNode *root;
Trie(){
root = new trieNode('\0');
}
// for programmer
private:
void insert(trieNode* root,string word){
//base case
if(word.size() == 0){
root->isTerminal = true;
return ;
}
// small calculation
int index = word[0] - 'a';
trieNode *child;
if(root->children[index] != NULL){
child = root->children[index];
}
else{
child = new trieNode(word[0]);
root->children[index] = child;
}
// recursion
insert(child,word.substr(1));
}
// for user
public:
void insertWord(string word){
insert(root,word);
}
// for programmer
private:
void deleteWord(trieNode* root, string word){
if(word.size() == 0){
root->isTerminal = false;
return;
}
int index = word[0] - 'a';
trieNode *child;
if(root->children[index] != NULL){
child = root->children[index];
}
else{
return;
}
deleteWord(child,word.substr(1));
if(child->isTerminal == false){
for(int i=0;i<26;i++){
if(child->children[i] != NULL)
return;
}
delete child;
root->children[index] = NULL;
}
}
// delete word
//for user
public:
void deleteWord(string word){
deleteWord(root,word);
}
// search a sting in trie
//function for programmer
// i used a pair class as return type brcause i want to return if word exists then return it's
address too
// i.e return a bool = true and adress where the word ends
private:
Pair find(trieNode *root, string word){
Pair p;
if(word.size() == 0){
Pair p;
p.address = root;
if(root->isTerminal == true)
p.exist = true;
else
p.exist = false;
return p;
}
trieNode *child;
int index = word[0]-'a';
if(root->children[index] == NULL){
Pair p;
p.address = root;
p.exist = false;
return p;
}
else{
child = root->children[index];
p = find(child, word.substr(1));
}
}
// search a string in the trie
// function for user
public:
Pair findstr(string word){
Pair p;
p = find(root,word);
return p;
}
};
int main(){
Trie t;
t.insertWord("sucess");
t.insertWord("s");
t.insertWord("a");
Pair p;
p = t.findstr("sucess");
cout<< p.address->data <<" "<< p.exist<<endl;
p = t.findstr("s");
cout<< p.address->data <<" "<< p.exist<<endl;
p = t.findstr("a");
cout<< p.address->data <<" "<< p.exist;
I am using pair class for implementing a function called findstr which finds a word in the trie and returns 2 things a bool and address of the last trieNode of the word, for that i used a pair class, in this code it should return address in hexadecimal and true for all three , but i an only see garbage values
}
One problem is here
else{
child = root->children[index];
p = find(child, word.substr(1));
}
that should be
else{
child = root->children[index];
p = find(child, word.substr(1));
return p;
}
The compiler should have given you a warning about a missing return statement. Did you ignore it?
There may be many other problems with the code. As already said the thing to do is use a debugger. Much faster way to fix your bugs than ask on SO.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define LOWERCASE_ALPHABET_SiZE 26
typedef int (*ptr) (char );
inline int charToIndex(char a) { return a - 'a'; };
class trienode
{
private:
vector< trienode* > child;
bool leaf;
public:
trienode(int );
~trienode();
void initialiseChild(int i);
trienode* getChild(int i);
void setLeaf() { leaf = true; };
bool isLeaf() { return leaf; };
};
trienode::trienode(int size)
{
for(int i = 0; i < size; i++)
{
child.push_back(NULL);
}
leaf = false;
}
trienode::~trienode()
{
for(int i = 0; i < child.size(); i++)
{
delete child.at(i);
child.at(i) = NULL;
}
}
void trienode::initialiseChild(int i)
{
child.at(i) = new trienode(child.size());
}
trienode* trienode::getChild(int i)
{
return child.at(i);
}
class trie
{
private:
trienode* root;
ptr toIndex;
public:
trie(int , ptr );
~trie();
void insert(const string& ref);
bool search(const string& ref);
};
trie::trie(int size, ptr toIndex) : toIndex(toIndex), root(new trienode(size)) { }
trie::~trie()
{
cout << "In destructor trie" << endl;
delete root;
root = NULL;
}
void trie::insert(const string& ref)
{
int size = ref.size();
trienode* root = root;
for(int i = 0; i < size; i++)
{
int index = toIndex(ref[i]);
if(root->getChild(index) == NULL) // crashing in getChild()
{
root->initialiseChild(index);
}
root = root->getChild(index);
}
root->setLeaf();
}
bool trie::search(const string& ref)
{
trienode* root = root;
int size = ref.size();
for(int i = 0; i < size && root != NULL; i++)
{
int index = toIndex(ref[i]);
if((root = root->getChild(index)) == NULL)
{
break;
}
}
return (root != NULL && root->isLeaf());
}
int main(int argc,char* argv[])
{
trie* altrie = new trie(LOWERCASE_ALPHABET_SiZE, charToIndex);
int n;
string temp;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> temp;
altrie->insert(temp);
}
int k;
for(int i = 0; i < k; i++)
{
cin >> temp;
if(altrie->search(temp))
{
cout << temp << " exists in the trie" << endl;
}
else
{
cout << temp << " doesn`t exist in the trie" << endl;
}
}
return 0;
}
I am creating Trie by supplying no of children it can have in each level and function pointer to convert the given character to index. After that I am Creating the root node of trie and when I`m inserting the first string it is getting Segmentation Fault in getChild Function
First things first explain me the reason behind the crash.
Explain me how I can improve the implementation of trie.
You are using the same name for member and local variables, like this:
trienode* root = root;
The compiler cannot tell the diffirence between the local root and trie::root so you are assigning it to itself.
i'm trying to sort a large amount of strings alphabetically and by length and it seems i'm only sorting around 1/7 of the amount needed. I am trying to sort around 100,000 words, when I sorted 70000 I ended up with 8000 words sorted and can't seem to find why it isn't working. Any help would be much appreciated
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
class Node
{
public:
char value; // the character value
bool end; // indicates whether this node completes a word
Node * children[93]; // represents the 93 ascii values for 33-126
Node(char newChar);
~Node();
};
class Trie
{
public:
Trie();
~Trie();
void addWord(string word);
Node * getRoot();
private:
Node * root;
};
Node::Node(char newChar)
{
value = newChar;
for (int i = 0; i < 93; ++i)
children[i] = NULL;
}
Node::~Node()
{
delete[] children;
}
Trie::Trie()
{
root = new Node(' ');
root->end = true;
}
Trie::~Trie()
{
delete root;
}
Node * Trie::getRoot()
{
return root;
}
void Trie::addWord(string word)
{
Node * currentNode = root;
for (int i = 0; i < word.size(); ++i)
{
char currentChar = word.at(i);
int index = currentChar - '!';
if (currentNode->children[index] != NULL)
{
currentNode = currentNode->children[index];
}
else
{
Node * newNode = new Node(currentChar);
currentNode->children[index] = newNode;
currentNode = newNode;
}
if (i == word.size() - 1)
{
currentNode->end = true;
}
}
}
void alphabetize(Node * node, vector<string> & sorting, string prefix = "") //why dont i have to declare this?
{
if (node->end)
{
sorting.push_back(prefix);
}
for (int i = 0; i < 93; ++i)
{
if (node->children[i] != NULL)
{
string currentString = prefix + node->children[i]->value; //store all characters
alphabetize(node->children[i], sorting, currentString);
}
else
{
}
}
}
int main()
{
Trie * t = new Trie();
string tempS;
int lengthCounter = 0;
ifstream fin;
fin.open("test.txt");
vector< vector<string> > sortLength;
vector <string> row(0, "");
vector<string> sorted;
while(fin >> tempS)
{
while(tempS.length() > lengthCounter)
{
sortLength.push_back(row);
lengthCounter++;
}
t->addWord(tempS);
}
alphabetize(t->getRoot(),sorted); //filled with sorted vector
for(int i = 0; i < sorted.size(); i++)
{
sortLength[sorted[i].length()-1].push_back(sorted[i]);
}
for(int k = 0; k < sortLength.size(); k++)
{
for(int l = 0; l < sortLength[k].size(); l++)
{
cout << sortLength[k][l] << "\n";
}
}
cout << sorted.size();
return 0;
}
This was a 2 part problem, implementing a Trie and a Hash->linked lists
the files contain words for a to z in column format... basically searching for words in the input file from an output file.
The trouble we are having is printing the hash value associated at each memory location in out table.
Words are sorted based on their ACII value sum.
abc and bcd will be placed into same bucket/or created hash value.
ignore the commented code as we have been using/saving most of everything we type and find in out textbook.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
const int N = 111;
//int HashNode *table[N];
//======================================//
// CLASS DEFINITIONS //
//======================================//
// Node class
class Node {
public:
Node(string lab) { mContent = lab[0]; mMarker = false; mLabel = lab; }
~Node() {}
string mLabel;
char mContent;
bool mMarker;
vector<Node*> mChildren;
Node *rightsibling;
Node *firstchild;
char content() { return mContent; }
void setContent(char c) { mContent = c; }
bool wordMarker() { return mMarker; }
void setWordMarker() { mMarker = true; }
vector<Node*> children() { return mChildren; }
Node* findChild(char c);
void appendChild(Node* child) { mChildren.push_back(child); }
};
// Trie class
class Trie {
private:
Node* root;
public:
Trie();
~Trie();
void insert(string s);
bool search(string s);
bool search2(string s);
};
// Hash class
class HashNode{
private:
int tableSize;
Node *parent; //pointer to parent node
char c; //next character of word being hashed
Node *child; //pointer to child node
HashNode *next; //pointer to next node in LL Hash
HashNode(Node *p,char c,Node *q);
public:
HashNode();
void HashInsert(Node *p, char c, Node *q);
int calc_hash(Node *p, char c);
void preorder( Node *p);
Node *findChild2(Node *parent, char c);
};
HashNode *table[N]; //global hashtable array
//======================================//
// METHOD DEFINITIONS //
//======================================//
// FindChild Method
Node* Node::findChild(char c)
{
for ( int i = 0; i < mChildren.size(); i++ )
{
Node* tmp = mChildren.at(i);
if ( tmp->content() == c )
{
return tmp;
}
}
return NULL;
}
// Trie Constructor
Trie::Trie()
{
root = new Node(" ");
}
// Trie Destructor
Trie::~Trie()
{
// Free memory
}
// Insert Method
void Trie::insert(string s)
{
Node* current = root;
if ( s.length() == 0 )
{
current->setWordMarker(); // an empty word
return;
}
for ( int i = 0; i < s.length(); i++ )
{
Node* child = current->findChild(s[i]);
if ( child != NULL )
{
current = child;
int j=0;
string s1, s2, s3;
Node *p, *q;
while((j < current->mLabel.length()) && (current->mLabel[j] == s[i])){j++;i++;}
if ((j<current->mLabel.length())) {
//split current
s1=current->mLabel.substr(0,j-1);
s2=current->mLabel.substr(j,current->mLabel.length()-1);
s3=s.substr(i,s.length()-1); //if i = s.length then ...s3 should be empty string
p=new Node(s3);
p->setWordMarker();
q=new Node(s2);
q->firstchild = current->firstchild;
current->mLabel = s1;
if(s3 < s2){
p->rightsibling=q;
q->rightsibling = NULL;
current->firstchild = p;
}
else {
q->rightsibling=p;
p->rightsibling = NULL;
current->firstchild = q;
}
}
}
else
{
Node* tmp = new Node(" ");
tmp->setContent(s[i]);
current->appendChild(tmp);
current = tmp;
}
if ( i == s.length() - 1 )
current->setWordMarker();
}
}
// Search Method1
bool Trie::search(string s)
{
Node* current = root;
while ( current != NULL )
{
for ( int i = 0; i < s.length(); i++ )
{
Node* tmp = current->findChild(s[i]);
if ( tmp == NULL )
return false;
current = tmp;
}
if ( current->wordMarker() )
return true;
else
return false;
}
return false;
}
// SEARCH METHOD 2
bool Trie::search2(string s)
{
Node* current = root;
while ( current != NULL )
{
for ( int i = 0; i < s.length(); i++ )
{
Node* tmp = current->findChild(s[i]);
if ( tmp == NULL )
return false;
current = tmp;
}
if ( current->wordMarker() )
return true;
else
return false;
}
return false;
}
// Hash Constructor
HashNode::HashNode(Node *p,char c,Node *q){
tableSize = N;
parent =p;
c = c;
child = q;
}
int HashNode::calc_hash(Node *p, char c){
int a = N/3;
int i = *((int*)(&p)); //int i = (int)p;
int j = (int)c;
int h = (a*i + j) % N;
return h;
}
void HashNode::HashInsert(Node *p, char c, Node *q){
int h = calc_hash(p,c);
HashNode *x = table[h];
HashNode *y = new HashNode(p,c,q);
if (x==NULL)
table[h]=y;
while (x->next != NULL)
x = x->next;
x->next = y;
//y->next = x;
//table[h] = y;
}
void HashNode::preorder( Node *p) {
if (p==NULL) return;
Node *q = p->firstchild;
while (q != NULL){
HashInsert(p,q->mContent, q);
preorder(q);
q = q->rightsibling;
}
}
Node *HashNode::findChild2(Node *parent, char c){
int h = calc_hash(parent, c);
HashNode *p = table[h];
while (p != NULL){
if (p->parent == parent && p->c == c){
return p->child;
}
p = p->next;
}
}
//======================================//
// MAIN //
//======================================//
int main()
{
Trie* trie = new Trie();
HashNode hashObj;
//HashEntryNode Hashtable[N];
ifstream infile;
infile.open("testdata.txt");
if (!infile)
cout<<"Input file cannot be openned!"<<endl;
cout<<"---------------------------------"<<endl;
cout<<"List of words inserted into Trie:"<<endl;
cout<<"---------------------------------"<<endl;
cout<<endl;
string wordLine;
while (!infile.eof()){
infile >> wordLine;
trie->insert(wordLine);
cout<<wordLine<<endl;
}
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<" End of List "<<endl;
cout<<"---------------------------------"<<endl<<endl;
ifstream searchFile;
searchFile.open("searchdata.txt");
if(!searchFile)
cout<<"Search file cannot be openned!"<<endl;
string searchLine;
while (!searchFile.eof()){
searchFile >> searchLine;
if ( trie->search(searchLine) )
cout << searchLine <<" => FOUND!" << endl;
else
cout << searchLine <<" => NOT FOUND." <<endl;
int h;
char p;
// h = hashObj.calc_hash(searchLine);
cout << "hash value is "<< h << endl;
//int index;
//index = hashObj.hashFunction(searchLine);
//cout << "Hash value = " << index <<endl<<endl;
//Hashtable[index] =
}
delete trie;
return 0;
}
I found a function which traverse all the trie and return a list contains all the words exist in my trie. My problem is I can't make this work for me, any help will appreciated.
class Node {
public:
Node();
Node* ch[26];
bool isEnd;
};
Node::Node() {
for(int i = 0; i < 26; i++)
ch[i] = NULL;
isEnd = 0;
}
class Trie {
public:
Node* root;
Trie() {root = new Node();}
void insert(string word, Node* ptr);
bool find(string word, Node* ptr);
list<string> findWords(Node* root);
};
void Trie::insert(string word, Node* ptr) {
for(unsigned int i = 0; i < word.size(); i++) {
if(ptr->ch[word[i]-'a'] == NULL)
ptr->ch[word[i]-'a'] = new Node();
ptr = ptr->ch[word[i]-'a'];
}
ptr->isEnd = 1;
}
list<string> Trie::findWords(Node* ptr) {
list<string> result;
if(ptr->isEnd)
result.push_back("");
for(int i = 0; i < 26; i++)
if(ptr->ch[i] != NULL) {
ptr = ptr->ch[i];
list<string> childResult = findWords(ptr);
char letter = (char) (97 + i);
for(string sufix : childResult)
result.push_back("" + letter + sufix);
}
copy(result.begin(),result.end(),ostream_iterator<string> (cout," "));
return result;
}
test main:
int main() {
Trie T;
string word;
for(int i = 0; i < 10; i++) {
cin >> word;
insert(word, root);
}
system("PAUSE");
return 0;
}