I'm using a trie implementation to store and search words in c++ programming language. In using the search() function, I am getting a segmentation fault when searching for a specific word. It seems that the error occurred in checking if the struct is null.
here is the error message:
Program received signal SIGSEGV, Segmentation fault.
0x000055555555b2ff in search (this=0x55555577ee70,
wordlist=0x55555577ef00, word="a1g6os") at test.cc:30
if (!pCrawl->children[index])
here is the source code:
#include <bits/stdc++.h>
using namespace std;
const int ALPHABET_SIZE = 26;
struct TrieNode {
struct TrieNode *children[ALPHABET_SIZE];
bool isEndOfWord;
};
struct TrieNode *getNode(void) {
struct TrieNode *pNode = new TrieNode;
pNode->isEndOfWord = false;
for (int i = 0; i < ALPHABET_SIZE; i++)
pNode->children[i] = NULL;
return pNode;
}
void insert(struct TrieNode *root, string key) {
struct TrieNode *pCrawl = root;
for (int i = 0; i < key.length(); i++) {
int index = key[i] - 'a';
if (!pCrawl->children[index])
pCrawl->children[index] = getNode();
pCrawl = pCrawl->children[index];
}
// mark last node as leaf
pCrawl->isEndOfWord = true;
}
// Returns true if key presents in trie, else
// false
bool search(struct TrieNode *root, string key) {
struct TrieNode *pCrawl = root;
for (int i = 0; i < key.length(); i++) {
int index = key[i] - 'a';
if (!pCrawl->children[index])
return false;
pCrawl = pCrawl->children[index];
}
return (pCrawl != NULL && pCrawl->isEndOfWord);
}
int main() {
string keys[] = {"the", "a", "there",
"answer", "any", "by",
"bye", "their" };
int n = sizeof(keys)/sizeof(keys[0]);
struct TrieNode *root = getNode();
for (int i = 0; i < n; i++)
insert(root, keys[i]);
// Search for different keys
search(root, "a1g6os")? cout << "Yes\n" :
cout << "No\n";
return 0;
}
Both #Some programmer dude and #JohnnyJohansson have pointed out the root cause. The live test showed where the code read the array out-of-bounds. Actually the fix is easy once you understand what happens. The following is the fixed code if you cannot figure it out by yourself. A live test of it is here cee.studio
#include<iostream>
using namespace std;
const int ALPHABET_SIZE = 75; // increase the range
struct TrieNode {
struct TrieNode *children[ALPHABET_SIZE];
bool isEndOfWord;
};
struct TrieNode *getNode(void) {
struct TrieNode *pNode = new TrieNode;
pNode->isEndOfWord = false;
for (int i = 0; i < ALPHABET_SIZE; i++)
pNode->children[i] = NULL;
return pNode;
}
void insert(struct TrieNode *root, string key) {
struct TrieNode *pCrawl = root;
for (int i = 0; i < key.length(); i++) {
int index = key[i] - '0'; // lower the low bound
if (!pCrawl->children[index])
pCrawl->children[index] = getNode();
pCrawl = pCrawl->children[index];
}
// mark last node as leaf
pCrawl->isEndOfWord = true;
}
// Returns true if key presents in trie, else
// false
bool search(struct TrieNode *root, string key) {
struct TrieNode *pCrawl = root;
for (int i = 0; i < key.length(); i++) {
int index = key[i] - '0'; // lower the low bound
if (!pCrawl->children[index])
return false;
pCrawl = pCrawl->children[index];
}
return (pCrawl != NULL && pCrawl->isEndOfWord);
}
int main() {
string keys[] = {"the", "a", "there",
"answer", "any", "by",
"bye", "their" };
int n = sizeof(keys)/sizeof(keys[0]);
struct TrieNode *root = getNode();
for (int i = 0; i < n; i++)
insert(root, keys[i]);
// Search for different keys
search(root, "a1g6os")? cout << "Yes\n" :
cout << "No\n";
return 0;
}
Related
Hi so i've been trying to implement Auto-complete/suggestion using trie tree
but the suggestion part only suggests 1 or 2 first similar words to it and i can't find out what causing this.
This is my Trie structre
struct TrieNode {
struct TrieNode* children[ALPHABET_SIZE];
bool isEndOfWord;
};
struct TrieNode* getNode(void) {
struct TrieNode* pNode = new TrieNode;
pNode->isEndOfWord = false;
for (int i = 0; i < ALPHABET_SIZE; i++)
pNode->children[i] = NULL;
return pNode;
}
bool isLeafNode(struct TrieNode* root) { return root->isEndOfWord != false; }
and this is the suggestion/Auto-complete part
void suggestionsRec(struct TrieNode* root, string currPrefix) {
if (root->isEndOfWord) {
cout << currPrefix;
cout << endl;
}
if (isLeafNode(root))
return;
for (int i = 0; i < ALPHABET_SIZE; i++)
{
if (root->children[i])
{
currPrefix.push_back(97 + i);
suggestionsRec(root->children[i], currPrefix);
currPrefix.pop_back();
}
}
}
int spellchecker(TrieNode* root, const string query) {
struct TrieNode* pCrawl = root;
int level;
int n = query.length();
for (level = 0; level < n; level++) {
int index = CHAR_TO_INDEX(query[level]);
if (!pCrawl->children[index])
return 0;
pCrawl = pCrawl->children[index];
}
bool isWord = (pCrawl->isEndOfWord == true);
bool isLast = isLeafNode(pCrawl);
if (isWord && isLast) {
cout << query << endl;
return -1;
}
if (!isLast) {
string prefix = query;
suggestionsRec(pCrawl, prefix);
return 1;
}
}
for example when i try words like : [ the , there , these ] and input is "t" all it suggests is "the" .
this is the whole code https://pastebin.com/VPd94rny
also any suggestion to improve my code is much appreciated
I have written a simple code to implement a trie data structure in c++. But when I run this program, it gives segmentation error as an output.
Kindly please correct me, where i have been wrong.
#include <bits/stdc++.h>
using namespace std;
struct trienode {
struct trienode * child[26];
bool isEnd;
trienode()
{
isEnd = false;
for(int i = 0; i < 26; i++)
{
child[i] = NULL;
}
}
};
struct trienode * root;
void insert_str(string &s, int n)
{
trienode * curr = root;
int i;
for(i = 0; i < n; i++)
{
int index = s[i] - 'a';
if(curr -> child[index] == NULL)
{
curr -> child[index] = new trienode();
}
else
{
curr = curr -> child[index];
}
}
curr -> isEnd = true;
}
int main()
{
string s1 = "yash";
insert_str(s1, 4);
}
You haven't allocated any memory for your root node.
Normally you would have a separate class to handle the trie as a whole. It can then allocate the root node.
class trie
{
public:
trie()
{
root = new trienode();
}
void insert_str(string &s, int n)
{
...
}
private:
trienode* root;
};
int main()
{
trie t;
string s1 = "yash";
t.insert_str(s1, 4);
}
I have below code and i need help to do node count to below codes! Anyone can help me to write that function?
I have already words count, but need s help in the Node count!
// C++ implementation to count words in a trie
#include <bits/stdc++.h>
using namespace std;
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
// Alphabet size (# of symbols)
#define ALPHABET_SIZE (26)
// Converts key current character into index
// use only 'a' through 'z' and lower case
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
// Trie node
struct TrieNode
{
struct TrieNode *children[ALPHABET_SIZE];
// isLeaf is true if the node represents
// end of a word
bool isLeaf;
};
// Returns new trie node (initialized to NULLs)
struct TrieNode *getNode(void)
{
struct TrieNode *pNode = new TrieNode;
pNode->isLeaf = false;
for (int i = 0; i < ALPHABET_SIZE; i++)
pNode->children[i] = NULL;
return pNode;
}
// If not present, inserts key into trie
// If the key is prefix of trie node, just
// marks leaf node
void insert(struct TrieNode *root, const char *key)
{
int length = strlen(key);
struct TrieNode *pCrawl = root;
for (int level = 0; level < length; level++)
{
int index = CHAR_TO_INDEX(key[level]);
if (!pCrawl->children[index])
pCrawl->children[index] = getNode();
pCrawl = pCrawl->children[index];
}
// mark last node as leaf
pCrawl->isLeaf = true;
}
// Function to count number of words
int wordCount(struct TrieNode *root)
{
int result = 0;
// Leaf denotes end of a word
if (root -> isLeaf)
result++;
for (int i = 0; i < ALPHABET_SIZE; i++)
if (root -> children[i])
result += wordCount(root -> children[i]);
return result;
}
// Driver
int main()
{
// Input keys (use only 'a' through 'z'
// and lower case)
char keys[][8] = {"the", "a", "there", "answer",
"any", "by", "bye", "their"};
struct TrieNode *root = getNode();
// Construct Trie
for (int i = 0; i < ARRAY_SIZE(keys); i++)
insert(root, keys[i]);
cout << wordCount(root);
return 0;
}
You can do a simple inorder traversal of the tree.
int inorderTraversal(TrieNode* pNode)
{
if (!pNode)
return 0;
int count = 0;
for (int i = 0; i < ALPHABET_SIZE; ++i)
count += inorderTraversal(pNode->children[i]);
return count + 1;
}
I'm creating a word suggestion auto-complete interface. I'm using a trie in c++ to do this. I'd like to enter part of a word into my code and have the trie suggest possible words to complete the end of my word.
#include<bits/stdc++.h>
using namespace std;
#define alphabet (26)
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
struct TrieNode
{
struct TrieNode *children[alphabet];
// isWordEnd is true if the node represents
// end of a word
bool isWordEnd;
};
struct TrieNode *getNode(void)
{
struct TrieNode *Node = new TrieNode;
Node->isWordEnd = false;
for (int i = 0; i < alphabet; i++)
Node->children[i] = NULL;
return Node;
}
void insert(struct TrieNode *root, const string key)
{
struct TrieNode *Crawl = root;
for (int level = 0; level < key.length(); level++)
{
int index = CHAR_TO_INDEX(key[level]);
if (!Crawl->children[index])
{
Crawl->children[index] = getNode();
//Crawl = Crawl->children[index];
}
Crawl = Crawl->children[index];
}
// mark last node as leaf
Crawl->isWordEnd = true;
}
//returns 0 if current node has a child
// If all children are NULL, return 1.
bool isLastNode(struct TrieNode* root)
{
for (int i = 0; i < alphabet; i++)
if (root->children[i])
return 0;
return 1;
}
void suggestionsRec(struct TrieNode* root, string currPrefix)
{
// found a string in Trie with the given prefix
if (root->isWordEnd)
{
cout << currPrefix;
cout << endl;
}
// All children struct node pointers are NULL
if (isLastNode(root))
{
//currPrefix = "help";
//deleteNode(root);
//delete root;
//root = NULL;
//currPrefix.pop_back();
return;
}
for (int i = 0; i < alphabet; i++)
{
if (root->children[i])
{
currPrefix.push_back(97 + i);
//currPrefix.push_back(i);
//currPrefix.pop_back(97 + i);
/*if (isLastNode(root))
{
currPrefix.erase(3);
}*/
// recur over the rest
suggestionsRec(root->children[i], currPrefix);
//printAutoSuggestions(root->children[i], currPrefix);
}
}
}
// print suggestions for given query prefix.
int printAutoSuggestions(TrieNode* root, const string query)
{
struct TrieNode* Crawl = root;
// Check if prefix is present and find the
// the node (of last level) with last character
// of given string.
int level;
int n = query.length();
for (level = 0; level < n; level++)
{
int index = CHAR_TO_INDEX(query[level]);
// no string in the Trie has this prefix
if (!Crawl->children[index])
return 0;
Crawl = Crawl->children[index];
}
// If prefix is present as a word.
bool isWord = (Crawl->isWordEnd == true);
// If prefix is last node of tree (has no
// children)
bool isLast = isLastNode(Crawl);
// If prefix is present as a word, but
// there is no subtree below the last
// matching node.
if (isWord && isLast)
{
cout << query << endl;
return -1;
}
// If there are are nodes below last
// matching character.
if (!isLast)
{
string prefix = query;
suggestionsRec(Crawl, prefix);
return 1;
}
}
// Driver Code
int main()
{
struct TrieNode* root = getNode();
insert(root, "hello");
insert(root, "dog");
insert(root, "hell");
insert(root, "cat");
insert(root, "a");
insert(root, "hel");
insert(root, "help");
insert(root, "helps");
insert(root, "helping");
int comp = printAutoSuggestions(root, "hel");
if (comp == -1)
cout << "No other strings found with this prefix\n";
else if (comp == 0)
cout << "No string found with this prefix\n";
return 0;
}
When I enter the prefix "hel" I'd like to see
hel
hell
hello
help
helping
helps
But instead, I just see
hel
hell
hello
hellp
hellping
hellpis
In suggestionsRec(...) you have:
for (int i = 0; i < alphabet; i++)
{
currPrefix.push_back(97 + i);
...
suggestionsRec(root->children[i], currPrefix);
}
}
You are adding characters to currPrefix and keeping them. So you call suggestionsRec on later children, with characters in currPrefix that don't belong there.
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;
}