I am creating a trie and am having trouble at the time of compiling.
The warningI get is:
"Reading invalid data from 'currNode->dict': the readable size is '104' bytes, but '388' bytes may be read."
#pragma once
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int SIZE = 26;
struct Node {
bool isWord;
Node* dict[SIZE];
};
class Dictionary
{
public:
Dictionary();
Dictionary(string file);
void addWord(string word);
private:
Node *root;
int numWords;
};
Dictionary::Dictionary()
{
numWords = 0;
root = new Node;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
}
Dictionary::Dictionary(string file)
{
numWords = 0;
root = new Node;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
ifstream inFile;
string word;
inFile.open(file);
while (inFile >> word) {
addWord(word);
numWords++;
}
}
void Dictionary::addWord(string word)
{
int len = word.length(); // size of word
char letter;
int pos;
Node *currNode = root;
for (int i = 0; i < len; i++) {
letter = word[i]; // takes character at position i
pos = letter - 'a'; // finds the position of the character in the array (0 through 25)
// with 'a' being 0 and 'z' being 25
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node;
currNode->isWord = false;
}
currNode = currNode->dict[pos];
}
currNode->isWord = true;
}
What could be causing this? I'm pretty sure that I'm not trying to access invalid memory. Perhaps it's the way I setup my node and class?
One mistake is that you fail to initialize Node to default values. In your Dictionary default constructor, you have code that really should be part of what Node should be doing:
root = new Node ;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
This should be Node's job, not the job of Dictionary.
Instead, you have this:
struct Node {
bool isWord;
Node* dict[SIZE];
};
So every time you do this:
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node;
You are creating an uninitialized Node object. That entire Node::dict array contains uninitialized pointers, which you later try to access.
The easiest solution is to zero-initialize the Node object.
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node(); // <-- Note the parentheses
This will automatically set the dict pointers to nullptr.
The other method is to make sure Node objects are created with default values:
#include <algorithm>
struct Node {
bool isWord;
Node* dict[SIZE];
Node() : isWord(false) { std::fill_n(dict, SIZE, nullptr); }
};
With this, even new Node; will create nodes that are initialized.
Related
The question is
There is a collection of input strings and a collection of query strings. For each query string, determine how many times it occurs in the list of input strings.
strings = [ab,ab,abc]
queries = [ab,abc,bc]
There are instances 2 of ab, 1 of 'abc' and 0 of 'bc'. For each query, add an element.
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
struct node {
int data;
node *next;
}*first=NULL,*last= new node;
void create(int count) {
node *temp;
temp = new node;
temp->data = count;
temp->next = NULL;
if(!first) first=last=temp;
else {
last->next = temp;
last = temp;
}
}
void display() {
node *temp = first;
while(temp) {
cout<<temp->data<<endl;
temp = temp->next;
}
}
void matchStrings(string s[],string q[],int s_count,int q_count){
int counter;
// res = new int[q_count];
for(int i=0;i<=q_count;i++){
counter = 0;
for(int j=0;j<s_count;j++){
if( q[i] == s[j] ) counter++;
}
if(counter != 0) create(counter);
else create(0);
}
// return res;
}
int main() {
int string_count,query_count,*res;
cin>>string_count;
string strings[string_count];
for(int i=0;i<string_count;i++) cin>>strings[i];
cin>>query_count;
string queries[query_count];
for(int i=0;i<query_count;i++) cin>>queries[i];
matchStrings(strings,queries,string_count,query_count);
// res = matchStrings(strings,queries,string_count,query_count);
matchStrings(strings,queries,string_count,query_count);
// for(int i=0;i<query_count;i++) cout<<res[i]<<endl;
display();
return 0;
}
Now I am trying to implement it using Linked List but instead of getting output as 2,1,0.
I am getting output as 2,1,0,2,2,1,0,2.
I dont how is the LL being created for more than 3 links.
Please help.
In the function void matchStrings(),
you have written
for(int i=0;i<=q_count;i++){
Rather it should be
for(int i=0;i<q_count;i++){
Because of the extra iteration, a randomly generated string gets checked with the set of strings[], and as a result they are incorrectly matched.
So this leads to the execution of create(0) one extra time, which results in creating an extra node with data 0, that gets printed.
I write a code for insertion sort for integer data in linked list in c++, I referred to the algorithms on the Internet, and finally took the following code using array as a basic concept for my version.
however, the sorting always ignore my first element,(but all the other element is ordered well).
I have tried checking my loop statement, checking the pointer address while looping (because my key pointer loop at first time didn't go into the judge pointer loop), checking the shifting mechanism while comparing, but I cannot find my logic problem.
(I know someone would said I doesn't provide enough data for you to help me, but I have been checking these things for two days, including asking friends and searching the solutions existed on website. So I really hope someone can answer me without blame, thank you.)
array version(on the internet)
#include <iostream>
void InsertionSort(int *arr, int size){
for (int i = 1; i < size; i++) {
int key = arr[i];
int j = i - 1;
while (key < arr[j] && j >= 0) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
linked list version(by my own)
Node class used in my version
class Node
{
public:
Node()
{
next = NULL;
pre = NULL;
}
Node(int n)
{
data = n;
next = NULL;
pre = NULL;
}
int getData() { return data; }
Node *getNext() { return next; }
Node *getPre() { return pre; }
void setData(int d) { data = d; }
void setNext(Node *n) { next = n; }
void setPre(Node *p) { pre = p; }
private:
int data;
Node *next, *pre;
};
class List
{
public:
List() { list = NULL; }
List(int n) { generate(n); }
void generate(int n)
{
int j;
list = NULL;
for(j = 0;j < n;j ++)
generate();
}
void generate()
{
Node *buf = new Node(rand());
buf->setNext(list); //list->NODE2.next->NODE1.next->NULL
if(list != NULL)
list->setPre(buf);
list = buf;
}
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;// judge is the value that is going to compare with key
int key;
for(keyptr = list->getNext(); keyptr != NULL;
keyptr = keyptr->getNext()){
//if we set list as 5,7,6 ; 6 is key
key = keyptr->getData();//store the key value for the setting after shifting
breakByCompare = 0;
for(judgeptr = keyptr->getPre() ; judgeptr->getPre()!= NULL;
judgeptr= judgeptr->getPre()){
//list: 5,7,6 ; 7 is judge
if(judgeptr->getData() > key){
// 7>6, so we shift 7 to the position which was for 6
judgeptr->getNext()->setData(judgeptr->getData());// list: 5,7,7 ;
cout << judgeptr->getData() << " , " << keyptr->getData() << endl;
}
else{
break;
}
}
judgeptr->getNext()->setData(key);// list: 5,6,7
}
}
void print()
{
Node *cur = list;
while(cur != NULL)
{
cout<<cur->getData()<<" ";
cur = cur->getNext();
}
cout<<endl;
}
private:
Node *list;
};
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define SIZE 100
int main()
{
srand(time(NULL));
List *l = new List(10);
l->print();
l->insertionSort();
l->print();
}
One of the most important difference between a linked list and an array is that it is sometimes required to handle the first element as a special case.
Here is a fixed version of your sorting method :
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;
int key;
for(keyptr = list->getNext(); keyptr != NULL; keyptr = keyptr->getNext()){
key = keyptr->getData();
breakByCompare = 0;
// I replaced judgeptr->getPre() by judgeptr in the condition
// to allow the backward loop to go until the root
for(judgeptr = keyptr->getPre() ; judgeptr != NULL; judgeptr= judgeptr->getPre()){
if(judgeptr->getData() > key){
judgeptr->getNext()->setData(judgeptr->getData());
cout << judgeptr->getData() << " , " << key << endl;
}
else break;
}
// Here is the special case : we must support a null judgeptr
// and replace its next element by the list
if (judgeptr) judgeptr->getNext()->setData(key);
else list->setData(key);
}
}
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 am trying to make a dynamic array in my member function, however, it seems to create a new dynamic array each time I call the function. Is there anyway to create a dynamic array inside a member function so it doesn't remake itself.
class predator
{
private:
string name;
string species;
protected:
string *list;
public:
predator(string theSpecies);
void killsRecorded(string kills); // add a new kill to the end of the predator's list of kills
string *killsList(); // return a pointer to the array of all kills by this predator
int noOfTotalKills(); // how many kills have been recorded
int k;
static int n;
};
//The header file
void predator::killsRecorded(string kills)
{
k = 0;
list = new string[5];
*(list + k) = kills;
k = n++;
cout<< k<< endl;
}
string* predator::killsList()
{
//cout<< (sizeof(list)/sizeof(list[0]))<< endl;
for(int i=0; i<5; i++)
{
cout<< *(list + i)<< endl;
}
}
Above is my class and header file, void killsRecorded(string kills) should add kills to my array, however, when I try that in my main.
predator *prey;
prey = new predator("Cheetah");
prey->killsRecorded("Mouse");
prey->KillsRecorded("Donkey");
prey->killsList();
It prints out
Created a hunter that is a Cheetah
0
1
Donkey
*BLANK LINE
*BLANK LINE
*BLANK LINE
*BLANK LINE
Instead, Mouse should be in the first line and Donkey in the second. Am I doing something wrong? Also, I can't use vectors, it's for an assignment.
In your constructor, assign n a default value, say 5. Then create an array of that size.
predator::predator()
: n(5),
k(0)
{
kills = new string[n];
}
Then recordKills checks to see if there is space in kills, reallocating if necessary:
recordKills(string kill)
{
if(k >= n) {
string* oldKills = kills;
kills = new string[2*n];
// copy
for(int i = 0; i< n: i++) {
kills[i] = oldKills[i];
}
n *= 2;
delete [] oldKills;
}
kills[k++] = kill;
}
It's generally a bad idea to call a variable by the name of a data structure, so I renamed 'list' to 'kills'.
Then when printing the kills, loop until k:
string* listKills()
{
for(int i = 0; i < k; i++) {
cout << kills[i] << endl;
}
return kills;
}
Remember to delete kills in the destructor!
Hmm, your killsRecorded(string kills) method is an example of how not to program...
you erase list losing all previously recorded kill
you lose the pointer obtained by a previous new[] which leads to a memory leak (how could you free them now your program has forgotten what had been allocated)
What should be done (what vector class does under the hood):
define a chunk of slots that you initially allocate
add the recorded strings to this simple array until it is full
when it is full allocate another array say of twice the size, carefully copy the values from the old array, release the old array and only them affect the new array to the saved pointer
do not forget to release the allocated array in class destructor
and store in the class the current size (number of kills) and the maximum size (allocated size)
Code could be:
class predator
{
private:
string name;
string species;
protected:
string *list;
size_t max_size;
size_t cur_size;
public:
predator(string theSpecies);
void killsRecorded(string kills); // add a new kill to the end of the predator's list of kills
string *killsList(); // return a pointer to the array of all kills by this predator
int noOfTotalKills(); // how many kills have been recorded
/*int k; what it that???
static int n;*/
};
//The implementation file
predator(string theSpecies): species(species) {
list = new string[5];
max_size = 5;
cur_size = 0;
// what do you do with name ?
}
void predator::killsRecorded(string kills)
{
if (cur_size >= max_size) { /* need a bigger array */
max_size *= 2;
temp = new string[max_size];
for(int i=0; i<cursize; i++) { // copy previous recorded values
temp[i] = list[i];
}
delete[] list; // free previous allocated array
list = temp; // ok list is now big enough
}
list[cur_size++] = kills;
}
You should use std::vector...
to do that you have to
#include <vector>
with the command
std::vector<string> kills;
you can create a new vector of strings
with the command
kills.pushback(stringvalue);
you can add a new string into your vector "list" also you don't have to count your kills... you can use
kills.size();
to get the number of strings back.
To get the values (strings) back you can use the vector like an array
string name = kills[3];
btw: you should save the vector as a member... to do that you have to save it in your class definition (header)
If you arn't allowed to use std::vector, you can write your own list...
class list
{
private:
node* head;
int size = 0;
struct node
{
node* next;
string value;
}
public:
list();
~list();
void PushBack(string);
string GetElement(int index);
int GetSize();
};
list::list()
{
head = new list();
head->next = nullptr;
}
list::~list()
{
node* temp = head;
node* temp2 = temp;
do //delete hole list
{
temp2 = temp->next;
delete temp;
temp = temp2;
}while(temp != nullptr);
}
void list::PushBack(string item)
{
node* temp = head;
while(temp->next != nullptr)
{
temp = temp->next;
}
//found the end of the list
node* newNode = new node();
newNode->value = item;
newNode->next = nullptr;
temp->next = newNode;
size++;
}
int list::GetSize()
{
return size;
}
string list::GetElement(int index)
{
node* temp = head;
while(temp->next != nullptr)
{
temp = temp->next;
if(index == 0)
{
return temp->value;
}
index--;
}
//index out of bounds
return "";
}
I can not check if the code is correct at the moment, because on this computer is no IDE... but I think it should word ;)
BTW: you can use this list instead of an array to do that you have to write:
list kills;
kills.PushBack("Peter");
kills.PushBack("Thomas");
kills.PushBack("Alex");
for(int i = 0; i< kills.GetSize();i++)
{
std::cout<<kills.GetElement(i)<<std::endl;
}
i want to make a linked list ..
but the first node with a data and null link
if i input a string (123)
linked list be like this:
1/null - 2/point to the last one(1) - 3/point to the last one(2)
#include <iostream>
#include <string>
using namespace std;
struct link
{
int data;
link* next;
};
class LinkedList
{
private:
link* first;
public:
LinkedList(){}
void Add(string s)
{
for (int i = 0; i > s.length(); i++)
{
if (i == 0)
{
first->data = s[i];
first->next = NULL;
}
else
{
link* NewOne = new link;
NewOne->data = s[i];
NewOne->next = first;
first = NewOne;
}
}
}
void display()
{
cout << first->data;
}
};
int main()
{
LinkedList l1;
l1.Add("2734");
l1.display();
return 0;
}
what's the wrong in the code
You forget to allocate memory for first.
Following may help (using std::unique_ptr for free/correct memory management):
struct link{
char data;
std::unique_ptr<link> next;
};
class LinkedList {
private:
std::unique_ptr<link> first;
public:
void Set(const std::string& s){
for (auto c : s) {
std::unique_ptr<link> node = std::move(first);
first = std::make_unique<link>();
first->data = c;
first->next = std::move(node);
}
}
Live example
It also looks like you're storing characters in an int. Your output will be the ASCII value of the character rather than the raw int values.
I would recommend using unique pointers as Jarod42 has done. Having said that, this quick example below does not use them so you will need to call delete appropriately or use unique_ptr.
I added a last pointer to help traversal of the list as we make new links.
private:
Link * first;
Link *last;
int numLinks;
public:
LinkedList()
{
first = NULL;
last = NULL;
numLinks = 0;
}
Now for Add
void Add(string s)
{
for (int i = 0; i < s.length(); i++)
{
if (numLinks == 0)
{
first = new Link;
first->data = (s[i] - '0');
first->next = NULL;
last = first;
numLinks++;
}
else
{
Link * newLink = new Link;
newLink->data = (s[i] - '0');
newLink->next = NULL;
last->next = newLink;
last = newLink;
numLinks++;
}
}
}
The constructor does not initialize the first member. Subsequently, in Add():
for (int i = 0; i > s.length();i++){
if (i == 0){
first->data = s[i];
first->next = NULL;
}
This ends up dereferencing an uninitialized pointer, leading to undefined behavior.
There's also a problem with your display() too, but this is the main problem.