BST only first node can be found - c++

Every node has a data&meaning array, right&left pointer.and, it looks like second node is added (I knew by print count), but when I search for it, there is no result. Also, if I tried to add more nodes.
in main
BST tree;
char sw[10];
char A[ ]={"BST"};
char Am[ ]={"Binary Search Tree"};
tree.maketree(A,Am);
char B[ ]={"COM"};
char Bm[ ]={"commerce"};
tree.maketree(B,Bm);
cout<<"Search: ";
string inputword;
cin>>inputword;
strcpy(sw, inputword.c_str());
tree.BST_Retrieve(sw);
retrieve function: _retrieve return node if found and BST_Retrieve print the meaning
NODE* _retrieve (char key[],NODE*node)
{
if (node)
{
if (strcmp(key,node->data)<0)
return _retrieve (key, node->left);
else if (strcmp(key,node->data)>0)
return _retrieve (key, node->right);
else
return (node);
}
else
return NULL;
}// _retrieve
bool BST_Retrieve (char key[])
{
NODE *node;
if (! root)
return false;
node = _retrieve (key,root);
if (node)
{
printf("%s",node->meaning);
cout<<endl;
node=node->right;
if (node) {
cout<<"\nNext word is: ";
printf("%s",node->data);
}
return true;
}
else
return false;
}
thank you for your time

Your retrieval code looks fine, so I would check your tree building code.
Also, I wouldn't mix printf and cout.
cout << node->meaning << endl;
and
cout << "Next word is: " << node->data << endl;
will do just fine.
Other suggestions:
strcpy(sw, inputword.c_str());
tree.BST_Retrieve(sw);
can be safely shortened to:
tree.BST_Retrieve( inputword.c_str() );
since you're not trying to store the pointer returned by c_str. You will have to change your methods to take const char *key instead of char key[], however.
EDIT: It appears your retrieval code and tree builder code have opposite senses for how left and right should work. Tree builder:
if (strcmp(node->data,newPtr->data)<0)
node->left = addword(node->left,newPtr);
This will recurse left if the node is less than the newPtr. This is opposite of what the tree recursion does:
if (strcmp(key,node->data)<0)
return _retrieve (key, node->left);
You need to flip one to match the other. My preference would be to flip the builder, so that the left pointer is less than the parent, and the parent is less than the right node.

Related

I am trying to Create this function in C++ and I am confused by the wording

Requirements
You must create a function called searchLinkedList that searches a sorted linked list for a word and returns a pointer to the node containing the word (if found) or NULL.
This function must return NULL immediately after you pass the point in the linked list where the word would have been found if it was in the linked list.
The function takes three parameters:
char * searchWord (or you can use a string object): word to search for (entered by the user)
struct linkedList * linkedList: linked list to search (in your program, you can call the linked list node struct anything that makes sense)
int * comparisonCount: pointer to int filled in by the function with the count of strcmp comparisons done in searching the linked lis
Here is what I created.
WordNode* searchLinkedList(string searchedWord, WordNode* searchLinkedList, int* comparisonCount) {
*comparisonCount = 0;
if (searchLinkedList == NULL)
{
cout << "Error list\n";
}
while (searchLinkedList!=NULL) {
if (searchLinkedList->word == searchedWord) {
cout << "SUCCESS\n";
cout << "Word was found:" << *comparisonCount;
break;
}
else {
cout << "NOT there\n";
}
*comparisonCount++;
}
return searchLinkedList;
}
It looks like you understand what the question is asking... iterate through the linked list in search of a specified word searchWord . As you do so, keep track of the amount of comparisons you make comparisonCounter and return the Node that matches. If for example, your linked list was A->B->D->Z and your searchWord was C, you would return NULL on the 3rd iteration, as the list is sorted and it should have been in between B and D.
WordNode* search(std::string searchWord, linkedList* l, int* comparisons) //instructions says a LinkedList is passed, so I assuming it has head variable...
{
WordNode* temp = l->head;
while(temp != NULL)
{
*comparisons = *comparisons + 1;
if(temp->word == searchWord)
{
return temp;
}
else if(temp->word > searchWord) //lexicographical comparison by ASCII values
{
return NULL;
}
temp = temp->next;
}
return NULL;
}

Binary Tree only adding to the the root

