Getting a segmentation fault while implementing Trie in c++ - c++

Another day another seg fault I don't understand, I'm trying to implement tries for the first time and it is proving to be quite some challenge, I think it would be very helpful if someone could tell me what I'm doing wrong, would probably help me understand OOP better too I suppose, because I think the error is related to that.
The fault happens while searching and I wasn't able to understand it using the debugger myself.
Here is the code:
#include <vector>
#include <iostream>
using std::string, std::cout, std::vector;
class TrieNode {
private:
bool isLeaf;
vector<TrieNode*> ar = vector<TrieNode*>(26);
public:
TrieNode() {
isLeaf = false;
for(int i = 0; i < 26; i++) ar[i] = nullptr;
}
void insert(TrieNode *root, string key) {
TrieNode *crawl = root;
for(int i = 0; i < key.size(); i++) {
if(!crawl->ar[key[i]]) {
crawl->ar[key[i]] = new TrieNode();
}
crawl = crawl->ar[key[i]];
}
crawl->isLeaf = true;
}
bool search(TrieNode *root, string key) {
TrieNode *crawl = root;
for(int i = 0; i < key.size(); i++) {
if(!crawl->ar[key[i]]) {
return false;
}
crawl = crawl->ar[key[i]];
}
return crawl->isLeaf;
}
};
int main() {
TrieNode* head = new TrieNode();
head->insert(head, "hello");
cout << head->search(head, "hello");
}

Make your ar[key[i]] to something like ar[key[i]-'a'] if your string is say always lower-case.
Basically, key[i] is a char in the range of ['a'-'z']. When it's implicitly converted to an int, it's not in the range of [0,25], but rather equal to their ascii values.

Related

How to insert elements from a structure into a min heap priority queue

I am making a file compressor using Huffman Algorithm in C++. I have calculated the character frequency, but now I am having difficulty in pushing it into a min heap priority queue. I want to sort the inserted elements by frequency. Every time I execute the code, it gives the error:
Error C2676 binary '>': 'const _Ty' does not define this operator or a conversion to a type acceptable to the predefined operator
I have tried almost every way mentioned on this website, yet I still cannot get rid of this error.
Here is my code:
#include<iostream>
#include<string>
#include<queue>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
struct node
{
char c; //character in the string
int f; //Frequency of character in the string
node* next;
node* left, * right; //left and right child of binary tree respectively
node()
{
f = 0;
left = NULL;
right = NULL;
c = NULL;
next = NULL;
}
bool operator>(const node& a)
{
return a.f > f;
}
};
class Huffman
{
string text; //The text that will be encoded
priority_queue <node> pq;
public:
Huffman()
{
}
void StringInput()
{
cout << "Enter the string you want to encode:";
getline(cin, text);
}
//Function which will calculate the frequency of characters in the string entered by the user
void CharacterFrequency()
{
for (int i = 0; i < text.length(); i++)
{
int sum = 0;
for (int j = 0; j < text.length(); j++)
{
if (j < i and text[i] == text[j])
{
break;
}
if (text[i] == text[j])
{
sum++;
}
}
if (sum != 0)
{
PriorityQueue(text[i], sum);
}
}
}
void PriorityQueue(char ch, int freq)
{
node n;
n.c = ch;
n.f = freq;
pq.push(n);
}
};
int main()
{
Huffman obj;
obj.StringInput();
obj.CharacterFrequency();
return 0;
}
I will be grateful for any help in this regard.
There are two issues:
Issue 1: You are not declaring the priority queue correctly.
If you want to add a custom comparison, you need to specify that in the template:
std::priority_queue <node, std::vector<node>, std::greater<node>> pq;
Now the node::operator > will be used.
Issue 2: The operator > should be a const function:
bool operator>(const node& a) const
{
return a.f > f;
}

Constructor doesn't update class member variables

