C++ Binary Search Tree printing and depth calc - c++

I have created binary search tree. My functions can add, delete, and find nodes with numbers. All of that functions is working fine.
Can You help me with two functions:
1) Printing BST
2) Calculating depth of BST?
I have no idea how to do this in a quick and easy way. Depth i calculating during adding new Nodes but I want to have function only for doing that.
class Node{
public:
shared_ptr<Node> right;
shared_ptr<Node> left;
int number;
Node(int number)
{
this->number=number;
right=nullptr;
left=nullptr;
}
~Node()
{
cout<<"Deleted"<<" "<<number<<endl;
}
};
class BT
{
public:
shared_ptr<Node> root;
int deep;
BT(int num)
{
deep=0;
root=make_shared<Node>(num);
}
void add_number(int num)
{
shared_ptr<Node> new_num=make_shared<Node>(num);
shared_ptr<Node> tmp=root;
int tmp_deep=0;
while(tmp!=nullptr)
{
tmp_deep++;
if(tmp->number>num)
{
if (tmp->left==nullptr)
{
tmp->left=new_num;
break;
}
else
tmp=tmp->left;
}
else if (tmp->number<num)
{
if (tmp->right==nullptr)
{
tmp->right=new_num;
break;
}
else
tmp=tmp->right;
}
}
tmp.reset();
if (tmp_deep>deep)
deep=tmp_deep;
}
shared_ptr<Node> find_node(int num)
{
shared_ptr<Node> tmp=root;
while (tmp!=nullptr && tmp->number!=num)
{
if (tmp->number>num)
tmp=tmp->left;
else if (tmp->number<num)
tmp=tmp->right;
}
if (tmp==nullptr)
{
cout<<"Not found";
return nullptr;
}
else
return tmp;
}
void delete_ (int num)
{
shared_ptr<Node> tmp=root;
shared_ptr<Node> previous=root;
while (tmp!=nullptr && tmp->number!=num)
{
if (tmp->number>num)
{
previous=tmp;
tmp=tmp->left;
}
else if (tmp->number<num)
{
previous=tmp;
tmp=tmp->right;
}
}
if (tmp==nullptr)
{
cout<<"Not found";
}
else
{
if(tmp->left==nullptr && tmp->right==nullptr)
{
if (previous->number>tmp->number)
previous->left=nullptr;
else
previous->right=nullptr;
tmp.reset();
}
else if (tmp->left==nullptr && tmp->right!=nullptr)
{
if(tmp->right!=nullptr)
{
previous->right=tmp->right;
}
else
previous->right=tmp->left;
tmp.reset();
}
else if (tmp->left!=nullptr && tmp->right==nullptr)
{
if(tmp->right!=nullptr)
{
previous->left=tmp->right;
}
else
previous->left=tmp->left;
tmp.reset();
}
else if (tmp->left!=nullptr && tmp->right!=nullptr)
{
shared_ptr<Node> tmp_left=tmp->right;
shared_ptr<Node> prev_left=tmp->right;
while (tmp_left->left!=nullptr)
{
//prev_left=tmp_left;
tmp_left=tmp_left->left;
}
if (tmp->number<previous->number)
previous->left=tmp_left;
else
previous->right=tmp_left;
prev_left->left=tmp_left->right;
tmp_left->left=tmp->left;
tmp_left->right=tmp->right;
tmp.reset();
}
}
void show_bt()
{
}
void calc_depth()
{
}
}
};

Both of calculating depth and printing can done using tree traversal. Moreover, tree traversal has O(n) time complexity(n is number of nodes in the tree).
PS: For calculating tree depth you can use one of three traversal methods.
In each recursion call increase the depth variable
After that decrease it and
Save total maximum value(before decreasing it)

