I'm trying to implement a trie that can print out the frequency of words with a given prefix.
Edit: Thanks to #kaidul-islam finding my error with the following error:
new_word->child[letter]->prefixes_++;
Below is the fixed code:
Trie Class:
class Trie
{
public:
Trie(): prefixes_(0), is_leaf_(false), frequency_(0)
{
for (int i=0; i<26; i++)
{
child[i] = nullptr;
}
}
virtual ~Trie();
//Child nodes of characters from a-z
Trie *child[26];
//vector<Trie> child;
int prefixes_;
//accessor & mutator functions
bool GetIsLeaf() { return is_leaf_; }
void SetIsLeaf(bool val) { is_leaf_ = val; }
int GetFrequency() { return frequency_; }
void SetFrequency(int val) { frequency_ = val; }
int GetPrefixes() { return prefixes_; }
void SetPrefixes(int val) { prefixes_ = val; }
bool is_leaf_;
private:
//bool is_leaf_;
int frequency_;
};
Function in Question:
void AddWord(string &word, Trie *root)
{
Trie *new_word = root;
new_word->prefixes_++;
for(unsigned int i = 0 ; i < word.length(); i++)
{
int letter = (int)word[i] - (int)'a'; //extract character of word
if(new_word->child[letter] == nullptr)
{
new_word->child[letter] = new Trie;
}
/*cout << "not value of x: " << new_word->child[letter]->GetPrefixes() << endl;
int x = (new_word->child[letter]->GetPrefixes())+1;
cout << "value of x: " << x << endl;
new_word->child[letter]->SetPrefixes(x);*/
new_word->child[letter]->prefixes_++;
new_word = new_word->child[letter];
}
new_word->SetFrequency(new_word->GetFrequency()+1);
/*
cout << "Word: " << word << endl;
cout << "frequency: " << new_word->GetFrequency() << endl;
cout << "prefixes: " << new_word->GetPrefixes() << endl;
cout << "is leaf: " << new_word->GetIsLeaf() << endl << endl;
*/
}
After a quick inspection, I found you didn't initialize member variables in your constructor.
Trie(): prefixes_(0),
is_leaf_(false),
frequency_(0) {
for(int i = 0; i < 26; i++) {
child[i] = nullptr;
}
}
Unlike global variable, there is no guarantee that prefixes_ will be 0 by default on declaration. And child[i] is not guaranteed to be nullptr too. You need to initialize everything.
Related
// in this code I first created nodes stored them in a que and keep on removing them as I entered their left and right children. To make a node have no further children I entered -1 while entering data. Here I am not able to understand what is wrong with my code , I am getting wrong output for preorder and postorder traversals. It would be really great if you guys could help me out.
I made a class que for queue ds and inherited it in tree class in protected mode.
#include <iostream>
#include <math.h>
using namespace std;
struct node
{
int data;
struct node *left;
struct node *right;
};
class que
{
protected:
int start;
int end;
struct node **arr;
int n;
public:
que(int x)
{
n = x;
arr = new struct node *[n];
start = -1;
end = -1;
}
void isfull()
{
if (end == n)
cout << "Queue is full !!!" << endl;
return;
}
int isempty()
{
if (start == end)
{
start = -1;
end = -1;
cout << "Queue is empty !!!" << endl;
return 1;
}
return 0;
}
void enqu(struct node *x)
{
if (end == n)
{
cout << "called" << endl;
isfull();
return;
}
end++;
arr[end] = x;
}
struct node *dequ(void)
{
struct node *q = 0;
if (start == end)
{
isempty();
return q;
}
start++;
cout << "Element removed is ->" << arr[start] << endl;
return arr[start];
}
};
class tree : protected que
{
public:
struct node *head;
struct node *ptr;
tree(int n) : que(n)
{
head = 0;
ptr = 0;
enter();
}
void create(void)
{
ptr = new struct node;
ptr->left = 0;
ptr->right = 0;
}
void enter(void)
{
struct node *p;
if (head == 0)
{
create();
cout << "Enter root element of tree -> ";
cin >> ptr->data;
head = ptr;
cout << "Enquing ptr - " << ptr << endl;
enqu(ptr);
}
while (!isempty())
{
p = dequ();
cout << "Enter left child ->";
int x;
cin >> x;
if (x != -1)
{
create();
p->left = ptr;
ptr->data = x;
cout << "Enquing ptr - " << ptr << endl;
enqu(ptr);
}
cout << "Enter right child ->";
cin >> x;
if (x != -1)
{
create();
p->right = ptr;
ptr->data = x;
cout << "Enquing ptr - " << ptr << endl;
enqu(ptr);
}
}
}
void inorder(struct node *yes)
{
if (yes != 0)
{
inorder(yes->left);
cout << "--> " << yes->data << endl;
inorder(yes->right);
}
}
void preorder(struct node *yes)
{
if (yes != 0)
{
cout << "--> " << yes->data << endl;
inorder(yes->left);
inorder(yes->right);
}
}
void postorder(struct node *yes)
{
if (yes != 0)
{
inorder(yes->left);
inorder(yes->right);
cout << "--> " << yes->data << endl;
}
}
int count(struct node *yes)
{
static int x = 0, y = 0;
if (yes == 0)
return 0;
x = count(yes->left);
y = count(yes->right);
return x + y + 1;
}
int height(struct node *yes)
{
static int a = 0, b = 0;
if (yes == 0)
return 0;
a = count(yes->left);
b = count(yes->right);
if (a > b)
return a + 1;
else
return b + 1;
}
};
int main()
{
int x;
cout << "Enter height of tree - ";
cin >> x;
int max = 0;
max = pow(2, x + 1) - 1;
tree tr(max);
cout << "Preorder traversal -- " << endl;
tr.preorder(tr.head);
cout << "Inorder traversal -- " << endl;
tr.inorder(tr.head);
cout << "Postorder traversal -- " << endl;
tr.postorder(tr.head);
cout << "\n No. of elements -- " << tr.count(tr.head);
cout << "\n Height of tree --" << tr.height(tr.head);
}
The preorder and postorder functions doesn't call themselves recursively. Instead they call the inorder function, which will lead to all but the root will be printed using inorder.
Trie()
{
nxt.assign(26, NULL);
cout << nxt.size() << endl;
Trie* root = this;
isWord = false;
}
/** Inserts a word into the trie. */
void insert(string word)
{
auto node = root;
for (int i = 0; i < word.size(); i++)
{
cout << "node: " << node<< ":" << "word[i] -'a': " << word[i] - 'a' << endl;
if (node->nxt[word[i] - 'a'] == NULL ) // misaligned memory access here
node->nxt[word[i]-'a'] = new Trie();
node = node->nxt[word[i]-'a'];
}
node->isWord = true;
}
I am getting the following error although the vector seems to have correct length: Member access within misaligned address 0xbebebebebebebe for type 'Trie' which requires 8 byte alignment. Why is the nxt vector elements not accessible?
Update:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Trie {
public:
Trie() {
nxt.assign(26, NULL);
isWord = false;
}
void insert(string word) {
auto node = this;
for(int i = 0; i < word.size(); i++) {
if (!node->nxt[word[i]-'a']) {
cout << " nxt entry not found... :" << word[i] << endl;
node->nxt[word[i]-'a'] = new Trie();
}
else {
cout << "nxt entry found! :" << word[i] << endl;
node = node->nxt[word[i]-'a'];
}
node->isWord = true;
}
}
bool search(string word) {
auto node = this;
for(int i = 0; i < word.size(); i++) {
if (!node->nxt[word[i]-'a']) return false;
node = node->nxt[word[i]-'a'];
}
return node->isWord ? true: false;
}
private:
vector<Trie*> nxt;
bool isWord;
};
int main() {
Trie* trie = new Trie();
trie->insert("test");
cout << "found test: " << trie->search("test") << endl;
cout << "success!" << endl;
return 0;
}
This runs! Bailey's comment helped me realize my mistake. I had declared a local root in ctor. The intent was to only initialize the class member, root! Thank you!
main():
char inp[] = "(A+B)/(C*D))";
Infix i;
cout << "In main: " << inp /* + ')' */ << endl << endl;
Here is Infix constructor:
Infix() {
push('(');
cout << "Element In Stack: " << *returnElement(returnTop()) << endl;
outputString = "";
strcpy(operatorArray, "/*-+%");
cout << "Operator Array: " << operatorArray << endl;
}
Infix is inheriting from a class 'Stack':
class Stack{
int top = -1;
char arr[100];
public:
bool push(char);
char pop();
char peek();
bool isEmpty();
void displayAll();
char returnTop() { return top;}
char* returnElement(int i) {
if(i > 98){
cout << "StackOutOfIndex";
return nullptr;
}
return &arr[i];
}
};
When I run the code in main, it displays unusual output:
Element In Stack: (
Operator Array: /*-+%
In main: +%
Stack Object Destroyed!
But, when in main, if the comment the line declaring 'Infix' object declaration, the code runs fine:
In main: (A+B)/(C*D))
EDITS:
Stack Class
#include<iostream>
using namespace std;
class Stack{
int top = -1;
char arr[100];
public:
bool push(char);
char pop();
char peek();
bool isEmpty();
void displayAll();
char returnTop() { return top;}
char* returnElement(int i) {
if(i > 98){
cout << "StackOutOfIndex";
return nullptr;
}
return &arr[i];
}
};
bool Stack:: push(char elementToPush) {
if(top > 98) {
cout << "\nStack Overflow!!";
return false;
} else {
arr[++top] = elementToPush;
return true;
}
}
char Stack:: pop() {
if(top <= -1) {
cout << "\nStack Underflow!!";
return ' ';
} else {
return (arr[top--]);
}
}
char Stack:: peek() {
if(top > 98) {
cout << "\nStack Overflow!!";
return ' ';
} else {
return arr[top];
}
}
bool Stack:: isEmpty() {
return (top <= 0);
}
void Stack:: displayAll() {
if(top <= -1) {
cout << "null";
return;
}
int i = top;
while (i >= 0) {
cout << arr[i] << " ";
--i;
}
cout << "\n";
}
Infix Class
#include<iostream>
#include<cstring>
#include<D:\Programs\11Stack.cpp>
using namespace std;
class Infix : public Stack {
string outputString;
char operatorArray[];
public:
Infix() {
push('(');
cout << "Element In Stack: " << *returnElement(returnTop()) << endl;
outputString = "";
strcpy(operatorArray, "/*-+%");
cout << "Operator Array: " << operatorArray << endl;
}
string infixToPostfix(char *, int);
bool manupulateOperator(char, int);
int checkPrecedence(char);
~Infix() {
cout << "\nStack Object Destroyed!" << endl;
}
};
string Infix:: infixToPostfix(char *str, int size) {
cout << "\nGiven String: " << str << endl;
int x;
for(int i = 0; i < size; ++size) {
x = str[i];
if(x != ' ') {
if(x == ')') {
while(returnTop() != '(') {
cout << pop() << " popped!\n";
}
cout << pop() << " popped!\n";
} else if(isalpha(x)) {
cout << x;
} /* else{ // scanned character is an operator
if(manupulateOperator(x, i)) {
} else {
return " ";
}
} */
}
}
return outputString;
}
bool Infix::manupulateOperator(char c, int position) {
try {
char topElement = *returnElement(returnTop());
if(checkPrecedence(c) == -1) {
cout << "\nErr\n";
}else if((checkPrecedence(c) > checkPrecedence(topElement)) || returnTop() == 0) {
push(c);
cout << c << " pushed!\n";
}
} catch(std::exception e) {
std::cerr << e.what() << '\n';
return false;
} catch (char* Ce) {
cout << Ce << endl;
}
return true;
}
int Infix::checkPrecedence(char c) {
/*
+ -> 1
- -> 1
* -> 2
/ -> 2
% -> 2
*/
switch(c) {
case '+':
return 1;
case '-':
return 1;
case '*':
return 2;
case '/':
return 2;
case '%':
return 2;
default:
// throw "Illegal Operator Detected!";
cout << "Illegal Operator Detected: " << c << endl;
return -1;
}
}
int main() {
cout << endl;
int x = 1;
char inp[] = "(A+B)/(C*D))";
//Infix i;
cout << "In main: " << inp /* + ')' */ << endl << endl;
// cout << i.infixToPostfix(input + ')', sizeof(input));
/* for(int i = 0; i < strlen(inp); ++i) {
cout << inp[i];
}
*/
return 0;
}
You are declaring operatorArray as an array of char but you are not assigning any memory for it! So, when you then call strcpy(operatorArray, "/*-+%"); in your Infix constructor, you are causing undefined behaviour by attempting to copy the given string constant to memory that hasn't been assigned - and this appears to be overwriting the inp[] array declared in your main.
To fix this, I would suggest giving your operatorArray member a specific size, which will be large enough to accommodate whatever string you want to copy to it - 8 characters will work in the sample code you've given:
class Infix : public Stack {
string outputString;
char operatorArray[8]; // Make this member a REAL array of characters.
//..
Your variable char operatorArray[] have no memory allocated when your constructor is called. When you use strcpy, you write to a place where you don't have permissions in your memory, and therefore on other informations.
To find these kinds of mistakes, I recommend using valgrind.
char operatorArray[]; is not allowed in Standard C++.
If you didn't see an error message then I would recommend adjusting compiler settings to follow the standard form of the language, this would have saved you a lot of time.
The issue is portrayed clearly in the display function.I wanted to display the array items in top, but I couldn't figure out a way to do so as it was constantly being incremented.
Instead of this...:
void CircularQueue :: Display() const {
for(int i = front; i < MAX; i++) {
cout << a[i] << endl;
}
}
**I want to display the circular queue using top:**
void CircularQueue :: Display() const {
for(int i = front; i < top; i++) {
cout << a[i] << endl;
}
}
In my main function, I enqueue'd 15 items, and as a result, top incremented 15 times. So obviously there would be 5 garbage values. How can I manipulate top so that the display function shows all 10 array values?
#include <iostream>
using namespace std;
#define MAX 10
class CircularQueue {
private:
int top;
int front;
public:
//assume that the max number of items in this circular queue is 10.
int a[MAX];
CircularQueue() {top = -1; front = -1;}
int enqueue(int x);
void dequeue();
void peekFront() const;
void peekBack() const;
void Display() const;
bool isEmpty();
};
//1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
//10,11,12,13,14,15,6,7,8,9
int CircularQueue :: enqueue(int x) {
//Problem: The array is actually growing in size.
++top;
a[top%10] = x;
int y = a[top%10];
cout << "Adding " << y << " to the queue." << endl;
if(top == 0) {
front = 0;
}
return y;
}
void CircularQueue :: dequeue() {
if(top < 0) {
cout << "The queue is empty." << endl;
} else {
int x = a[top];
cout << x << " will now be removed." << endl;
for(int i = 0; i <= top - 1; i++) {
a[i] = a[i+1];
}
top--;
x = a[top];
cout << "The last element of the queue is now: " << x << endl;
}
}
bool CircularQueue :: isEmpty() {
return top < 0;
}
void CircularQueue :: peekFront() const {
if(front < 0) {
cout << "The queue is empty." << endl;
} else {
int x = a[front];
cout << "The Front value is: " << x << endl;
}
}
void CircularQueue :: peekBack() const {
if(top < 0) {
cout << "The queue is empty." << endl;
} else {
int x;
x = a[top];
cout << "The back value is: " << a[top] << endl;
}
}
void CircularQueue :: Display() const {
for(int i = front; i < MAX; i++) {
cout << a[i] << endl;
}
}
int main() {
CircularQueue Aq;
Aq.enqueue(0);
Aq.enqueue(1);
Aq.enqueue(2);
Aq.enqueue(3);
Aq.enqueue(4);
Aq.enqueue(5);
Aq.enqueue(6);
Aq.enqueue(7);
Aq.enqueue(8);
Aq.enqueue(9); Aq.Display();
Aq.enqueue(10);
Aq.enqueue(11);
Aq.enqueue(12);
Aq.enqueue(13);
Aq.enqueue(14);
Aq.enqueue(15); Aq.Display();
return 0;
}
Expected output should be:
10,11,12,13,14,15,6,7,8,9
The array size should be 10 always. But when I keep enqueueing; The array size goes beyond 10.
Trying to Implement a hash table in C++, Where the table has to take in string data and must hold at least 10 items. Implemented this below but doesn't compile and have broke it somehow :(, open to other ideas on how is best to implement or a fix for this one
Thanks
Someone be a legend please. :)
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class hash{
private:
static const int tableSize = 10;
struct item
{
string d;
item* next;
};
item* HashTable[tableSize];
public:
hash();//the constructor
int Hash(string key);
void AddItem(string d);//will add new item
int NumberOfItemsInBucket(int bucket);
void PrintTable();
void PrintItemsInBucket(int bucket);
};
hash::hash()
{
for(int i = 0;i < tableSize;i++)
{
HashTable[i] = new item;
HashTable[i]->d = "";
HashTable[i]->next = NULL;
}
};
void hash::AddItem(string d)
{
int bucket = Hash(d);
if(HashTable[bucket]->d == "")
{
HashTable[bucket]->d = d;
}
else
{
item* Ptr = HashTable[bucket];
item* n = new item;
n->d = d;
n->next = NULL;
while(Ptr->next != NULL)
{
Ptr = Ptr->next;
}
Ptr->next;
}
}
int hash::NumberOfItemsInBucket(int bucket)
{
int slot = 0;
if(HashTable[bucket]->d == "")
{
return slot;
}
else
{
slot++;
item* Ptr = HashTable[bucket];
while(Ptr->next != NULL)
{
slot++;
Ptr = Ptr->next;
}
}
return slot;
}
void hash::PrintTable()
{
int number;
for(int i = 0;i < tableSize;i++)
{
number = NumberOfItemsInBucket(i);
cout << "--------------------\n";
cout << "bucket = " << i << endl;
cout << "Data: " << HashTable[i]->d << endl;
cout << "No. of items = " << number << endl;
cout << "--------------------\n";
}
}
void hash::PrintItemsInBucket(int bucket){
item* Ptr = HashTable[bucket];
if(Ptr->d == ""){
cout << "bucket " << bucket << " is empty!\n";
}else{
cout << "Bucket " << bucket << " contains this: " << endl;
while(Ptr != NULL){
cout << "--------------------\n";
cout << Ptr->d << endl;
cout << "--------------------\n";
Ptr = Ptr->next;
}
}
}
int hash::Hash(string key){
int hash = 0;
int index;
for(int i = 0;i < key.length();i++)
{
hash = hash + (int)key[i];
//cout << "Hash = " << hash << endl; //displays the hash function result
}
index = hash % tableSize;
return index;
}
int main (){
hash newHash;
newHash.AddItem("restaurant");
newHash.AddItem("innovation");
newHash.AddItem("vegetarian");
newHash.AddItem("opposition");
newHash.AddItem("attractive");
newHash.AddItem("incredible");
newHash.AddItem("assessment");
newHash.AddItem("illustrate");
newHash.AddItem("presidency");
newHash.AddItem("background");
newHash.PrintTable();
//newHash.PrintItemsInBucket();
return 0;
}
Compile errors:
note: class hash
error: 'newHash' not declared in the scope
error: reference to 'hash' is ambiguous
Just remove the using manespace std; and add explicitly add std:: to endl, cout, and string.