C++: Updating binary search tree using a recursive search function? - c++

I'm in the middle of making a binary search tree that stores Items of type MechPart, which stores an int quantity and a string code. The MechParts are generated by reading from a text file and storing their data. A separate text file called MonthlyUpdate.txt is used to read a list of MechParts in the tree and then update their quantities. For example:
MechPart A0001's quantity = 12
MonthlyUpdate.txt says A0001's quantity = 6
Run an update function that finds A0001 in the tree
Replace it with the updated quantity value of 6 (12 - 6).
Here's the two functions that perform this task:
void DBInterface::updateFromFile(string f_Name)
{
ifstream file (f_Name.c_str());
string line;
MechPart tmp_mp;
if (file.is_open())
{
std::getline(file, line);
while (std::getline (file, line))
{
std::istringstream iss (line);
int q=0;
int pos=0;
pos = line.find('\t',0); //find position of blank space
string tmp_str = line.substr(0,pos); //create a substring
string tmp_str1 = line.substr((pos+1), string::npos);
stringstream ss (tmp_str1);
ss >> q;
tmp_mp.set_code(tmp_str); //set code
tmp_mp.set_quantity(q);
MechPart currentQuantity;
currentQuantity = tree.quantitySearch(tree.getRoot(), tmp_mp);
tmp_mp.set_quantity((currentQuantity.get_quantity()) + q);
tree.update(tree.getRoot(), tmp_mp);
cout << "Current node data: " << tmp_mp.get_code() << " | " << tmp_mp.get_quantity() << endl;
}
}
and BSTree.template:
template <typename Item>
Item BSTree<Item>::quantitySearch(BTNode<Item>* q_ptr, Item obj)
{
if (q_ptr == NULL)
{
//POINTER IS NULL
}
else if (q_ptr->data() == obj)
{
return q_ptr->data();
}
else if (obj > q_ptr->data())
{ //WORK ON RIGHT SIDE
quantitySearch(q_ptr->get_right(), obj);
}
else
{
//work on left side
quantitySearch(q_ptr->get_left(), obj);
}
}
The search goes through the tree and locates a MechPart with the same part name code as the parameter and then returns that MechPart.
I've been running the code through GDB debugger. I have it displaying currentQuantity.get_quantity() to validate the returned MechPart's quantity is correct, however i am getting very large numbers for some reason. What is also confusing me is that in the MechPart constructor it assigns a value of 0 to quantity.
Eventually the updateFromFile() function gives me a segmentation fault, so something is very wrong here but I can't work out what as yet.

Recursive functions need to return their recursive calls back up to their caller for them to work properly. Look at the classic factorial example of recursion:
int factorial(int n) {
if (n == 1) {
return 1;
}
else {
return n*factorial(n-1);
}
}
As others have pointed out, your quantitySearch function only returns q_ptr->data() but never returns the return value from the recursive quantitySearch calls. I would start there and I would strongly suggest adding in cout statements in the recursive function to get a complete picture of what's happening "under the hood"

Related

Returning a vector from a function in order to print the contents

My program has a function named 'WordLadder' that uses BFS to make a path from one word in a dictionary to another. I was given a starter code that prints the number of nodes in the path, but I want to print the path itself. Currently, I have appended the words to a vector as they enter a queue but I am not able to return the vector as part of my 'WordLadder' function in order to print it in the main program.
I just want the program to print a path based on the two words I picked, i.e. "TOON - POON - POIN - POIE - PLIE - PLEE - PLEA", if the start word is "TOON" in the dictionary and the target word is "PLEA" in the dictionary.
I tried to declare the vector outside of the function and print it in main with this code, but I was unsuccessful.
void print(std::vector < int >
const & transformation) {
std::cout << "The vector elements are : ";
for (int i = 0; i < transformation.size(); i++)
std::cout << transformation.at(i) << ' ';
}
I have attempted to return the vector inside of the function, but I receive this error
error: no viable conversion
from returned value of type
'vector<std::__cxx11::string>' (aka
'vector<basic_string<char> >') to
function return type 'int'
return transformation;
Here is my code. Any help would be appreciated, as I am new to C++.
// To check if strings differ by exactly one character
bool nextWord(string & a, string & b) {
int count = 0; // counts how many differences there
int n = a.length();
// Iterator that loops through all characters and returns false if there is more than one different letter
for (int i = 0; i < n; i++) {
if (a[i] != b[i]) {
count++;
}
if (count > 1) {
return false;
}
}
return count == 1 ? true : false;
}
// A queue item to store the words
struct QItem {
string word;
};
// Returns length of shortest chain to reach 'target' from 'start' using minimum number of adjacent moves. D is dictionary
int wordLadder(string & start, string & target, set < string > & ew) {
//Create vector to store path in a
vector < string > transformation;
// Create a queue for BFS and insert 'start' as source vertex
queue < QItem > Q;
QItem item = {
start
};
Q.push(item);
// While queue is not empty
while (!Q.empty()) {
// Take the front word
QItem curr = Q.front();
transformation.push_back(Q.front().word);
Q.pop();
// Go through all words of dictionary
for (set < string > ::iterator it = ew.begin(); it != ew.end(); it++) {
// Proccess the next word according to BFS
string temp = * it;
if (nextWord(curr.word, temp)) {
// Add this word to queue from the dictionary
item.word = temp;
Q.push(item);
// Pop from dictionary so that this word is not repeated
ew.erase(temp);
// If we reached target
if (temp == target) {
return trasformation;
}
}
}
}
return 0;
}
// Driver program
int main() {
string start;
string target;
// make dictionary
std::ifstream file("english-words.txt");
set < string > ew;
copy(istream_iterator < string > (file),
istream_iterator < string > (),
inserter(ew, ew.end()));
cout << endl;
cout << "Enter Start Word" << endl;
cin >> start;
cout << "Enter Target Word" << endl;
cin >> target;
cout << wordLadder(start, target, ew);
return 0;
}
There are multiple problems.
You were on the right track when you said "I tried to declare the vector outside of the function and print it in main..."
So, change wordLadder to take the vector by reference.
int wordLadder(vector<string> &transformation, string & start, string & target, set < string > & ew)
Then declare it in main and pass it to wordLadder
vector<string> t;
wordLadder(t, start, target, ew);
print(t);
You will have to also change print to take a vector of the right type, ie. string and not int
void print(std::vector < string > &transformation)

Real time data from CSV read in C++

I need to read data from CSV file which is updated every second with a new data in the same cell and row.
What i mean is following :
For example i have 1 in the first row and cell then i have already 2 etc. But everything is changed in the same row and column.
struct Node
{
double number;
}
void readData(vector<Node>&Values)
{
Node Data;
ifstream file("file.csv");
if (file.good())
cout << "file ok";
file >> Data.number;
Values.push_back(Data);
}
int main()
{
vector<Node>Values;
while (true)
{
readData(Values);
_sleep(1000);
}
}
The problem i have is that it reads every second the new data but it saves in the vector the same number from the beginning. If the number was 1, it will save the same number hundreds times even if the number has been changed 10 times.
What should i change in the read file to work with the data which can be updated because the csv file is opened and updated, i can not close it?
I am pretty sure that it can be done the problem i did not find any solution in the internet.
Thank you in advance!
I would simplify the code as such;
double ReadData()
{
double val;
ifstream file("file.csv");
if (!file.good())
{// Check if valid, return Error Code
return 0;
}
file >> val;
return val;
}
int main()
{
vector<double> values;
while (true)
{
double retVal = ReadData();
if (retVal == 0)
{// Whatever you defined the error code as
break;
}
values.push_back(retVal);
_sleep(1000);
}
}
and if you really want the structure I'd just return the data and add it to the structure in the main loop.
Change from _sleep(1000) to _sleep(150

(C++) Cannot use string::substr to assign substrings to objects

I am designing a cheat for the game WordBrain. Basically this is just a small program that takes a number of letters, permutes the sequence, then splits the sequence into 'words' which have length attribute, then search my text file to file meaningful permutation to print out.
while (next_permutation(letters.begin(), letters.end())) //loop through possible permutations of the combination
{
int position_marker = 0; //serve specific purpose
for (auto x : substring_collection) //trouble is in this loop
{
string temp;
int k = x.take_length();
try { temp = letters.substr(position_marker, k); }
catch (out_of_range) { cout << "OUT OF RANGE"; }
x.set(temp); //member content does not register change
position_marker += x.take_length(); //also member word_length is 0 now, despite their are no invocation of methods capable of changing it
}
if (all_of(substring_collection.begin(), substring_collection.end(), [&](substring & s) {return !(library.find(s.take_content()) == library.end()); }))
{
for (auto x : substring_collection)
{
cout << x.take_content() + " ";
}
}
}
This is the location the trouble stems from. Basically, substring_collection is a vector<substring>, which contains objects of class substring
Here is how the class looks like:
class substring
{
private:
std::string content;
int word_length;
public:
substring() : content(""), word_length(0) {};
substring(std::string & s, int c) : content(s), word_length(c) {};
void set(std::string & s)
{
content = s;
}
void clear()
{
content.clear();
}
void set_length(int c)
{
word_length = c;
}
void showinfo() const
{
std::cout << "Content is " + content << " Length is : " << word_length;
}
int take_length() const
{
return word_length;
}
std::string take_content() const
{
return content;
}
};
I suspect that the reason the code goes wrong is position_marker, whose value depends on the member 'word_length' of the object substring is set to 0.
In the code prior to this loop, I only the setting method for this member to take data from users' input (from std::cin).
Can you please tell me that is there any hidden mechanism that reset the property, or create brand new objects that I did not aware of?
Also, teachings on coding styles are very welcomed. I just started learning to code so any tips are much appreciated.
for (auto x : substring_collection)
Here, x is of type substring. This is a copy of the element in the vector, and then when you modify it, you only modify the copy, not the original.
You'll have to use a reference to modify the original element in the vector
for (auto& x : substring_collection)
For why word_length is 0, I don't know, it isn't in the code you posted. My guess would be that you resized the vector, which called the default constructor of substring, which set word_length to 0.

Can't figure out this memory bug (crash after program finishes)

Entire program: http://pastebin.com/x7gfSY5v
I made a parser that takes lines from a .txt file and places them in a binary search tree based on its value. The ID is the first string, the values are the following strings separated by /
Example txt:
Abcd/foo/bar// #ID/value/value2
Abce/foo2// #ID/value
The first line would call:
//parser
SequenceMap a; #has id and value member variables
a.writeAcronym(id); #Abcd
a.writeValue(value); #foo
insertNode(a, root); #Abcd/foo put into tree
a.writeValue(value2); #bar
insertNode(a, root); #Abcd/bar put into tree
Creating the tree itself doesn't cause the crash, and it works as it should. It's only when I try accessing the minimum value of the tree when it crashes. It still shows the correct minimum value though.
Here's the function that gets the minimum value,
I doubt that this is the root cause of the problem.
But running this in main() crashes my program:
string printMin(Node * x)
{
if (x == nullptr)
return nullptr; //this isn't ever called, I parse the tree before calling this fucntion
if (x->left == nullptr)
return x -> sqmap.getAcronym(); //returns correct value (end of program) then crash
else
printMin(x->left);
}
void printMain(){
cout << printMin(root) << endl;
}
main():
a.parse("foo.txt"); //doesn't crash
a.printMain(); //crashes when called
//but doesn't crash if I remove both a.writeValue(value) from parser
Here is the insert/parser:
void parse(string file) //uses delimiter to split lines
{
string line, id, value, value2;
ifstream myfile(file);
if (myfile.is_open())
{
while(getline(myfile, line))
{
if (!line.empty())
{
SequenceMap a;
istringstream is(line);
getline(is, id, '/');
a.writeAcronym(id);
getline(is,value, '/');
a.writeValue(value); //program doesn't crash if I remove this
insertNode(a, root);
getline(is,value2,'/');
if (value2 != "")
{
a.writeValue(value2); //program doesn't crash if I remove this
insertNode(a, root);
}
}
}
myfile.close();
}
else
cout << "Could not open file.";
}
/*****************************************************/
void insertNode(SequenceMap & sq, Node * & x)
{
if (x == nullptr)
x = new Node(sq, nullptr, nullptr);
else if (sq.getValue() < x->sqmap.getValue())
insertNode(sq, x->left);
else if (sq.getValue() > x->sqmap.getValue())
insertNode(sq, x->right);
else if (sq.getValue() == x->sqmap.getValue())
x->sqmap.Merge(sq);
}
I'm seriously stuck right now, my only guess is it's a memory bug. Everything works as it should, and I do get the correct minimum value. But right after the last line of code ends, I get the crash. I made a destructor for the tree but that didn't solve it. Can anyone figure this out?
printMin doesn't return a value when you traverse the left node, so you get a garbage return from that and not a string. If you compile with the warnings all the way up you should get a warning about that.

Modifying a recursive string reverse function

I am doing some recursive exercises. The previous one was to make a reverse() function for a string which basically removes the first character and then combines the solution. I managed to do that, here is the source code (the entire source) The current task is to modify this function (the following exercise in the book) by adding a helper function which reverses a substring of the string. At this moment I am stuck at this. It is my understanding that you use helper functions when you need to pass additional arguments or something and this function takes none so I really have no idea how to approach this problem. Help appreciated.
#include <iostream>
#include <string>
using namespace std;
void reverse(string& text)
{
if (text.length() == 0)
{
return;
}
if (text.length() == 1)
{
return;
}
else
{
string firstLetter = text.substr(0,1);
text = text.substr(1, text.length()-1);
reverse(text);
text += firstLetter;
}
}
int main()
{
string a = "tyu";
reverse(a);
cout << a << endl;
return 0;
}
A guy suggested to use parameters, ect, this is my try with it:
#include <iostream>
#include <string>
using namespace std;
//is actually doing the hard work
void reverse1(string& input, int a, int b)
{
// base case
if( a >= b)
{
return;
}
//swap the characters
char tmp;
tmp = input[a];
input[a] = input[b];
input[b] = tmp;
//create the boundries for the new substring
a++;
b--;
//call the function again
reverse1(input, a, b);
}
// sets the parameters and calls the helper function
void strreverse(string& input)
{
reverse1(input, 0, input.length()-1);
}
int main()
{
cout << "Please enter the string which you want to be reversed:";
string a;
cin >> a;
strreverse(a);
cout << a << endl;
return 0;
}
The goal is probably to avoid creating all of the intermediate substrings. The helper function will take iterators, or a start and end index in addition to the string begin reversed.
Try to implement reversing so that there is only one instance of std::string (i.e. work with it as with an array). Then you will need a helper function with additional parameters (at least one parameter - which index to reverse now).
I would implement reverse here as series of exchanges: a[0] <-> a[n-1], a[1] <-> a[n-2] etc. where n is length of the string.
You can define a helper function that takes a start and an end index of the substring which it will reverse.
The function should exchange the element at the start index with that at the end index IFF the difference between the start and the end indices is 1. Otherwise, it places a recursive call to itself by decrementing the end index and incrementing the start index. You will need to keep check on the condition if the start and end index become same though.