I'm writing a simple Binary Tree program in C++ and right now it only stores the most recent value entered at the root node eg. if I enter 10 into the tree then 9 into the tree, 9 just overwrites 10 as the root node so the tree only stores the value 9.
I've looked at multiple C++ Binary Tree solutions online and tried their version of implementing them yet I still get no success.
Here is my struct for a single node in the tree
struct TreeNode{
int value;
TreeNode *left;
TreeNode *right;
TreeNode(int value){
this -> value = value;
left = NULL;
right = NULL;
}
};
My class for the binary tree so far
class IntTree{
private :
TreeNode *root;
public :
IntTree();
TreeNode* getRoot();
void insertValue(TreeNode *root, int intValue);
TreeNode* searchTree(TreeNode *root, int intValue);
void inOrder(TreeNode *root);
void deleteValue(int intValue);
void deleteTree(TreeNode *root);
};
The Insert Method
void IntTree::insertValue(TreeNode *root, int intValue){
if(root == NULL){
root = new TreeNode(intValue);
}
else if(intValue == root->value){
cout << "Value already exists in the tree" << endl;
}
else if(intValue < root->value){
insertValue(root->left, intValue);
}
else{
insertValue(root->right, intValue);
}
}
And then this method is simply called in a menu like this
cout << "Enter Value to Insert : " << endl;
input = readInt();
theTree.insertValue(theTree.getRoot(), input);
The logic all seems fine to me, apart from that I've tried not using a constructor and just induvidually setting the variable, having two functions for inserting one with just the int parameter which so I don't have to use the getRoot() later on and a million other things which I've forgotten
The answer is simple, the pointer you are modifying is only a copy, so the copy is discarded at the end of the function and you have lost memory. You need to take a reference on the pointer to actually modify it (nothing else to modify):
void insertValue(TreeNode *& root, int intValue)
This should work:
New insertvalue function call will look as below
void insertValue(TreeNode **root, int intValue)
{
if(*root == NULL)
{
*root = newNode(intValue);
}
else if(intValue == (*root)->value)
{
cout << "Value already exists in the tree" << endl;
}
else if(intValue < (*root)->value)
{
insertValue(&(*(root))->left, intValue);
}
else
{
insertValue(&(*(root))->right, intValue);
}
}
int main()
{
//initial code
insertvalue(&root,value) //root is a single pointer variable.
//code for printing the tree
}
There are many less complex ways to implement the same. i have just modified your code.

Binary Tree In Order Traversal causing Stack Overflow