So I am trying to implement a hash table and I am having trouble seeing what is wrong in my class or constructor. In summary when I try to reach an element of hash table array, I can in constructor, but I cannot in the member function (I get seg fault), which leads me to believe there is something wrong with my class/ constructor doesn't work.
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE];
for (int i = 0; i<SIZE; i++)
{
hashtable[i] = NULL;
if(!hashtable[i])
{
cout<<"It works at "<<i<<"th"<<endl;//This is to check
}
}
}
int website::hashfunction(const char array []) //Hash function
{
int inputsize = strlen(array);
int value = 0;
for (int i=0; i< inputsize; i++)
{
value = value + int(array[i]);
}
value = value % SIZE;
return value;
}
These functions do what they are supposed to do
but when I run this function. I get seg fault at hashtable[place]==NULL level.
int website::insert(const mainentry& input)
{
int place = 0;
node*temp = new node;
/* Ignore this part
temp->data.topic = new char[strlen(input.topic)+1];
strcpy(temp->data.topic, input.topic);
temp->data.url = new char[strlen(input.url)+1];
strcpy(temp->data.url, input.url);
temp->data.summary = new char[strlen(input.summary)+1];
strcpy(temp->data.summary, input.summary);
temp->data.review = new char[strlen(input.review)+1];
strcpy(temp->data.review, input.review);
temp->data.rating = input.rating;
*/
place = hashfunction(temp->data.topic);
cout<<"Place is: "<<place<<endl; //Hash function works correctly
if (hashtable[place]== NULL) // THIS IS THE PART I GET SEG FAULT
{
hashtable[place] = temp;
temp->next = NULL;
return 1;
}
else
{
temp->next = hashtable[place];
hashtable[place] = temp;
return 1;
}
return 0;
}
Here is my class:
class website
{
public:
website(int input);
// ~website();
int insert(const mainentry & input);
int retrieve( char [], mainentry output [] );
int edit (mainentry & input);
int remove();
int display(char []);
int display_all();
int hashfunction(const char []);
private:
int SIZE;
node ** hashtable;
};
I am assuming I am making a beginner's mistake but I can't see what is going on, if anyone can direct me, I'd appreciate it.
You are shadowing the class's hashtable variable in the constructor by writing:
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE]; //<<-- Shadowing. you are declaring a local scope veriable called hastable, and not using the class's instance.
}
node** hashtable = new node * [SIZE];
should be
hashtable = new node * [SIZE];

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);
};
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.

Validation of BST using Morris

This is my first post on Stackoverflow. Please forgive me if my post format is not correct. I will try to learn as quick as possible. :)
So recently I am learning about BST. And I am practicing my skills on validating if a given Binary Tree is really a BST(duplicates are allowed as right child.) I tried recursion method and it works but the performance is not as good as I expected for a large given tree. So I tried to use Morris Algorithm to do the work. First I do an in-order traverse to see if the given tree is a BST. Then, I need to validate if all the duplicates are actually the right children of their parents. However, I am stuck on how to make that happen. So I am wondering if someone can give me some hints on that please? Or there's other ways to do that? Thank you very much.
The following are my currently code.
#include <algorithm>
#include <iostream>
#include <vector>
#include <limits.h>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
struct Node {
int key;
int left;
int right;
Node() : key(0), left(-1), right(-1) {}
Node(int key_, int left_, int right_) : key(key_), left(left_), right(right_) {}
};
bool IsBST(vector<Node> S) {
vector<size_t> result;
vector<size_t> check;
size_t cur_pos = 0;
size_t pre_pos = 0;
if (!S.size()) {
return true;
}
while (cur_pos != -1) {
size_t nxt_left_child = S[cur_pos].left;
if (nxt_left_child == -1) {
result.push_back(S[cur_pos].key);
check.push_back(cur_pos);
cur_pos = S[cur_pos].right;
}
else {
pre_pos = S[cur_pos].left;
while (S[pre_pos].right != -1 && S[pre_pos].right != cur_pos) {
pre_pos = S[pre_pos].right;
}
if (S[pre_pos].right == -1) {
S[pre_pos].right = cur_pos;
cur_pos = S[cur_pos].left;
}
else {
S[pre_pos].right = -1;
result.push_back(S[cur_pos].key);
check.push_back(cur_pos);
cur_pos = S[cur_pos].right;
}
}
}
if (std::is_sorted(result.begin(), result.end())) {
for (int i = 0; i < result.size() - 1; i++) {
if (result[i] == result[i + 1]) {
int temp = S[check[i]].right;
if (S[temp].key != S[check[i+1]].key) {
return false;
}
}
}
return true;
}
return false;
}

Stack overflow exception for large data sets