This exercise is something every programmer has to do, to learn recursion.
This can also be done by iteration, but that requires to build your stack
For recursion, a function has to be created, which calls itself in order to "calculate" a result.
You have to think, how the end result can be "calculated" from smaller results.
Let's look at the depth calculation.
This is on a tree. Which is constructed from nodes.
So how can we calculate something on the nodes to get the end result?
Every node has a height which is 1 greater than the maximum of height of (the left subtree and, right subtree). If there is no subtree we'll just say it has a height of zero.
BTW: never look for the quick and easy in the beginning. Always the first step is: make it work.

Related

Function to check whether a binary tree is binary search tree or not working

Can someone tell me why is this not working?
This seems correct to me
please someone look into this.
I am not able to find my mistake.
bool checkbst(node* root,int minValue,int maxValue)
{
if(root==NULL)
{
return true;
}
else if(((root->data)>(minValue))&&
((root->data)>(maxValue))&&
(checkbst(root->left,minValue,root->data))&&
(checkbst(root->right,root->data,maxValue)))
{
return true;
}
else
{
return false;
}
}
void isbst(node* root)
{
if( checkbst(root,INT_MIN,INT_MAX))
{
cout<<"the tree is bst";
}
}
You have a typo in checkbst, you are checking
((root->data)>(minValue))&&((root->data)>(maxValue))
while it probably should be
((root->data)>(minValue))&&((root->data)<(maxValue))
(notice the "less than" sign).
Your code verifies that the keys are inside a range, but it does not verify if the children satisfy the bst condition respect to the root. That is, the keys in the left subtree must be lesser than the root and the keys in the right one greater. You should check if the children are not null before doing any comparison involving subtrees.
This version should work:
bool checkbst(node* root, int minValue,int maxValue)
{
if (root == nullptr)
return true;
if (not (root->data >= minValue && root->data <= maxvalue))
return false;
if (root->left)
{
if (root->data < root->left->data)
if (not checkbst(root->left, minValue, maxValue))
return false;
else
return false;
}
// here the left subtree has been checked
if (root->right)
{
if (root->data < root->right->data)
return checkbst(root->right, minValue, maxValue);
else
return false;
}
return true; // everything is ok
}
I have checked your there is a small mistake code but there is a better way to do it. You just have to do the in order traversal of the given tree and store it in a array and then check if the elements in the array are sorted. If the elements are sorted then its a binary search tree else it will be a binary tree (which is a kind of basic difference between a binary tree and binary search tree).
There is a small mistake in your code
((root->data)>(maxValue))
should be
((root->data)<(maxValue))
Here is a solution that is O(n) time complexity and O(1) space. It uses in-order tree traversal to confirm that the tree is sorted according to BST rules, but it does not rely on maintaining an auxiliary array of in-order traversed Nodes. However, because it does rely on recursion it's usage of the stack (i.e. stack depth) can reach O(logn).
struct Node
{
int data;
struct Node* left;
struct Node* right;
};
bool isBSTHelper(Node* root, int& min, int& max)
{
if (nullptr == root)
{
max = numeric_limits<int>::min(); // has meaning for LHS traversal.
min = numeric_limits<int>::max(); // has meaning for RHS traversal.
return true;
}
int lhsMax;
int lhsMin;
if (!isBSTHelper(root->left, lhsMin, lhsMax) ||
lhsMax >= root->data)
{
return false;
}
int rhsMax;
int rhsMin;
if (!isBSTHelper(root->right, rhsMin, rhsMax) ||
rhsMin <= root->data)
{
return false;
}
min = std::min(lhsMin, root->data);
max = std::max(rhsMax, root->data);
return true;
}
bool isBST(Node* root)
{
int min;
int max;
return isBSTHelper(root, min, max);
}

BST method returns Segfault