Ok so, I have a read method that is reading the values in correctly (all 7000), (hand written 15 values as a tree structure), doesn't create any errors.
However, when it comes to the output of the binary tree I am using the method as stated on several websites.
The error I am getting is a stack overflow, and I am assuming its due to the recursive calls and never breaking out, But I have no idea why this isn't working.
Any help is appreciated, thanks.
Code Listed Below:
// Read
void BinaryTreeStorage::read(ifstream& _fin)
{
// Get first line with number of names in it
string numberOfNamesString;
getline(_fin, numberOfNamesString);
// Loop through all the names
string line;
int num = 0;
while (!_fin.eof())
{
getline(_fin, line);
if (line != "")
{
// Insert Value Here
if (root != NULL)
{
insert(line, root);
}
else
{
insert(line);
}
}
}
}
// Write
void BinaryTreeStorage::write(ofstream& _out) const
{
inorderPrint(_out, root);
}
// inorderPrint
void BinaryTreeStorage::inorderPrint(ofstream& _out, node *_root) const
{
if (_root != NULL)
{
// Inorder
inorderPrint(_out, root->left);
_out << root->nodeValue;
cout << root->nodeValue << " ";
inorderPrint(_out, root->right);
}
}
// Insert if root is null
void BinaryTreeStorage::insert(string _nodeValueIn)
{
if(root!=NULL)
insert(_nodeValueIn, root);
else
{
root=new node;
root->nodeValue=_nodeValueIn;
root->left=NULL;
root->right=NULL;
}
}
// Insert when root is not null
void BinaryTreeStorage::insert(string _nodeValueIn, node *leaf)
{
if(_nodeValueIn< leaf->nodeValue)
{
if(leaf->left!=NULL)
insert(_nodeValueIn, leaf->left);
else
{
leaf->left=new node;
leaf->left->nodeValue=_nodeValueIn;
leaf->left->left=NULL; //Sets the left child of the child node to null
leaf->left->right=NULL; //Sets the right child of the child node to null
}
}
else if(_nodeValueIn>=leaf->nodeValue)
{
if(leaf->right!=NULL)
insert(_nodeValueIn, leaf->right);
else
{
leaf->right=new node;
leaf->right->nodeValue=_nodeValueIn;
leaf->right->left=NULL; //Sets the left child of the child node to null
leaf->right->right=NULL; //Sets the right child of the child node to null
}
}
}
You have a bug in BinaryTreeStorage::inorderPrint,
your param _root is not used where intended: You always loop on root instead.
hint: Avoid using similar names!
hint: Avoid using std to avoid bugs, unless you write std:: too often in nested templates.
hint: Do not use _ at the beginning or end of names.
hint: Do not compare with NULL: Write if(n) instead of if(n!=NULL).
hint: Do not nest blocks when not needed:
void BinaryTreeStorage::inorderPrint(std::ofstream& out, node *n) const
{
if(!n) return;
inorderPrint(out, n->left);
out << n->nodeValue; // no separator??
std::cout << n->nodeValue << " ";
inorderPrint(out, n->right);
}
void BinaryTreeStorage::inorderPrint(ofstream& _out, node *_root) const
{
if (_root != NULL)
{
// Inorder
inorderPrint(_out, root->left);
In the above code, I can see _root defined but you're using root in your call (last line above). I think that is causing the infinite loop.
When you constructed your tree nodes did you ensure that the left and right pointers are initialized to NULL?
The depth of the call tree of inorderPrint is the same as the depth of the tree itself. It looks like you don't try to keep the tree balanced, so the depth can get as large as the size of the tree.
There are a few ways of fixing this. You can make sure that the tree always remains balanced so that the depth grows logarithmically with the size of the tree. Or you can make the tree threaded, which lets you visit the nodes iteratively.

Deleting from Binary Tree error

I wrote a small code to detect the largest number in the binary tree, it is working just fine, its simple, it goes far down to the last right node(leaf in case) and then i just cout<< it, now i would like to delete it, i looked trough some similar question, but i only need to delete the number i got back from the search, but my prog just crashes after i run it list the tree get the number, delete and try to list it again.
Here is my search:
T Remove( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
Here is the full code:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot)
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);
}
void PrintTree(Node* theRoot)
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" \n";
PrintTree(theRoot->rChildptr);
}
}
T Largest( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
T Remove(Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return ;
};
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
T Largest()
{
return Largest(root);
}
//void Remove()
//{
// Remove(root);
//}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(2);
myBT->AddItem(20);
myBT->AddItem(5);
myBT->AddItem(1);
myBT->AddItem(10);
myBT->AddItem(15);
//for(int i = 0; i < 10; i++) //randommal tolti fel
//myBT->AddItem(rand() % 100);
cout << "BinaryTree:" << endl; //kilistazaa a fat
myBT->PrintTree();
cout << "Largest element: " << myBT->Largest() << endl; //visszaadja a legnagyobb elemet
//myBT->Remove();
myBT->PrintTree();
}
the actual delete function is in // comments so i can run the prog.
You are deleting theRoot and then trying to dereference it. If you want to return the value stored in the node you need to make a local copy first like this:
T value = theRoot->data;
delete theRoot;
return value;
Is the return thetRoot->data; line intended to be part of the else statement? If so you need to add brackets around it like this:
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
else
{
T value = theRoot->data;
delete theRoot;
return value;
}
Or simply remove the else case altogether (since you always return if the child pointer is null):
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
T value = theRoot->data;
delete theRoot;
return value;
You will also need to make sure that the parent node does not still point to a deleted child (hard to see exactly what is going on because you haven't posted much code).
You cannot simply delete the object you don't want -- you must also remove the reference you used to find the node that you are deleting. And, if the node has any children, you must reattach the child nodes elsewhere to the tree so that they remain reachable.
The thing that makes it so tricky is that you have to properly update: the parent's reference to the node being deleted; one of the 'child' pointers for one of the children of the deleted node; and the parent links from both children of the deleted node. If you perform the updates out-of-order, you'll read a stale pointer and perhaps corrupt memory, so you must wait to remove nodes until you do not need any more references from within the node and you've removed references to the node from elsewhere.
Update
Don't forget that "the last right node" can in fact be the root of your tree:
5
4
3
2
1
5 is the largest, right-most, node of your tree, and if you delete it, you've lost your entire tree.
Unless you're doing some re-balancing that we're not seeing here; if you are, be sure you also handle this case:
2
1
Our friends at Wikipedia have been very kind to analyze how to delete a node from a binary search tree:
Deleting a leaf (node with no children): Deleting a leaf is easy, as we can simply remove it from the tree.
Deleting a node with one child: Remove the node and replace it with its child.
Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node
or its in-order predecessor node, R. Replace the value of N with the
value of R, then delete R.
Your delete code must handle all three of these cases. Don't forget that the node you're deleting might be the root of the tree and not have a parent node.
Can you post the entire program so that it can be compiled. But basically the problem is that when theRoot->rChildptr is NULL you are deleting theRoot and then your return statement tries to return theRoot->data which is pointing to nowhere.

c++ pass by reference?

/*
This program demonstrates a few routines for processing binary
sort trees. It uses a binary sort tree of strings. The user
types in strings. The user's string is converted to lower case, and --
if it is not already in the tree -- it is inserted into the tree.
Then the number of nodes in the tree and a list of items in the tree
are output. The program ends when the user enters an empty string.
*/
#include <iostream>
#include <string>
using namespace std;
class TreeNode {
// An object of type TreeNode represents one node
// in a binary tree of strings.
public:
// Constructor. Make a node containing str.
TreeNode(string str) : item(str), left(NULL), right(NULL) {}
string item; // The data in this node.
TreeNode *left; // Pointer to left subtree.
TreeNode *right; // Pointer to right subtree.
};
typedef TreeNode* TreeNodePtr;
void treeInsert(TreeNodePtr& root, string newItem);
// Add the item to the binary sort tree to which the parameter
// "root" refers. Note that root is passed by reference since
// its value can change in the case where the tree is empty.
bool treeContains( TreeNodePtr root, string item );
// Return true if item is one of the items in the binary
// sort tree to which root points. Return false if not.
void treeList(TreeNodePtr node);
// Print the items in the tree in postorder, one item
// to a line. Since the tree is a sort tree, the output
// will be in increasing order.
int countNodes(TreeNodePtr node);
// Count the nodes in the binary tree to which node
// points. Return the answer.
int main() {
TreeNodePtr root;// Pointer to the root node in a binary tree. This
// tree is used in this program as a binary sort tree.
// The tree is not allowed to contain duplicate
// items. When the tree is empty, root is null.
root = NULL; // Start with an empty tree.
cout << "This programs stores strings that you enter in a binary sort\n";
cout << "tree. After each items is inserted, the contents of the tree\n";
cout << "are displayed. The number of nodes in the tree is also output.\n";
cout << " Any string you enter will be converted to lower case.\n";
cout << "Duplicate entries are ignored.\n";
while (true) {
// Get one string from the user, insert it into the tree,
// and print some information about the tree. Exit if the
// user enters an empty string. Note that all strings are
// converted to lower case.
cout << ("\n\nEnter a string to be inserted, or press return to end.\n");
string item; // The user's input.
if (cin.peek() == '\n')
break;
cin >> item;
cin.ignore(10000,'\n'); // just in case a space and other words typed
if (treeContains(root,item)) {
// Don't insert a second copy of an item that is already
// in the tree.
cout << "\nThat item is already in the tree.\n";
}
else {
treeInsert(root,item); // Add user's string to the tree.
cout << "\nThe tree contains " << countNodes(root) << " items.\n";
cout << "\nContents of tree:\n\n";
treeList(root);
}
} // end while
cout << "\n\nExiting program.\n\n";
} // end main()
void treeInsert(TreeNodePtr& root, string newItem) {
// Add the item to the binary sort tree to which the parameter
// "root" refers. Note that root is passed by reference since
// its value can change in the case where the tree is empty.
if ( root == NULL ) {
// The tree is empty. Set root to point to a new node containing
// the new item. This becomes the only node in the tree.
root = new TreeNode( newItem );
return;
}
else if ( newItem < root->item ) {
treeInsert( root->left, newItem );
}
else {
treeInsert( root->right, newItem );
}
} // end treeInsert()
bool treeContains( TreeNodePtr root, string item ) {
// Return true if item is one of the items in the binary
// sort tree to which root points. Return false if not.
if ( root == NULL ) {
// Tree is empty, so it certainly doesn't contain item.
return false;
}
else if ( item == root->item ) {
// Yes, the item has been found in the root node.
return true;
}
else if ( item < root->item ) {
// If the item occurs, it must be in the left subtree.
return treeContains( root->left, item );
}
else {
// If the item occurs, it must be in the right subtree.
return treeContains( root->right, item );
}
} // end treeContains()
void treeList(TreeNodePtr node) {
// Print the items in the tree in inorder, one item
// to a line. Since the tree is a sort tree, the output
// will be in increasing order.
if ( node != NULL ) {
treeList(node->left); // Print items in left subtree.
cout << " " << node->item << endl; // Print item in the node.
treeList(node->right); // Print items in the right subtree.
}
} // end treeList()
int countNodes(TreeNodePtr node) {
// Count the nodes in the binary tree to which node
// points. Return the answer.
if ( node == NULL ) {
// Tree is empty, so it contains no nodes.
return 0;
}
else {
// Add up the root node and the nodes in its two subtrees.
int leftCount = countNodes( node->left );
int rightCount = countNodes( node->right );
return 1 + leftCount + rightCount;
}
} // end countNodes()
One thing not understand, why this function " void treeInsert(TreeNodePtr& root, string newItem);" has "&" mark after TreeNodePtr? others not...confused!
Thank you for anyone's help!
The root pointer is passed by reference since its value can change in the case where the tree is empty.
Cheers & hth.,
All the std::strings should also be passed by const reference. This way the whole class is not placed on the stack.