I tried solving this problem: http://projecteuler.net/problem=201 But the program below breaks for larger SET size(>20) throwing a stack overflow exception. Is there a memory leak happening? Could you please point out where? Also if the following implementation involves bad coding practice, please let me know. I'm trying to improve my amateur programming skills. Thanks in advance.
EDIT: I edited the code below. I don't get any stack overflow exceptions now. But could anyone suggest me a better algorithm? Thanks!
#include "stdafx.h"
#include <iostream>
#include <cmath>
#include <winsock2.h>
#define SET 100
#define SUBSET 50
class node
{
public:
int data;
node* next;
};
using namespace std;
int sum(int A[SUBSET]);
void combCalc(int S[SET]);
bool search(node* head, int sum);
void appendIfUnique(int total, bool nullHeader);
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Hello World" << endl;
int S [SET];
for(int i=1; i<=SET; i++)
{
S[i-1]= (int)pow((float)i,2);
}
combCalc(S);
cin.get();
return 0;
}
static node *head;
static node *current = head;
void combCalc(int S[])
{
int row=0, col=0;
int elePos[SUBSET], B[SUBSET];
bool nullHeader = true;
for(int z=0; z<SUBSET; z++) // initializing elePos
{
elePos[z]=z;
}
bool notDone = true;
while (notDone || col <(SUBSET-1))
{B[col] = S[elePos[col]];
if(col==(SUBSET-1)) //finished forming a subset
{
notDone = false;
for(int q=(SUBSET-1); q>=0; q--) //incrementing from the last element
{
if(elePos[q]<(SET-SUBSET+q)) //checking if the element has reached its maximum
{
notDone = true;
elePos[q]++;
for(int w=q+1; w<SUBSET; w++) //setting the trailing elements to its minimum
{
elePos[w]=elePos[q]+w-q;
}
break;
}
}
if(notDone){col=0;row++;}
int total = sum(B);
appendIfUnique(total,nullHeader);
nullHeader = false;
}
else
{
col++;
}
}
int result = 0;
for(node *pnode = head; pnode != current->next; pnode=pnode->next)
result = result + pnode->data;
cout << result << endl;
}
int sum(int A[])
{
int total = 0;
for(int i=0; i<SUBSET; i++)
{
total = total + A[i];
}
return total;
}
bool search(node* head, int sum)
{
bool exists = false;
node* pNode = head;
while(pNode != NULL)
{
if(pNode->data == sum)
{
exists = true;
break;
}
pNode = pNode->next;
}
return exists;
}
void appendIfUnique(int total, bool nullHeader)
{
if(nullHeader){head = NULL;}
if(!search(head,total))
{
node *temp;
/*temp=(node *) malloc(sizeof(node));*/
temp = new node();
temp->data = total;
temp->next = NULL;
if(head == NULL)
{
head = current = temp;
}
else
{
current->next = temp;
current = temp;
}
}
}
Some notes:
Break point (in my system: cygwin g++) is SET=18 (17 works)
Problem is due to too much recursion [run it within a debugger] You have too many calls to combCalc(S) (in my case, it dies after 32K calls).
As it has been indicated in the comments, you should probably reconsider your algorithm. In the meantime, a simple modification is to remove the recursion (since it is not even a proper recursion):
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Hello World" << endl;
int S [SET];
for(int i=1; i<=SET; i++)
{
S[i-1]= (int)pow((float)i,2);
}
while(combCalc(S)) { } // <--- keep calling while combCalc is true
cin.get();
return 0;
}
by making combCal() return a bool:
bool combCalc(int S[]) // <--- MODIFY (check also the forward declaration)
{
...
if(notDone || col <(SUBSET-1))
{
...
return true; // <--- MODIFY return true... I need to keep calculating.
}
else
{
int result = 0;
for(node *pnode = head; pnode != current->next; pnode=pnode->next)
result = result + pnode->data;
cout << result << endl;
return false; // <--- MODIFY return false.... we're done
}
}
The above is just a minimum modification. I'm not even sure it solves the problem correctly since I haven't really looked at the algorithm.
You should consider:
Use a less brute force algorithm
Move the while loop within the combCalc()... so you will be having a single call... and in this case you probably can remove the static variables and make them simple local variables.
Consider not using #define for constants.
Consider using STL structures... instead of your own home grown ones. This will remove some of the concerns below.
Consider not using malloc but using new (more C++)
You're not using free this means that the memory you allocated will not be released. (use delete if you're using new or delete [] if you did new [])