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 :-)
Related
The problem in my code starts from the final insertion that I have tried in the main() followed by the swapping method. I don't understand why swapping is not working plus the fact that insertion just doesn't work for the last one simply blows my mind. Is anybody there to help me?
```
void LL::insertion(int info,int val) //insertion problem arises in the fifth insertion.
{
if(head==NULL)
{
cout<<"LL is empty!"<<endl;
Node *temp=new Node;
temp->data=val;
temp->next=NULL;
head=temp;
}
else
{
Node *temp=new Node;
temp->data=val;
query=head;
while(query->data!=info && query->next!=NULL)
{
query=query->next;
}
if(query->data==info)
{
temp->next=query->next;
query->next=temp;
}
else
{
cout<<"The value you entered is not found in the LL!"<<endl;
}
}
}
void LL::swapping(int info,int val) //swapping is not working.
{
if(head==NULL)
{
cout<<"LL is empty!"<<endl;
}
else
{
query=head;
Node *temp;
temp=query;
while(query->data!=info && temp->data!=val)
{
query=query->next;
temp=temp->next;
}
Node *temp1;
temp1=query;
query->next=temp->next;enter code here
temp->next=temp1->next;
delete temp1;
}
}
int main()
{
LL obj; //"obj" is object of of the class "LL"
//cout<<obj.emptiness()<<endl;
obj.insertion(0,1);
obj.insertion(1,2);
obj.insertion(2,3);
obj.insertion(3,4);
obj.insertion(4,5); //here problem arises.
obj.swapping(1,5); //no error is shown on compiler.
}
```
I wanted to implement a BST class with a vector and somehow its not working. I just wanted to know the reason why its not working.
The main reason that I can think of that root in the BST always remain NULL.
I wanted to experiment ways to use classes in data structures.
#include<iostream>
#include<vector>
using namespace std;
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = NULL;
right = NULL;
}
};
class BST{
public:
Node* root = NULL;
void insert(Node* r,int data){
Node* new_node = new Node(data);
if(r == NULL){
r = new_node;
}
if(data < r->data){
if(r->left == NULL){
r->left = new_node;
}
else{
insert(r->left,data);
}
}else if(data > r->data){
if(r->right == NULL){
r->right = new_node;
}
else{
insert(r->right,data);
}
}else{
return;
}
return;
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(root,bst_array[i]);
}
}
void print_t(Node* r){
if(r == NULL){
cout<<"NULL";
return;
}
else{
print_t(r->left);
cout<<r->data<<" ";
print_t(r->right);
}
}
};
int main(){
vector<int> v = {1,3,5,44,23,78,21};
BST* tr = new BST(v);
tr->print_t(tr->root);
return 0;
}
There seem to be a logical mistake on my end please help me find it.
Thanks in advance.
The reason is that root is never assigned another value after its initialisation to NULL. Passing root as argument to the insert method can never alter root itself, as it is not the address of root that is passed, but its value.
Some other remarks:
insert always starts by creating a new node, at every step of the recursion. This is a waste of node creation. In the end you just need one new node, so only create it when its position in the tree has been identified.
The final else is not needed, as all it does is execute a return, which it would have done anyway without that else block
As insert is a method of BST, it is a pity that it requires a node as argument. You would really like to just do insert(data) and let it take care of it. For that to happen I suggest to move your insert method to the Node class, where the this node takes over the role of the argument. Then the BST class could get a wrapping insert method that forwards the job to the other insert method.
Instead of NULL use nullptr.
To solve the main issue, there are many solutions possible. But after making the above changes, it is quite easy to assign to root in the simplified insert method on the BST class.
Here is how it could work:
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
void insert(int data) {
if (data < this->data) {
if (this->left == nullptr) {
this->left = new Node(data);
} else {
this->left->insert(data);
}
} else if (data > this->data) {
if (this->right == nullptr) {
this->right = new Node(data);
} else {
this->right->insert(data);
}
}
}
};
class BST {
public:
Node* root = nullptr;
void insert(int data) {
if (root == NULL) { // Assign to root
root = new Node(data);
} else { // Defer the task to the Node class
root->insert(data);
}
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(bst_array[i]); // No node argument
}
}
/* ...other methods ...*/
}
I'm working on a university project (Data structures) this weekend and I have to code an AVL tree in C++. I thought that it wouldn't be difficult to code a BST first and then convert it into an AVL. Probably I was wrong... I have two classes, class node and class AVLTree,which is friend of class node. I managed to do the insertions and deletions according to BST's rules (I checked) and also I managed to find the balance factor of its node of the tree (which also worked). However, when I tried the simple left rotations, everything went out of order! Here's my code (first the .h files):
class node
{
public:
node();
private:
int data;
int heightL;
int heightR;
int balance;
node* leftChild;
node* rightChild;
friend class AVLTree; //Only class AVLTree has now access to the private fields of class node
};
class node;
class AVLTree
{
public:
AVLTree();
bool insertNode(int aData);
node* searchNode(int key);
bool deleteNode(int key);
node* findMostLeft(node *aRoot);
node* findMostRight(node *subtree);
void display();
private:
node *root;
void inOrderTraversal(node* pointer);
node* newNode(int aData);
void updateHeightsInserting(int nodeCounter,int aData);
void updateHeightsDeleting(int nodeCounter,int aData);
void updateTreeHeights(node *ptr);
int max(int a,int b);
void balanceTree(node *current,node *previous,node *next);
void slRotation(node* current,node *previous,node *next);
void srRotation(node* current,node *previous,node *next);
void dlRotation(node* current,node *previous,node *next);
void drRotation(node* current,node *previous,node *next);
};
And now the .cpp file of class AVLTree (some methods only)
bool AVLTree::insertNode(int aData)
{
node *current,*next,*ptr;
bool isLeftChild;
int nodeCounter=0;
current=next=root;
ptr=newNode(aData);
if(ptr==NULL) //Couldn't allocate memory
{
return false;
}
if(current==NULL) //Inserting the first node in our tree (root==NULL)
{
root=ptr;
return true; //Successful insertion of root
}
do
{
if(aData<current->data) //If the node we want to insert has data smaller than the current node's data, then repeat the procedure for the left child of the current node
{
next=current->leftChild;
isLeftChild=true;
nodeCounter++;
}
else if(aData>current->data) //If the node we want to insert has data bigger than the current node's data, then repeat the procedure for the right child of the current node
{
next=current->rightChild;
isLeftChild=false;
nodeCounter++;
}
if(next==NULL)
{
if(isLeftChild)
{
current->leftChild=ptr;
}
else
{
current->rightChild=ptr;
}
updateHeightsInserting(nodeCounter,aData);
return true;
}
current=next; //Repeat the procedure for the next node
}while(next!=NULL); //Repeat the procedure until there's no next node, meaning we enter the if(next==NULL) statement
}
The method for updating heights:
void AVLTree::updateHeightsInserting(int nodeCounter,int aData)
{
node *current,*next,*previous;
current=next=previous=root;
do
{
if(aData<current->data)
{
if(current->heightL<nodeCounter)
{
current->heightL=nodeCounter;
}
next=current->leftChild;
nodeCounter--;
}
else if(aData>current->data)
{
if(current->heightR<nodeCounter)
{
current->heightR=nodeCounter;
}
next=current->rightChild;
nodeCounter--;
}
current->balance=current->heightR-current->heightL;
if(abs(current->balance)>1)
{
if(abs(next->heightR-next->heightL)<1) //We use <1, because the hight of the next node hasn't been increased yet-If the next node isn't problematic it means the current node is
balanceTree(current,previous,next);
}
previous=current;
current=next;
}while(next->data!=aData);
}
A trial code for rotation (It doesn't work!)
void AVLTree::slRotation(node *current,node *previous,node *next)
{
if(current==root) //previous=current
{
node *temp;
root=next; //next=current->rightChild
temp=next->leftChild;
next->leftChild=current;
current->rightChild=temp;
}
else
previous->rightChild=next;
current->rightChild=NULL;
next->leftChild=current;
}
And the Balancing method:
void AVLTree::balanceTree(node *current,node *previous,node *next)
{
if(current->balance>1) //if the tree is right heavy
if(next->balance>0) //if the tree's right subtree is right heavy
slRotation(current,previous,next); //perform Simple Left Rotation
else //if the tree's right subtree is left heavy
dlRotation(current,previous,next); //perform Double Left Rotation
else //if the tree is left heavy
if(next->balance<0) //if the tree's left subtree is left heavy
srRotation(current,previous,next); //perform Simple Right Roation
else //if the tree's left subtree is right heavy
drRotation(current,previous,next); //perform Double Right Rotation
updateTreeHeights(root);
}
I also use the updateTreeHeights (this is tested, too and works well without the rotations) method here that isn't efficient, I know, but I didn't have a better idea!
void AVLTree::updateTreeHeights(node *ptr) //Visits the nodes by level recursively (post-order traversal), so that it can calculate the balance of each node
{
if(ptr==NULL)
return;
updateTreeHeights(ptr->leftChild);
updateTreeHeights(ptr->rightChild);
if(ptr->leftChild==NULL && ptr->rightChild==NULL)
{
ptr->heightL=ptr->heightR=0;
}
else if(ptr->leftChild==NULL)
{
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
ptr->heightL=0;
}
else if(ptr->rightChild==NULL)
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=0;
}
else
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
}
ptr->balance=ptr->heightR-ptr->heightL;
}
Sorry for the long post! It's the first time in my life I use an AVL tree, let alone programming it! Hope you can help!
Problem solved! I messed up with the right and left pointers in double rotations!
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.
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.