I am writing a method to check if a given tree is a BST using the inorder traversal method. On executing this method, I get a segfault. Can someone help me correct it?
here, maximum stores the largest value in the BST, and k is initialized to 0. The BST is assumed to have unique positive values. isNull(root) checks if the current node is a null node or not.
bool check(BstNode* root)
{
if (root->data==maximum) return true;
isNull(root);
check(root->left);
if (root->data>k)
{
k=root->data;
}
else
{
return false;
}
check(root->right);
}
Every time when you call check(root->left) and check(root->right), I suppose you need to add sth to determine the left and the right branch is null or not. In your code, you just assume that there is sth in left and right branch and call the check function. I think that's the main reason.
You shouldn't need to specify the maximum value. An elegant solution can be found here
There are two approaches you can do this.
One is top-down approach, first check if current node is valid, if so, then check two subtree. This is very intuitive. you can find the code from #lerman's post:
struct TreeNode {
int data;
TreeNode *left;
TreeNode *right;
};
bool isBST(TreeNode *node, int minData, int maxData) {
if(node == NULL) return true;
if(node->data < minData || node->data > maxData) return false;
return isBST(node->left, minData, node->data) && isBST(node->right, node->data, maxData);
}
if(isBST(root, INT_MIN, INT_MAX)) {
puts("This is a BST.");
} else {
puts("This is NOT a BST!");
}
The other way is a bottom-up approach: first check left substree then right substree and check current tree at last. below is the code for this approach.
bool isValidBST(TreeNode *root) {
int mmin, mmax;
return helper(root, mmin, mmax);
}
bool helper(TreeNode* root, int& mmin, int& mmax) {
if(!root) {
mmin = INT_MAX;
mmax = INT_MIN;
return true;
}
int leftmin, leftmax, rightmin, rightmax;
if(!helper(root->left, leftmin, leftmax))
return false;
if(!helper(root->right, rightmin, rightmax))
return false;
if(root->val > leftmax && root->val < rightmin) {
mmin = min(min(leftmin, rightmin), root->val);
mmax = max(max(leftmax, rightmax), root->val);
return true;
}
else
return false;
}
You might notice that the first approach is pre-order traversal and the second approach is post-order traversal. inorder traversal in inappropriate here because it conflicts with the definition of BST.

search in a binary tree

I have written the following function to search for a value in a binary tree storing integer values (the function is part of a larger program):
bool tree::search(int num) //the function belongs to class 'tree'
{
node *temp=head; //'head' is pointer to root node
while(temp!=NULL)
{
if(temp->data==num)
break;
if(num>temp->data)
temp=temp->right;
if(num<temp->data)
temp=temp->left;
}
if(temp==NULL)
return false;
else if(temp->data==num)
return true;
}
The problem is: when I search for a value present in the tree, it runs fine. But if I search for a value not present in the tree, the program just hangs, and I have to close it.
One more thing - I know we can implement the search function recursively by passing node *temp as an argument, instead of declaring it inside, and I have done so which caused the program to run correctly, but I want to know what is the problem in the above code.
I am giving the full program here, just in case it makes fault- finding easier( please note that I have written only two functions yet):
#include<iostream>
using namespace std;
struct node
{
int data;
node *left;
node *right;
};
class tree
{
public:
node *head; //pointer to root
int count; //stores number of elements in tree
tree();
void addnode(int);
void deletenode(int);
bool search(int);
int minimum();
int maximum();
void inorder();
void preorder();
void postorder();
void printtree();
int mthlargest(); //finds 'm'th largest element
int mthsmallest(); //finds 'm'th smallest element
void convert(); //converts binary tree to linked list
};
tree::tree()
{
head=NULL;
count =0;
}
void tree::addnode(int num)
{
node *temp= new node;
temp->data=num;
temp->left=NULL;
temp->right=NULL;
node **ptr=&head; //double pointer
while(*ptr!=NULL)
{
if(num>(*ptr)->data)
ptr=&((*ptr)->right);
if(num<(*ptr)->data)
ptr=&((*ptr)->left);
}
*ptr=temp;
}
bool tree::search(int num)
{
node *temp=head;
while(temp!=NULL)
{
if(temp->data==num)
break;
if(num>temp->data)
temp=temp->right;
if(num<temp->data)
temp=temp->left;
}
if(temp==NULL)
return false;
else if(temp->data==num)
return true;
}
int main()
{
tree ob;
ob.addnode(2);
ob.search(2);
ob.search(3);
ob.search(-1);
ob.search(2);
cout<<endl<<endl;
system("pause");
return 0;
}
Side note : I am using Dev C++ compiler and Windows 7 OS.
Put an else and your problem will disappear.
Because after temp = temp->right; you must check temp again but in your original code you immediately test temp->data which may not be a valid pointer.
bool tree::search(int num)
{
node *temp = head;
while (temp != NULL)
{
if (temp->data == num)
break;
if (num > temp->data)
temp = temp->right;
else // <--- Put this 'else' here
if (num < temp->data)
temp = temp->left;
}
if (temp == NULL)
return false;
if (temp->data == num)
return true;
return false;
}
std::set
Use a std::set; it is basically STL's binary tree. If you want to search for something, you would use count, find or lower_bound.
Implementing basic data structures are good exercises, but in production, try to use STL first, as they are implemented by professionals with specific knowledge of the compiler/platform in question. Boost is another great set of data structures and common idioms.

