I've been working on the input from file and think I have the logic right, but my nodes aren't linking properly. I'm able to set the root correctly and the program is able to walk through the string and load the nodes properly, just not link them. Can anyone help me sort through my logic and figure out the problem?
The input string is (A (B (D G) E) (C () F)).
struct node
{
string data;
node* left;
node* right;
};
void tree::build_tree(string &input, int i, node *n)
{
if(i > input.length())
return *n = NULL;
if(input[i] == '(')
{
string data; string temp;
int prev_i = i;
//get_data retrieves the identifier
data = get_data(input, temp, i+1);
//get_data_num retrieves the new position in the string
i = get_data_num(input, temp, i+1);
if(input[prev_i] == '('&& input[i] == ')')
{
i += 1;
*n = NULL;
}
else
{
// Allocate a new node and assign the data and
// set the pointer to the branches to null
*n = new node;
(*n)->data = data;
(*n)->left = NULL;
(*n)->right = NULL;
if(input[i] == ' ')
{i += 1; }
//Pass the address of the nodes
build_tree(input, i, &(*n)->left);
build_tree(input, i, &(*n)->right);
}
}
else if(isalnum(input[i]) || input[i] == '_' || input[i] == '-')
{
string data; string temp;
int prev_i = i;
data = get_data(input, temp, i);
i = get_data_num(input, temp, i);
if(input[prev_i] == '('&& input[i] == ')')
{
i += 1;
*n = NULL;
}
else
{
*n = new node;
(*n)->data = data;
(*n)->left = NULL;
(*n)->right = NULL;
if(input[i] == ' ')
{ i += 1; }
build_tree(input, i, &((*n)->left));
build_tree(input, i, &((*n)->right));
}
}
else if(input[i] == ' ')
{
i += 1;
}
else if(input[i] == ')')
{
i += 1;
*n = NULL;
}
else
{
cout << "The input tree is not in the correct format!" << endl;
}
}
I believe the issue is that you are not setting the value of the left and right pointers. You are passing the values of the pointers. You need to pass a pointer to the pointers (left and right), to set the value in the structure. The other alternative is to use references instead of pointers.
Here are the modifications I came up with for the code you supplied:
Changed the call to build_tree for the node argument be a pointer to
a pointer.
Changed assignments of values accordingly.
Changed call to build_tree to pass the address of left and right (to
get a pointer to a pointer).
Remove the assignment/conditions to set the root_node. So when you
call the build_tree you need to pass in the address of root. This
will set the node just like all of the nodes which follow, so it does not need
to be a special case.
Added assignment of NULL for left and right in case there is not a
branch (may not need to do this, but I feel it is good practice to
make sure all items have some initial values).
void tree::build_tree(string &input, int i, node **n)
{
if(input[i] == '(')
{
string data; string temp;
//get_data retrieves the identifier
data = get_data(input, temp, i+1);
//get_data_num retrieves the new position in the string
i = get_data_num(input, temp, i+1);
// Allocate a new node and assign the data and
// set the pointer to the branches to null
*n = new node;
(*n)->data = data;
(*n)->left = NULL;
(*n)->right = NULL;
if(input[i] == ' ')
{ i += 1; }
// Pass the address of the nodes
build_tree(input, i, &(*n)->left);
build_tree(input, i, &(*n)->right);
}
else if(isalnum(input[i]) || input[i] == '_' || input[i] == '-')
{
string data; string temp;
data = get_data(input, temp, i);
i = get_data_num(input, temp, i);
*n = new node;
(*n)->data = data;
(*n)->left = NULL;
(*n)->right = NULL;
if(input[i+1] == ' ')
{ i += 1; }
build_tree(input, i, &((*n)->left));
build_tree(input, i, &((*n)->right));
}
else if(input[i] == ' ')
{
i += 1;
}
else if(input[i] == ')')
{
*n = NULL;
}
else
{
cout << "The input tree is not in the correct format!" << endl;
}
}
Then for the initial call,
build_tree(testString,0,&root);
Since the get_data and get_data_num were not supplied, I was not able to test the changes which were made.
Related
edit, I'll try to give a better exemple:
first I'll tell your about the program:
basicly, there' two phases, the first is inserting the words (works perfectly fine)
struct trieLeaf {
keyType age = 1;
};
class Trie
{
private:
dataType character;
trieLeaf *leaf = nullptr;
class Trie **alphabet = nullptr;
int main()
{
string input;
Trie dictionary('\0');
while (getline(cin, input) && input[0] != '.')
{
dictionary.analyzeText(input);
}
while (getline(cin, input) && input[0] != '.')
{
dictionary.approxFind(input);
}
system("pause>null");
}
second phase is searching for words, if words is found then I need to reduce the number of times it has been added by 1.
if number of times it has been added is 0, then I remove it.
void Trie::approxFind(string &word)
{
int index = 0;
string result;
Trie *curr;
if (curr=find(word))
{
cout << curr->leaf->age << endl;
curr->leaf->age -= 1;
if (curr->leaf->age == 0)
{
remove(word);
}
}
else
{
result = approximate(word);
cout << "Did you mean " << result << "?\n";
}
}
Trie* Trie::find(const string &word)
{
int index = 0;
Trie *curr = this;
while (word[index] != '\0')
{
if (curr->alphabet[word[index] - 'a'] != nullptr)
{
curr = curr->alphabet[word[index++] - 'a'];
}
else
{
return (nullptr);
}
}
if (curr->leaf != nullptr)
{
return (curr);
}
}
void Trie::remove(const string &word)
{
int index = 0;
Trie *curr = this, **tempArr, *temp;
while (word[index] != '\0')
{
tempArr = curr->alphabet;
temp = curr;
curr = curr->alphabet[word[++index] - 'a'];
if (!isArrEmpty(tempArr))
{
delete(tempArr);
}
delete(temp);
temp = nullptr;
}
}
bool Trie::isArrEmpty(Trie **alphabet)
{
for (int index = 0; index < 26; index++)
{
if (!alphabet[index])
{
return (true);
}
}
return(false);
}
TempArr in isArrEmpty is losing the object it's pointing to when passing onto the funcion.
I hope it gives a better idea why
I'm working a project for class that requires creating a binary search tree of criminal names with up to 8 attributes per criminal.
I set up a string array att[] that will read in the attributes for each criminal, and then be passed to my BSTInsert class function. Through debugging I can see that the array is correct when it's just in the setupTree function. Once it's passed to BSTInsert, instead of having each string it only has one string, and on top of that nothing is copied from the array to the node in the tree.
Can anyone tell me what I'm doing wrong?
Here's my code for setting up the tree:
void setupTree(BST& criminals)
{
ifstream fin("criminals.txt");
string temp;
fin >> temp;
//FINISHED means it has all the criminals
while (temp != "FINISHED")
{
//SUSPECT lets it know to read in a new name and new attributes
if (temp == "SUSPECT")
{
string name;
string att[8];
int count = 0;
fin >> temp;
//if there is a false "suspect" line, quit
if (temp == "FINISHED") return;
name = temp;
fin >> temp;
while (temp != "SUSPECT" && temp != "FINISHED")
{
att[count] = temp;
count++;
fin >> temp;
}
criminals.BSTInsert(name, att, count);
}
}
}
Here's my class function for inserting a node:
bool BST::BSTInsert(treetype name, treetype att[], int count)
{
//gets the memory for the node. If unable, returns fail.
node* newNode = new node;
if (newNode == NULL)
{
return false;
}
newNode->count = 0;
//initializes the node with the given information to place
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[count];
newNode->count++;
}
newNode->name = name;
newNode->left = newNode->right = NULL;
//if the tree is empty, creates this node as the root
if (root == NULL)
{
root = newNode;
root->parent = NULL;
}
else
{
//the tree is not empty, so it will use the parent to insert the node
node* current = root;
node* parent = NULL;
//finds the insertion spot
while (current != NULL)
{
parent = current;
if (name <= current->name)
{
current = current->left;
}
else
{
current = current->right;
}
}
//inserts the new node onto the correct side of the parent
if (name <= parent->name)
{
parent->left = newNode;
}
else
{
parent->right = newNode;
}
newNode->parent = parent;
}
return true;
treetype att[] doesn't pass an array, it passes a pointer to an array - it decays to treetype att*.
That said, your problem is here:
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[count];
newNode->count++;
}
This copies the wrong element of att (beyond the end of the array) into every att in newNode. What you meant was
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[newNode->count];
newNode->count++;
}
I am trying to insert the Morse Code into a binary tree but my Insert() is acting up. I'm stumped as to why it's failing.
Binary tree class:
class BST
{
private:
struct Node
{
string letter;
string code;
Node *left;
Node *right;
};
Node *root;
public:
BST()
{
root = NULL;
}
void Insert(Node *&r, string letter, string code)
{
if(r == NULL)
{
r = new Node;
r->letter = letter;
r->code = code;
r->left = r->right = NULL;
}
}
void Insert(string letter, string code)
{
Node *r = root;
if(r != NULL)
{
for(int i = 0; i < code.length(); i++)
{
if(code[i] == '.') r = r->left;
else if(code[i] == '-') r = r->right;
else break;
}
Insert(r, letter, code);
}
else Insert(root, letter, code);
}
};
Main:
struct alphaTree
{
string letter;
string code;
};
alphaTree tree[] = {
{"ROOT", ""}, {"E", "."}, {"T", "-"}, {"I", ".."}, {"A", ".-"}, {"N", "-."},
{"M", "--"}, {"S", "..."}, {"U", "..-"}, {"R", ".-."}, {"W", ".--"}, {"D", "-.."},
{"K", "-.-"}, {"G", "--."}, {"O", "---"}, {"H", "...."}, {"V", "...-"}, {"F", "..-."},
{"L", ".-.."}, {"P", ".--."}, {"J", ".---"}, {"B", "-..."}, {"X", "-..-"}, {"C", "-.-."},
{"Y", "-.--"}, {"Z", "--.."}, {"Q", "--.-"}
};
for(int i = 0; i < 27; i++)
{
t.Insert(tree[i].letter, tree[i].code);
}
The first 3 elements of my tree[] array get inserted but the program crashes when trying to insert "I".
When you insert a new node parents left and right are not being updated.
You may think parents are updated because you are passing pointer by reference, but you are passing r and not r->left or r->root which you should.
One possible solution is to use **r instead if *r in void Insert(string letter, string code)
You can change something like: (Working example here)
void Insert(string letter, string code)
{
Node **r = &root;
if(*r != NULL)
{
for(int i = 0; i < code.length(); i++)
{
assert(*r);
if(code[i] == '.') r = &((*r)->left);
else if(code[i] == '-') r = &((*r)->right);
else break;
}
Insert(*r, letter, code);
}
else Insert(root, letter, code);
}
Not related to your problem, but as side notes:
In for(int i = 0; i < code.length(); i++) you are comparing an
unsigned (length) with singed int. You should change i to
std::string::size_type.
In function void Insert(string letter, string code) you should add
assert(*r) before accessing *r children.
Your problem is here:
for(int i = 0; i < code.length(); i++)
{
if(code[i] == '.') r = r->left;
else if(code[i] == '-') r = r->right;
else break;
}
When this loop starts, you make sure r is never NULL. Howover, as there is only one element in the tree it will immediately become NULL for the next iteration when you set it to either r = r->left or r = r->right, as there is only one node in the tree and both it's left and right are NULL.
You are not checking if r becomes NULL while looping.
The sooner you get to an element with two or more symbols in the morse code, your application crashes trying to read from r when it's a NULL pointer.
You probably wants to extend your code to something more like this:
for(int i = 0; i < code.length(); i++)
{
if (code[i] == '.')
{
if (r->left)
r = r->left;
else
{
// todo: code to bind a new node to r->left
break;
}
}
else // its always either '.' or '-' so there is no need to double check the symbol here
{
if (r->right)
r = r->right;
else
{
// todo: code to bind a new node to r->right
break;
}
}
}
Now you are making sure the loop stops while r is still a valid pointer. The last valid pointer in the descending tree.
Of course you still have to write the decision to create the new node to the left or right side of this node.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm trying to write a function that calculates the N-th Fibonacci number using doubly linked lists, but for some reason when I compile and run the linked list does not stop growing, it keeps adding 1 number over and over with no ending.
This should be a SSCCE:
#include <iostream>
using namespace std;
class node {
public:
int value;
node* previous;
node* next;
};//node
class number {
public:
node* start;
node* end;
node* add (int value);
void show (int K);
number ();
void destroy ();
void copy (number gg1);
void addition (number gg1, number gg2, int K);
void fibonacci (int K, int times);
};//number
number::number () {
start = NULL;
end = NULL;
}
int power (int K) {
int L = 1;
for (int i = (K-1); i > 0; i--) {
L = L*10;
}
return L;
}
int checksize (int value) {
int counter = 0;
while (value != 0) {
value = value / 10;
counter += 1;
}
return counter;
}
void number::show (int K) {
node* current;
cout << "\nValue:" << endl;
if (start == NULL) {
cout << "\nNothing\n" << endl;
}
if (start != NULL) {
current = start;
while (current != NULL) {
if (current->value == 0) {
for (int i = 0; i < K; i++) {
cout << "0";
}
cout << "\n";
}
else {
int size = checksize (current->value);
for (int j = size; j < K; j++) {
cout << "0";
}
cout << current->value << endl;
}
current = current->next;
}
}
//cout << "\n";
}
int main () {
number gg1;
number gg2;
number gg3;
const int K = 5;
gg1.fibonacci (K, 10);
}
node* number::add(int value) {
node* currentcode;
if (start == NULL){
currentcode = new node;
start = currentcode;
end = currentcode;
currentcode->next = NULL;
currentcode->previous = NULL;
currentcode->value = value;
return currentcode;
}
if (start != NULL) {
currentcode = new node;
currentcode->next = NULL;
end->next = currentcode;
currentcode->previous = end;
end = currentcode;
currentcode->value = value;
return currentcode;
}
return NULL;
}
void number::addition (number gg1, number gg2, int K) {
int value1, value2, value3;
int carry = 0;
node* current1;
node* current2;
current1 = gg1.start;
current2 = gg2.start;
while (current1 != NULL || current2 != NULL) {
if (current1 != NULL && current2 !=NULL) {
value1 = current1->value;
value2 = current2->value;
value3 = value1 + value2 + carry;
current1 = current1->next;
current2 = current2->next;
}
else if (current1 == NULL && current2 != NULL) {
value3 = current2->value + carry;
current2 = current2->next;
}
else if (current1 != NULL && current2 == NULL) {
value3 = current1->value + carry;
current1 = current1->next;
}
checksize(value3);
if (value3 > power(K)) {
value3 = value3 - 10*(power(K));
carry = 1;
}
else
carry = 0;
add(value3);
if ((current1 == NULL && current2 == NULL) && (carry == 1))
add(1);
}
}
void number::destroy () {
node* current;
node* current2;
if (start != NULL) {
current = start;
current2 = current->next;
while (current2 != NULL) {
delete current;
current = current2;
current2 = current->next;
}
delete current;
}
}
void number::fibonacci (int K, int times) {
number g1;
number g2;
number g3;
destroy ();
g1.add (1);
g2.add (1);
g3.addition (g1, g2, K);
g2.copy(g1);
g1.show(K);
g2.show(K);
//g1.copy(g3);
//g1.show(K);
//g2.show(K);
//g3.show(K);
//g3.addition (g1, g2, K);
//g3.show(K);
//g2.copy(g1);
//g1.copy(g3);
/*for (int i = 0; i < 2; i++) {
g3.addition (g1, g2, K);
g3.show(K);
g2.copy(g1);
g1.copy(g3);
}*/
copy(g3);
}
void number::copy (number gg1) {
int value;
destroy ();
node* current = gg1.start;
while (current != NULL) {
value = current->value;
add(value);
current = current->next;
}
}
Whenever I run the Fibonacci function it gives me endless 1's in the terminal.
The number class is just a basic doubly linked pointer list.
The addition function standalone works just fine, so does the copy. In fact everything was working fine until this. It's easy to finish the function with a for-loop, but this error prevents me from doing so. Does anyone know what my mistake is? Thanks in advance.
Right now, you have invalid memory access, since calling delete on each node in destroy() does not NULL-out the memory but it only marks the memory free.
Suggested correction:
void number::destroy () {
node* current;
node* current2;
if (start != NULL) {
current = start;
current2 = current->next;
while (current2 != NULL) {
delete current;
current = current2;
current2 = current->next;
}
delete current;
}
start = NULL; // so you can't access the now non-existing list anymore.
end = NULL;
}
Remark:
Class names should be capital-first by widely adapted convention.
You should not pass a class by value in your copy and addition function but const-ref.
Better use in this case operator= instead of copy. copy can be copy_from or copy_to, calling a function copy is ambigous, really.
Always better to use for loops when you can.
Node is not a class but a struct, it is better to call it a struct.
The new code can also look like this:
Number& Number::operator=(const Number& n)
{
destroy();
for(Node* current = gg1.start; current; current = current->next)
add(current->value);
}
void Number::destroy()
{
Node* temp;
for(Node* current = start; current; current = current->next, delete temp)
temp = current;
start = NULL;
end = NULL;
}
so heres my header and cpp file.
template<typename T> struct TreeNode
{
TreeNode(const T& value, TreeNode<T>* left = NULL, TreeNode<T>* right = NULL)
{
Value = value;
Left = left;
Right = right;
}
T Value;
TreeNode<T>* Left;
TreeNode<T>* Right;
bool IsLeaf() const
{
return Left == NULL && Right == NULL;
}
};
and now my cpp file
#include "TreeNode.h"
#include <iostream>
#include <string>
using namespace std;
float ValueOf(TreeNode<char>* root);
float ValueOf(TreeNode<char>* root)
{
if (root->IsLeaf())
return root->Value - '0';
float expressionValueL = ValueOf(root->Left);
float expressionValueR = ValueOf(root->Right);
if (root->Value == '+')
return expressionValueL+expressionValueR;
else if (root->Value == '-')
return expressionValueL-expressionValueR;
else if (root->Value == '*')
return expressionValueL*expressionValueR;
else if (root->Value == '/')
return expressionValueL/expressionValueR;
}
void main ()
{
TreeNode<char>* treeRoot = nullptr;
TreeNode<char>* currentNode = treeRoot;
string expr;
cout<<"please input expression to be tested:";
getline (cin, expr);
cout<<endl;
int size = expr.size();
for (int i=0; i<size; i++)
{
char test = expr[i];
if ((test=='1')||(test=='0')||(test=='2')||(test=='3')||(test=='4')||(test=='5')||(test=='6')||(test=='7')||(test=='8')||(test=='9'))
{
TreeNode<char> newLeaf = (expr[i]);
if (currentNode == nullptr)
{
treeRoot=&newLeaf;
currentNode = &newLeaf;
}
else
currentNode->Right = &newLeaf;
}
else if ((expr[i]=='+')||(expr[i]=='-'))
{
TreeNode<char> newRoot = test;
newRoot.Left = treeRoot;
treeRoot = &newRoot;
currentNode = &newRoot;
}
else if (((expr[i]=='*')||(expr[i]=='/'))&&(currentNode->Right==nullptr))
{
TreeNode<char> newRoot = test;
newRoot.Left = treeRoot;
treeRoot = &newRoot;
currentNode = &newRoot;
}
else if (((expr[i]=='*')||(expr[i]=='/'))&&(currentNode->Right!=nullptr))
{
TreeNode<char> newChild = test;
newChild.Left = currentNode->Right;
currentNode->Right = &newChild;
currentNode = &newChild;
}
}
cout<<ValueOf(treeRoot)<<endl;
system("pause");
}
the problem is that every time i run it, and i input something like 3*4-2, all of the digits in the tree gets overwritten to what the last digit inserted was, so its interpreted as 2*2-2 and gives me 2 as an answer, instead of 10 can anyone tell me what my problem is? thanks =).
btw this program assumes wellformed expressions and single digit numbers.
TreeNode<char> newLeaf = (expr[i]); creates an object on stack - it's invalidated when you leave the enclosing scope. You should not store pointers to such objects.
Use TreeNode<char> * newLeaf = new TreeNode<char>(expr[i]); - and corresponding for any other node that you assign to ->Right and ->Left - aka need to keep alive beyond the scope where you create them.
As mentioned by Erik,
TreeNode<char> newLeaf = (expr[i]);
is a local stack variable; instead of do following:
TreeNode<char> *newLeaf = new TreeNode<char>(expr[i]);
And then assign to proper leg. Also, below condition,
if ((test=='1')||(test=='0')||(test=='2')||(test=='3')||(test=='4')||(test=='5')||(test=='6')||(test=='7')||(test=='8')||(test=='9'))
Can be squeezed to,
if(test >= '0' && test <= '9')
In the same way, you can also co-relate the last two else if() statements for better code