/*
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.
Related
I want to make a binary tree in c++ that perform insert operation the inserted values are 4 on a node that is
name, type , order, and color
The use will enter these 4 as INSERT corn oil 3 yellow. It create a new node with name as corn and 3 child node as type ,order and color.
If again user enter same thing but change any other except name that exists like
INSERT corn oil 4 red as corn name exist this will update node
preorder and postorder traversal with remove and find any node
Here is how i am going ?
struct TreeNode {
string itemname; // The data in this node.
TreeNode *left; // Pointer to the left subtree.
TreeNode *right; // Pointer to the right subtree.
};
1- Name node will have 2 values left right where 4th will be place
2- The hierarchy of tree is like root have only names that have 2 left right node so root have many nodes with names that have only 2 further node but no more node will be added to child node of names is it really a tree
Since you are using binary tree, I am not sure you can use string as a key for TreeNode (well I have always used intigers). So what I suggest is that you have structure like this:
// I am not sure about types, but I assumed them by name
struct Element {
char* name;
int type;
int order;
char* color;
};
struct TreeNode {
int key;
Element *element;
TreeNode *left, *right;
};
Then you would somehow calculate hash of Element::name to get a numeric value, which a is key. Now you would just traverse tree from root to the left or right depending on key. You would check on each node if key you are inserting is same as one in current node and if answer is yes, then you would swap values in that node, otherwise continue traversing the tree to the left or right. If you get to the bottom it means you haven't find a node with that key, so you create a new one and attach it as a leaf.
You can look this link to generate hash. However, keep in mind that for some string you can get same hash value, so you may need to keep more than one element at the current tree node.
UPDATE
Here is the code, however you can optimize it more by using pointers. But as mentioned in comments, if you are not strictly bound to use binary tree, you should use HashTable or std::map.
std::map<std::string, struct Element*> elements
and for retrieving element:
Element *e = elements["corn"]
Binary Tree implementation:
#include <iostream>
#include <vector>
#define A 54059 /* a prime */
#define B 76963 /* another prime */
#define C 86969 /* yet another prime */
#define FIRSTH 37 /* also prime */
struct Element {
std::string name;
std::string type;
int order;
std::string color;
};
struct TreeNode {
int key;
std::vector<Element> values;
struct TreeNode *left;
struct TreeNode *right;
};
/**
* see: https://stackoverflow.com/questions/8317508/hash-function-for-a-string
*/
int calculateHash(const char *s)
{
int h = FIRSTH;
while (*s) {
h = (h * A) ^ (s[0] * B);
s++;
}
return h; // or return h % C;
}
void printElement(Element element)
{
std::cout
<< element.name
<< " "
<< element.type
<< " "
<< element.order
<< " "
<< element.color
<< std::endl;
}
void preOrder(TreeNode* node)
{
if( node == NULL )
return;
for(size_t i=0; i<node->values.size(); i++) {
printElement(node->values[i]);
}
preOrder(node->left);
preOrder(node->right);
}
void insert(TreeNode** root, Element element, int key)
{
if( *root == NULL ) {
TreeNode* node = new TreeNode();
node->key = key;
node->values.push_back(element);
*root = node;
return;
};
if( key == (*root)->key ) {
for(size_t i=0; i<(*root)->values.size(); i++) {
if( (*root)->values[i].name == element.name ) {
(*root)->values[i].type = element.type;
(*root)->values[i].order = element.order;
(*root)->values[i].color = element.color;
break;
}
}
}
else if( key < (*root)->key ) {
insert( &((*root)->left), element, key );
}
else {
insert( &((*root)->right), element, key );
}
}
int main()
{
TreeNode *node = NULL;
insert(&node, {"corn1", "oil", 3, "yellow"}, calculateHash("corn1"));
insert(&node, {"corn2", "oil", 3, "yellow"}, calculateHash("corn2"));
insert(&node, {"corn3", "oil", 3, "yellow"}, calculateHash("corn3"));
insert(&node, {"corn2", "aaa", 32, "blue"}, calculateHash("corn2"));
preOrder(node);
return 0;
}
Hi!
I would like to know what can be the if statement's condition so all left branches of a binary tree could be printed using postorder traverse.
template <class dataType>
void PrintLeft (BinaryTree <dataType> * bt) {
if (!(bt == NULL))
{
//traverse left child
PrintLeft (bt->left());
//traverse right child
PrintLeft (bt->right());
//visit tree
if(/*no idea what goes here*/)
cout << bt->getData() <<"\t";
}
}
I understand that you want to visit only the nodes that were seen from a left branch. Since it is postorder, you must visit them when you get back on the right branch. So, such as said by πάντα ῥεῖ, you can use a boolean flag indicating from which type of branch you have discovered the node.
So a possible way would be as follows:
using Node = BinaryTree <int>; // or another type supporting << operator
void printLeft(Node * root, bool from_left)
{
if (root == nullptr) // empty tree?
return;
printLeft(root->left, true); // this node must be visited in postorder
printLeft(root->right, false); // this one must not be visited in postorder
if (from_left) // was root seen from a left arc?
cout << root->getData() << "\t"; // visit only if was seen from a left branch
}
There is an ambiguity with the root. I assume that it must not be printed because it is not reached from a left branch (nor right too).
So the first call should be:
printLeft(root, false);
Just as verification, for this tree:
The algorithm produces as left postorder traversal the following sequence
0 1 4 3 8 9 12 11 16 18
here goes code for postorder traversing
void postorder(BinaryTree *bt)
{
if(bt!=NULL)
{
postorder(t->lp);
postorder(t->rp);
//No Code Goes Here
cout<<bt->data<<"\t";
}
}
Try This One
void leftViewUtil(struct node *root, int level, int *max_level)
{
// Base Case
if (root==NULL) return;
// If this is the first node of its level
if (*max_level < level)
{
printf("%d\t", root->data);
*max_level = level;
}
// Recur for left and right subtrees
leftViewUtil(root->left, level+1, max_level);
leftViewUtil(root->right, level+1, max_level);
}
// A wrapper over leftViewUtil()
void leftView(struct node *root)
{
int max_level = 0;
leftViewUtil(root, 1, &max_level);
}
// Driver Program to test above functions
int main()
{
struct node *root = newNode(12);
root->left = newNode(10);
root->right = newNode(30);
root->right->left = newNode(25);
root->right->right = newNode(40);
leftView(root);
return 0;
}
if(!bt->left()==NULL)
cout << bt->left()->getData() << "\t";
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.
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.
I'm working on a project where I have to make a binary search tree that stores strings and takes account of doubles. While i've already tackled the specifics, I can't for the life of me get this damn insert function to work. It seems to only store the root node, leaving it's "children" NULL even though it does actually seem to assign the left and right pointers to new nodes. However when I attempt to output it, only the main parent (root) node exists. I guess the changes do not get saved for whatever reason.
Here's the header file:
#ifndef BST_H
#define BST_H
#include <string>
#include <vector>
#include <iostream>
using namespace std;
typedef string ItemType;
class Node
{
public:
Node(); // constructor
ItemType data; // contains item
Node* left; // points to left child
Node* right;// points to right child
int dataCount; // keeps track of repeats
vector<int> lineNumber; // keeps track of line numbers
};
class Tree
{
public:
Tree(); // constructor
// ~Tree(); // destructor. not working.
bool isEmpty(); // tests for empty tree
Node* find(Node* root, ItemType item); // finds an item
void insert(Node* root, ItemType item, int lineN, Tree tree); // inserts an item
void outputTree(Node* root); // lists all items in tree
void treeStats(Tree tree); // outputs tree stats
void clearTree(); // erases the tree (restart)
Node* getRoot(); // returns the root
void setRoot(Node*& root);
// void getHeight(Tree *root); // gets height of tree
private:
Node* root; // root of tree
int nodeCount; // number of nodes
};
#endif
cpp:
#include "BST.h"
bool setRootQ = true;
/** Node constructor- creates a node, sets children
* to NULL and ups the count. */
Node::Node()
{
left = right = NULL;
dataCount = 1;
}
/** Tree constructor- creates instance of tree
* and sets parameters to NULL */
Tree::Tree()
{
root = NULL;
nodeCount = 0;
}
/** Destructor- deallocates tree/node data;
* avoids heap leaks. SOMETHING WRONG. CAUSES SEGFAULT
Tree::~Tree()
{
if(this->root->left) // if a left child is present
{
delete this->root->left; //recursive call to destructor ("~Tree(->left)")
this->root->left = NULL;
}
if(this->root->right) // if a right child is present
{
delete this->root->right; //recursive call to destructor
this->root->right = NULL;
}
} */
/** Returns true if tree is empty.
* Otherwise returns false (DUH). */
bool Tree::isEmpty()
{
return root == NULL;
}
/** Searches tree for item; returns the node if found
* #param root- tree node.
* item- data to look for. */
Node* Tree::find(Node* root, ItemType item)
{
if(root == NULL) // if empty node
{
return NULL;
}
else if(item == root->data) // if found
{
return root;
}
else if(item < root->data) // if item is less than node
{
find(root->left, item);
}
else if(item > root->data) // if item is more than node
{
find(root->right, item);
}
return NULL;
}
/** Adds a new node to the tree. If duplicate, increases count.
* #param item- data to insert.
* root- tree node/ */
void Tree::insert(Node* root, ItemType item, int lineN, Tree tree)
{
Node* temp = find(tree.getRoot(), item);
if(temp != NULL) // if item already exists
{
temp->dataCount += 1;
temp->lineNumber.push_back(lineN);
return;
}
if(root == NULL) // if there is an empty space
{
root = new Node; // insert new node
root->data = item; // w/ data value
root->lineNumber.push_back(lineN);
nodeCount++;
if(setRootQ)
{
setRoot(root);
setRootQ = false;
}
return;
}
if(item < root->data)
{
insert(root->left, item, lineN, tree);
}
if(item > root->data)
{
insert(root->right, item, lineN, tree);
}
}
/** Outputs tree to console in inorder.
* #param root- tree root. */
void Tree::outputTree(Node* root)
{
if(isEmpty()) // if empty tree
{
cout << "Error: No items in tree" << endl; // error message
}
else
{
if(root->left != NULL)
{
outputTree(root->left);
}
cout << "- " << root->data << " (" << root->dataCount << ") line#s: ";
for(unsigned int i = 0; i < root->lineNumber.size(); i++)
{
cout << root->lineNumber[i] << ", ";
}
cout << endl;
if(root->right != NULL)
{
outputTree(root->right);
}
}
}
/** Displays tree stats including number of nodes,
* tree height, and more frequent item.
* #param tree- tree instance. */
void Tree::treeStats(Tree tree)
{
cout << "Number of entries: " << nodeCount << endl;
// unfinished
}
/** Clears tree.
void Tree::clearTree()
{
this->~Tree();
} */
/** Returns the root of the tree. */
Node* Tree::getRoot()
{
return root;
}
void Tree::setRoot(Node*& rootS)
{
root = rootS;
}
I realize my destructor isn't working but I'll tackle that myself later. I've been pulling my hair out over this trying to figure out what I'm missing, but to no avail. If anyone can give me any help and point me in the direction towards a solution I would greatly appreciate it.
i think it might have something to do with
void Tree::insert(Node* root, ItemType item, int lineN, Tree tree)
and instead should be something like
void Tree::insert(Node* &root, ItemType item, int lineN, Tree tree)
but when i try i get a "no matching function" error. :/
The solution you suggest yourself (with insert() taking Node *& root) will work. You have to make a corresponding change to the .h file, AND also change getRoot() to return Node *& in both .h and .cc files.
This will work. But your code has other problems. For example, setRoot and setRootQ don't do anything useful, as far as I can tell. The fourth argument to insert() only confuses things and does nothing to detect duplicates. It should be removed. To detect a duplicate simply do if (item == root->data) just before you do if (item < root->data) in the insert() method (i.e. it'll be even more similar to find()).
Also, if anyone besides you will ever use your code, you shouldn't require passing in getRoot() to methods like find() and insert(). Instead, create private helper methods, like find_helper(Node*, Item) and insert_helper(Node*&,Item), and have the public methods call them with the root node as the first argument. E.g.:
Node *find(Item item) { return find_helper(root, item); }
This would also make the weird return type of getRoot() unnecessary, and you could change it back to returning the plain Node*, or get rid of that accessor altogether.
Seems like there is a lot of pointer comparison occurring but the pointer member variables are not being initialized. Ensure that the pointer member variables are initialized properly so that they evaluate properly in if statements.
Change from:
class Node
{
public:
Node(); // constructor
...
};
to
class Node
{
public:
Node() : left(0), right(0) {}
...
};