Trouble in traversing BST

I started learning about trees and tried writing the code for BST. Unfortunately i am having trouble displaying the tree datas. I am trying to implement Depth-first traversal. But have no idea how to implement it. Below is my code
#include<iostream>
using namespace std;
class node
{
public:
int data;
node *left,*right;
};
class btree
{
private:
node *root;
public:
btree(){root=NULL;}
void insert(int value)
{node *temp=new node;
if(root == NULL)
{
temp->right=NULL;
temp->data=value;
temp->left=NULL;
root=temp;
}
else
insertHelper(root, value);
}
void insertHelper(node* Node, int value)
{
if(value < Node->data)
{
if(Node->left == NULL)
{
Node->left=new node;
Node->left->data=value;
Node->left->left=NULL;
Node->left->right=NULL;
}
else
insertHelper(Node->left, value);
}
else
{
if(Node->right== NULL)
{
Node->right = new node;
Node->right->data=value;
Node->right->left=NULL;
Node->right->right=NULL;
}
else
insertHelper(Node->right, value);
}
}
void disp()
{node*tmp=root;
if(tmp==NULL)
cout<<"empty"<<endl;
else
{
cout<<tmp->data<<endl;
disphelper(tmp);
}
}
void disphelper(node *tmp)
{
if(tmp->left!=NULL)
{
cout<<tmp->left->data<<endl;
tmp=tmp->left;
disphelper(tmp);}
if(tmp->right!=NULL)
{
cout<<tmp->right->data<<endl;
tmp=tmp->right;
disphelper(tmp);
}
}
};
int main()
{
btree binarytree;
binarytree.disp();
binarytree.insert(10);
binarytree.insert(5);
binarytree.insert(30);
binarytree.disp();
}
the output is
empty
10
5
Can anyone please tell me why 30 is not displayed?
MODIFY your code to
void disphelper(node *tmp)
{
if(tmp == NULL)
return;
cout<<tmp->data<<endl; // print data for current node
if(tmp->left!=NULL) // traverse left branch
{
//cout<<tmp->left->data<<endl;
//tmp=tmp->left;
disphelper(tmp->left);}
if(tmp->right!=NULL) // traverse right branch
{
//cout<<tmp->right->data<<endl;
//tmp=tmp->right;
disphelper(tmp->right);
}
}
And it should work.
void disp()
{node*tmp=root;
if(tmp==NULL)
cout<<"empty"<<endl;
else
{
disphelper(tmp);
}
}
The reason you're not getting any output here is that in disphelper() you are first checking whether the left node is NULL and then changing it when you recurse into it. Same when you recurse into the right node.
void disphelper(node *tmp)
{
if(tmp->left!=NULL)
{
cout<<tmp->left->data<<endl;
//tmp=tmp->left; // Get rid of this.
disphelper(tmp->left); // Use this.
}
if(tmp->right!=NULL)
{
cout<<tmp->right->data<<endl;
//tmp=tmp->right; // Get rid of this
disphelper(tmp->right); // Use this.
}
}
Instead of changing the value of temp, which should be the same for both comparisons, just pass the left or right node in.
Two other things. Firstly, you're leaking memory like mad here: In your insert(), you create a new object every time, but only use it the first time, every other time it leaks. Your node class should be taking care of memory by having a destructor which deletes both nodes.
Secondly, before you post code, could you please take the trouble to format it so that the indentation is consistent? It's not the pain it use to be to do this - a lot of editors will do it for you or you can use the excellent Astyle. I know it's a small point but it's irritating for those who read your code - including, presumably the guy who's going to mark you homework! Thanks :-)

