I have made a function for insertion in BST using loops and it is working perfectly fine.
Now, when iam writing to do it using recursion i don't know why it's not working properly, however the logic is correct according to me. It seems that no newnode is being added to the BST tree and head of the tree after coming out of the insertion function is again becoming NULL.
#include <iostream>
using namespace std;
class node{
public:
int data;
node *right;
node *left;
node(){
data=0;
right=NULL;
left=NULL;
}
};
class tree{
node *head;
int maxheight;
void delete_tree(node *root);
public:
tree(){head=0;maxheight=-1;}
void pre_display(node* root);
node* get_head(){return head;}
void insert(int key,node* current);
};
void tree::insert(int key,node *current){
if(current==NULL)
{
node *newnode=new node;
newnode->data=key;
current=newnode;
}
else{
if(key<current->data)
insert(key,current->left);
else
insert(key,current->right);
}
return;
}
void tree::pre_display(node *root){
if(root!=NULL)
{
cout<<root->data<<" ";
pre_display(root->left);
pre_display(root->right);
}
}
int main(){
tree BST;
int arr[9]={17,9,23,5,11,21,27,20,22},i=0;
for(i=0;i<9;i++)
BST.insert(arr[i],BST.get_head());
BST.pre_display(BST.get_head());
cout<<endl;
system("pause");
return 0;
}
Please tell me what should i change in the algorithm to make it work.
In your insert function
void tree::insert(int key,node *current){
if(current==NULL)
{
node *newnode=new node;
newnode->data=key;
current=newnode;
}
else{
if(key<current->data)
insert(key,current->left);
else
insert(key,current->right);
}
return;
}
you allocate a new node but never set BST::head to newly allocated head. So BST::get_head will always return null.
One way to fix this would be for insert to return a node. This would be root node in your case and set the BST::head to this value.
Your recursion looks fine, but you don't actually add the node anywhere! You just recurse through the tree.
Edit You can change the insert method to take a pointer to a pointer, like this:
void tree::insert(int key, node **current)
{
if(*current == NULL)
{
node *newnode = new node;
newnode->data = key;
*current = newnode;
}
else
{
if(key < (*current)->data)
insert(key, &(*current)->left);
else
insert(key, &(*current)->right);
}
}
And in main call it like this:
BST.insert(arr[i], &BST.get_head()); // Note the ampersand (&)
you should try this
node tree:: insert ( int key , node * current ) {
if ( ! current ) {
node * newnode = new node ;
newnode -> key = key;
current = newnode ;
}
else if ( key < current -> key ) {
current -> left = insert ( key , current ->left
}
else
current -> right = insert ( key , current->right )
return current ;
}
it works fine....jsut update the head node every time whenver a new node is inserted and it will return the updated current node.
Just change your function as
void tree::insert(int key,node*& current){
if(current==NULL)
{
node *newnode=new node;
newnode->data=key;
current=newnode;
}
else{
if(key<current->data)
insert(key,current->left);
else
insert(key,current->right);
}
return;
}
make your input pointer as a reference parameter.
struct node{
node* left;
node* right;
int data;
};
node* root=NULL;
node* create(node* head,int val){
if(head==NULL){
node* nn=new node;
nn->data=val;
nn->left=NULL;
nn->right=NULL;
head=nn;
}
else if(val<head->data)
head->left=create(head->left,val);
else if(val>head->data)
head->right=create(head->right,val);
return head;
}
int main(){
int num=0;
cout<<"Enter value in tree or press -1 to Exit\n";
while(num!=-1){
cin>>num;
if(num==-1){
cout<<"\nTree Created\n";
break;
}
else{
root=create(root,num);
}
}
}
hope this code solves your problem
void insertNode_recursive(int value, TreeNode *current)
{
if (current == NULL)
{
if (current == NULL && isEmpty())
{
TreeNode *new_node = new TreeNode(value);
current = new_node;
root = new_node;
}
else
{
TreeNode *new_node = new TreeNode(value);
current = new_node;
}
}
else
{
if (value < current->getValue())
{
insertNode_recursive(value, current->getLeft());
}
else if (value > current->getValue())
{
insertNode_recursive(value, current->getRight());
}
else
{
cout << "\nDuplicate Value are Not Allowed\n";
}
}
}
This Code is Useful For Recursively Print the Tree Node
Related
I'm trying to add elements enter by the user in a BST.For this I've used 2 functions, one is used to create the function and other is just used to insert element to the tree. One is a pre-order function that is used to check if insertion is done or not Initially I tried to add elements manually.Its not printing all inserted values.
The overall layout
struct Node{
int data;
struct Node* left;
struct Node* right;
};
void Inorder(struct Node* root){
if(root==NULL){
return;
}
else{
Inorder(root->left);
cout<<root->data<<" ";
Inorder(root->right);
}
}
struct Node* create_node(int data){
struct Node* node=(struct Node*) malloc(sizeof(struct Node));
node->data=data;
node->left=NULL;
node->right=NULL;
return node;
}
The problem code:-
struct Node* insert(struct Node* root,int data){
static struct Node* prev=NULL;
if(root==NULL && prev==NULL){
return create_node(data);
}
if(root->data==data){
return root;
}
else{
if(root==NULL){
struct Node* ptr=create_node(data);
if(prev->data>data){
prev->left=ptr;
return root;
}
else{
prev->right=ptr;
return root;
}
}
else{
if(root->data>data){
prev=root;
insert(root->left,data);
}
else{
prev=root;
insert(root->right,data);
}
}
}
}
MAIN
int main()
{
struct Node* root=NULL;
root=insert(root,5);
Inorder(root);
cout<<endl;
insert(root,3);
Inorder(root);
insert(root,10);
Inorder(root);
return 0;
}
One thing I noticed that prev is static once we call insert for inserting next element(here 3) it won't roll over from start again because it is declared static.To overcome that
Tried to optimize the problem code by making prev as global and making null in main every time I call insert function in the main(), The optimised code is as follows:
#include <iostream>
#include<stdlib.h>
using namespace std;
static struct Node* prev=NULL;
struct Node{
int data;
struct Node* left;
struct Node* right;
};
void Inorder(struct Node* root){
if(root==NULL){
return;
}
else{
Inorder(root->left);
cout<<root->data<<" ";
Inorder(root->right);
}
}
struct Node* create_node(int data){
struct Node* node=(struct Node*) malloc(sizeof(struct Node));
node->data=data;
node->left=NULL;
node->right=NULL;
return node;
}
struct Node* insert(struct Node* root,int data){
if(root==NULL && ::prev==NULL){
return create_node(data);
}
if(root->data==data){
return root;
}
else{
if(root==NULL){
struct Node* ptr=create_node(data);
if(::prev->data>data){
::prev->left=ptr;
return root;
}
else{
::prev->right=ptr;
return root;
}
}
else{
if(root->data>data){
::prev=root;
insert(root->left,data);
}
else{
::prev=root;
insert(root->right,data);
}
}
}
}
int main()
{
struct Node* root=NULL;
root=insert(root,5);
Inorder(root);
cout<<endl;
::prev=NULL;
insert(root,3);
Inorder(root);
::prev=NULL;
insert(root,10);
Inorder(root);
return 0;
}
This is not how insertion into a BST is supposed to work. You don't need a prev pointer at all.
One of the issues in your code is that you don't use the return value of the recursive call, which at some point is going to be the pointer to a new node! You should really assign that return value to either the left or right member of the current node.
Also, the following if condition will never be true, as at that point it was already guaranteed that root is not NULL:
else{
if(root==NULL){
The correct code is actually quite simple:
struct Node* insert(struct Node* root, int data){
if (root == NULL) {
root = create_node(data);
} else if (root->data > data) {
root->left = insert(root->left, data);
} else if (root->data < data) {
root->right = insert(root->right, data);
}
return root;
}
I would also add some line breaks to the output in your main code:
int main()
{
struct Node* root = NULL;
root = insert(root, 5);
Inorder(root);
cout << endl;
insert(root, 3);
Inorder(root);
cout << endl;
insert(root, 10);
Inorder(root);
cout << endl;
return 0;
}
The issue that I noticed in my code (Unfortunately unable to upload the snippet). was in the part mentioned below.
if(root->data==data){
return root;
}
Firstly let me explain the recursion function, at beginning the root would be null at insertion(here inserting 5 as root) so first condition will be satisfied i.e.
if(root==NULL && ::prev==NULL){
return create_node(data);
}
and the function would return,now I set the global variable prev as NULL because I want to traverse again from the root of the tree to add the next element.
Now once we try to add another element (here adding element 3). This condition
if(root==NULL && ::prev==NULL){
return create_node(data);
}
won't be true, now the thought process while writing the logic was checking if at some stage while traversing down the tree if we encounter node with same value then we'll return the root and terminate the function. This is what I tried to implement .
Here's the code if you could relate(Problem Code Snippet)
else if(root->data==data){
return root;
}
No doubt approach is fine but I forgot to add one condition(actually I preempted that at this stage the root won't be NULL) but root can be NULL.
Because of this we will face segmentation fault error (in debugger mode -> which helped me to find the error in my code!).
So the correct code would be:
else if(root && root->data==data){// or if(root!=NULL && root->data=data)
return root;
}
Rest of the code remains unaltered
So to sum up when traversing through tree we return true for all conditions and once we reach NULL then since first condition won't we satisfied as prev!=NULL, so it comes to next condition root->data==data but here root=NULL so we get
segmentation fault error and function never encounters ROOT==NULL which was designed for this purpose only i.e. to add/insert element in the tree as everything seems fine on traversing the tree. So to over come this problem I modified my else if condition i.e. else if(root && root->data==data)
so the full function code is as follows:
struct Node* insert(struct Node* root,int data){
if(root==NULL && ::prev==NULL){
return create_node(data);
}
else if(root && root->data==data){
return root;
}
else{
if(root==NULL){
struct Node* ptr=create_node(data);
if(::prev->data>data){
::prev->left=ptr;
return root;
}
else{
::prev->right=ptr;
return root;
}
}
else{
if(root->data>data){
::prev=root;
insert(root->left,data);
}
else{
::prev=root;
insert(root->right,data);
}
}
}
}
PS: The code was executed for many trees including one mentioned in the question and got the expected results i.e. Inorder was a sorted array which depicts that insertion was done correctly.
I am writing a code to return data of a node in BST based on id.
below is my node class:
struct Node{
int id;
string data;
Node *left;
Node *right;
Node();
};
below is my node constructor: I defined id and data in addNode function
Node :: Node(){
this->left = nullptr;
this->right = nullptr;
}
below is my BST class:
class BST{
private:
Node * root = nullptr;
void setRoot(Node *);
Node* getRoot();
public:
Node *addNode(BST *, int);//helper function
Node *addNode(Node *,int);
string getEntry(BST*,int);//helper function
string getEntry(Node*,int);
}
below is my helper functions:
Node *BST::addNode(BST *bst, int val){
addNode(bst->getRoot(),val);
}
string BST::getEntry(BST* bst,int id){
getEntry(bst->getRoot(),id);
}
below is my addNode class:
Node* BST::addNode(Node* root, int val) {
Node *newNode = new Node();
newNode->id = val;
newNode->data = "Number " + to_string(val);
if (root == nullptr) {
if (getRoot() == nullptr){
setRoot(newNode);
}
setCount(getCount()+1);
return newNode;
}
if (root->id > val) {
root->left = addNode(root->left, val);
} else {
root->right = addNode(root->right, val);
}
return root;
}
below is my getEntry class:
string BST::getEntry(Node *base,int id) {
if (base == nullptr){
return "";
}
if (base->id == id){
cout<<base->data<<endl;
return base->data;
}
getEntry(base->left,id);
getEntry(base->right,id);
}
below are the nodes I passed in from main:
int main(){
BST *newBst = new BST();
newBst->addNode(newBst,1);
newBst->addNode(newBst,2);
newBst->addNode(newBst,3);
newBst->addNode(newBst,2);
newBst->addNode(newBst,3);
newBst->addNode(newBst,5);
newBst->addNode(newBst,7);
newBst->addNode(newBst,10);
cout<<newBst->getEntry(newBst,5)<<endl;
return 0;
}
The code would compile but does not return anything, I tried to debug, at the "return base->data statement", there is an error "can not access memory at address 0xc8". What causes the problem and what can I do about it?
this is the warning I got when I debug the code.
if (base->id != id){
getEntry(base->left,id);
getEntry(base->right,id);
}
As you are using a sorted tree, you know which of the right or left node you need to have a look at. Also, you need to return something:
if (base->id > val){
return getEntry(base->left,id);
}
return getEntry(base->right,id);
But the design with addNode is very bad, you shouldn't have to pass the root twice!
#include<iostream>
using namespace std;
struct node
{
int data;
node *right;
node *left;
} ;
node *root = NULL;
node *right = NULL;
node *left = NULL;
node insert(int data)
{
node *ptr = new node;
ptr->data = data;
ptr->left = NULL;
ptr->right = NULL;
if(root==NULL)
{
root = ptr;
cout<<"Inserted "<<root->data<<" at root\n";
}
else
{
node *pos = root;
while(pos)
{
cout<<pos->data<<" pos->data\n";
if(pos->data > data)
{
cout<<pos->data<<": data\n";
pos = pos->left;
}
else if(pos->data < data)
{
cout<<pos->data<<": data\n";
pos = pos->right;
}
if(!pos)
cout<<"NULL\n";
}
pos = ptr;
cout<<"Inserted\n";
}
return *root;
}
void preorder(node *root)
{
if(root)
{
cout<<root->data;
preorder(root->left);
preorder(root->right);
}
}
int main()
{
insert(2);
insert(1);
insert(3);
insert(4);
insert(5);
preorder(root);
return 0;
}
Here, while inserting the new element, I am pointing root to new variable pos so that root is unaltered so that it becomes parameter to the function preorder() properly as it is the actual root
But, pos isn't inserting all the elements and also not displaying the required results. In short I have to use root instead of pos to insert, but using root directly is altering the 'actual' root (which in this case is 2).
But, pos isn't inserting all the elements and also not displaying the required results.
I think there are mainly two bugs.
root is never updated in the current insert function because ptr is just only assigned to a temporal variable pos after while loop finished.
We should consider the case that the value of the passed argument data is already saved in the binary tree.
In addition, preorder is displaying the root again and again is confusing.
An example of fixing the insert and preorder is following one.
DEMO is here.
node insert(int data)
{
node *ptr = new node;
ptr->data = data;
ptr->left = nullptr;
ptr->right = nullptr;
if(!root)
{
root = ptr;
}
else
{
node *pos = root;
while(true)
{
if(pos->data > data)
{
if(!pos->left){
pos->left = ptr;
break;
}
pos = pos->left;
}
else if(pos->data < data)
{
if(!pos->right){
pos->right = ptr;
break;
}
pos = pos->right;
}
else{
break;
}
}
}
return *root;
}
void preorder(node *next)
{
if(next)
{
cout << next->data << std::endl;
preorder(next->left);
preorder(next->right);
}
}
I have written code to delete a node in Binary Search Tree.
Code :
#include<iostream>
using namespace std;
struct Node {
int value;
Node* left;
Node* right;
};
Node* GetNewNode(int data) {
Node* newNode = new Node();
newNode->value = data;
newNode->left = newNode->right = NULL;
return newNode;
}
void Insert(Node* &root,int x)
{
if(root==NULL) root=GetNewNode(x);
else if(x>root->value) Insert(root->right,x);
else Insert(root->left,x);
}
Node* Search(Node* root,int x)
{
if(root->value==x) return root ;
else if(root->value>x) Search(root->left,x);
else if(root->value<x) Search(root->right,x);
}
Node* Searchmin(Node* root)
{
if(root==NULL) cout<<"Empty tree"<<endl;
if(root->left==NULL) return root;
else Searchmin(root->left);
}
void Inorder(Node* root)
{
if(root==NULL) return;
else {
Inorder(root->left);
cout<<root->value<<endl;
Inorder(root->right);
}
}
Node* deleteNode(Node* root, int x)
{
Node* nodeptr;
nodeptr=Search(root,x);
if(nodeptr->left==NULL && nodeptr->right==NULL) return nodeptr;
else if(nodeptr->left==NULL && nodeptr->right!=NULL)
{
nodeptr->value=nodeptr->right->value;
nodeptr=nodeptr->right;
return nodeptr;
}
else if(nodeptr->right==NULL && nodeptr->left!=NULL)
{
nodeptr->value=nodeptr->left->value;
nodeptr=nodeptr->left;
return nodeptr;
}
else{
nodeptr->value=Searchmin(nodeptr->right)->value;
deleteNode(nodeptr->right,nodeptr->value);
return nodeptr;}
}
int main()
{
Node* root=NULL;
Insert(root,20);
Insert(root,15);
Insert(root,25);
Insert(root,10);
Insert(root,16);
Insert(root,7);
Inorder(root);
Node* x=deleteNode(root,7);
delete x;
Inorder(root);
}
Compiler doesn't show any syntax error either. The program is crashing. Its not even deleting leaf node. I can't find the error. Please help.
(These lines are just to extend length of question because stackoverflow was not accepting generating error in question on lines of long code and short description.)
The first thing your delete function does is call search, and what's the first thing search does?
Node* Search(Node* root,int x)
{
if(root->value==x) return root ;
Search immediately dereferences root. It never checks for a null pointer. This means it's guaranteed your search function will dereference a null pointer if there is no node in the tree to be found.
typedef struct treeNode {
treeNode* left;
treeNode* right;
int data;
treeNode(int d) {
data = d;
left = NULL;
right = NULL;
}
}treeNode;
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
else if (data < root->data) {
insert(root->left, data);
}
else {
insert(root->right, data);
}
}
void inorderTraversal(treeNode* root) {
if (root == NULL)
return;
inorderTraversal(root->left);
cout<<root->data;
inorderTraversal(root->right);
}
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(root, 2);
inorderTraversal(root);
return 0;
}
So I'm pretty tired, but I was whipping some practice questions up for interview prep and for some reason this BST insert is not printing out that any node was added to the tree. Its probably something im glossing over with the pointers, but I can't figure it out. any ideas?
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
This change to root is lost as soon as the function ends, it does not modify the root passed as argument but its own copy of it.
Take note that when u insert the node, use pointer to pointer (pointer alone is not enough):
So, here is the fixed code:
void insert(treeNode **root, int data) {
if (*root == NULL) {
cout << root;
*root = new treeNode(data);
}
else if (data < (*root)->data) {
insert(&(*root)->left, data);
}
else {
insert(&(*root)->right, data);
}
}
And in main:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(&root, 2);
inorderTraversal(root);
return 0;
}
Your logic is correct!
The only issue is that when you create a local variable, even if it is a pointer, its scope is local to the function. In your main:
...
insert(root, 2);
...
function call sends a copy of the root which is a pointer to treeNode (not the address of root). Please note that
void insert(treeNode *root, int data)
gets a treeNode pointer as an argument (not the address of the pointer). Attention: This function call may look like "call by pointer" (or reference) but it is actually "call by value". The root you define in the main function and the root inside the insert method have different addresses in the stack (memory) since they are different variables. The former is in main function stack in the memory while the latter is in insert method. Therefore once the function call insert finishes executing, its stack is emptied including the local variable root. For more details on memory refer to: stacks/heaps.
Of course the data in the memory that you allocated using:
*root = new treeNode(data);
still stays in the heap but you have lost the reference to (address of) it once you are out of the insert function.
The solution is either passing the address of original root to the function and modifying it (as K-ballo and dip has suggested) OR returning the modified local root from the function. For the first approach please refer to the code written by dip in his/her answer.
I personally prefer returning the modified root from the function since I find it more convenient especially when implementing other common BST algorithms. Here is your function with a slight modification of your original code:
treeNode* insert(treeNode *root, int data) {
if (root == NULL) {
root = new treeNode(data);
}
else if (data < root->data) {
root->left=insert(root->left, data);
}
else {
root->right=insert(root->right, data);
}
return treeNode;
}
The function call in main will be:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
root = insert(root, 2);
inorderTraversal(root);
return 0;
}
Hope that helps!
After a while seeing some complicated methods of dealing with the Binary tree i wrote a simple program that can create, insert and search a node i hope it will be usefull
/*-----------------------Tree.h-----------------------*/
#include <iostream>
#include <queue>
struct Node
{
int data;
Node * left;
Node * right;
};
// create a node with input data and return the reference of the node just created
Node* CreateNode(int data);
// insert a node with input data based on the root node as origin
void InsertNode (Node* root, int data);
// search a node with specific data based on the root node as origin
Node* SearchNode(Node* root, int data);
here we define the node structure and the functions mentioned above
/*----------------------Tree.cpp--------------*/
#include "Tree.h"
Node* CreateNode(int _data)
{
Node* node = new Node();
node->data=_data;
node->left=nullptr;
node->right=nullptr;
return node;
}
void InsertNode(Node* root, int _data)
{
// create the node to insert
Node* nodeToInsert = CreateNode(_data);
// we use a queue to go through the tree
std::queue<Node*> q;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
//left check
if(temp->left==nullptr)
{
temp->left=nodeToInsert;
return;
}
else
{
q.push(temp->left);
}
//right check
if(temp->right==nullptr)
{
temp->right=nodeToInsert;
return;
}
else
{
q.push(temp->right);
}
}
}
Node* SearchNode(Node* root, int _data)
{
if(root==nullptr)
return nullptr;
std::queue<Node*> q;
Node* nodeToFound = nullptr;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
if(temp->data==_data) nodeToFound = temp;
if(temp->left!=nullptr) q.push(temp->left);
if(temp->right!=nullptr) q.push(temp->right);
}
return nodeToFound;
}
int main()
{
// Node * root = CreateNode(1);
// root->left = CreateNode(2);
// root->left->left = CreateNode(3);
// root->left->left->right = CreateNode(5);
// root->right = CreateNode(4);
// Node * node = new Node();
// node = SearchNode(root,3);
// std::cout<<node->right->data<<std::endl;
return 0;
}