simple binary search tree. Segmentation Fault

Just a simple BST to print numbers inorder. Couldn't figure out what I did wrong.
#include <iostream>
using namespace std;
class bst {
private:
bst* root;
bst* left;
bst* right;
int value;
public:
bst(const int& numb) : root(NULL), left(NULL), right(NULL) {
value = numb;
}
void insert(const int& numb) {
if (numb < value) {
if (left == NULL) {
left = new bst(numb);
left->root = left;
} else {
left->insert(numb);
}
} else if (numb > value) {
if (right == NULL) {
right = new bst(numb);
right->root = right;
} else {
left->insert(numb);
}
} else if (numb == value) {
cout << "duplicated value" << endl;
}
}
void inorder() {
if (left == NULL) cout << value << endl;
else left->inorder();
right->inorder();
}
};
int main() {
bst tree(5);
tree.insert(7);
tree.insert(1);
tree.insert(3);
tree.insert(2);
tree.insert(9);
tree.insert(10);
return 0;
}
Line 29 should read:
right->insert(numb);
where it currently reads:
left->insert(numb);
I highly recommend looking into gdb for solving situations like this.
inorder() should be:
if (left != NULL) left->inorder();
cout << value << endl;
if (right != NULL) right->inorder();
I assume the rest are correct.
Logic errors throughout.
Crash is here:
if (right == NULL) {
right = new bst(numb);
right->root = right;
} else {
left->insert(numb);
}
The else case shold use right, not left.
At least as I see it, your fundamental design is flawed. Although I realize many text books (and such) describe a tree as a recursive structure where each node has two sub-trees, I've never found that a very good way to design the code.
At least in my experience, in actual code, you're (much) better off separating the notion of a node in the tree from the notion of an entire tree. Only the tree should be visible to the outside world; node should be hidden away inside the tree, invisible to the outside world.
class bst {
class node {
int value;
node *left;
node *right;
// ...
};
// ...
node *root;
};
I'd then split insert into two pieces: a public function that takes a value, and just forwards to the second function with the root as the starting point. The second actually traverses the three and inserts the new item:
// public interface:
void insert(int v) {
insert(new node(v), root);
}
// private workhorse:
void insert(node *n, node *&pos) {
if (pos == NULL)
pos = n;
else if (n->value < pos->value)
insert(n,pos->left);
else if (n->value > pos->value)
insert(n,pos->right);
else
// duplicate value.
}
Likewise, inorder gets split into a public and private pair, with the public providing only an interface, and the private one doing all the real work:
// public interface:
void inorder() {
inorder(root);
}
// private worker
void inorder(node *n) {
if (n==NULL)
return;
inorder(n->left);
std::cout << n->value << endl;
inorder(n->right);
}
For what it's worth: yes, I have tested this code and it does work at least with the input you used in you main. It does have shortcomings though. For example, both insert and inorder traverse the tree recursively, so a large, badly imbalanced tree could lead to stack overflow. It's fairly easy to do insertion iteratively, but for real use you usually just switch to some sort of balanced tree instead.