I have been trying to implement the delete BST function but I don't know why it is not working, I think it's logically correct. Can any body please tell me, why I'm getting run time error and how should I correct it.
#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;
public:
tree(){head=0;maxheight=-1;}
bool deletenode(int key,node* root);
int get_height(){return maxheight;}
void insert(int key);
void pre_display(node* root);
void delete_tree(node *root);
node* get_head(){return head;}
};
void tree::insert(int key){
node *current=head;
node *newnode=new node;
if(newnode==NULL)
throw(key);
newnode->data=key;
int height=0;
if(head==0){
head=newnode;
}
else
{
while(1){
if(current->right==NULL && current->data < newnode->data)
{
current->right=newnode;
height++;
break;
}
else if(current->left==NULL && current->data > newnode->data)
{
current->left=newnode;
height++;
break;
}
else if(current->right!=NULL && current->data < newnode->data)
{
current=current->right;
height++;
}
else if(current->left!=NULL && current->data > newnode->data)
{
current=current->left;
height++;
}
}
}
if(height>maxheight)
maxheight=height;
}
void tree::pre_display(node *root){
if(root!=NULL)
{
cout<<root->data<<" ";
pre_display(root->left);
pre_display(root->right);
}
}
void tree::delete_tree(node *root){
if(root!=NULL)
{
delete_tree(root->left);
delete_tree(root->right);
delete(root);
if(root->left!=NULL)
root->left=NULL;
if(root->right!=NULL)
root->right=NULL;
root=NULL;
}
}
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.pre_display(BST.get_head());
cout<<endl;
BST.delete_tree(BST.get_head());
BST.pre_display(BST.get_head());
cout<<endl;
system("pause");
return 0;
}
All the other functions are working correctly, you just need to check the delete_tree function, the other code is provided to give the idea of the structure of my BST.
In your delete_tree
void tree::delete_tree(node *root){
if(root!=NULL)
{
delete_tree(root->left);
delete_tree(root->right);
delete(root);
if(root->left!=NULL)
root->left=NULL;
if(root->right!=NULL)
root->right=NULL;
root=NULL;
}
}
you are accessing root variable after you have deleted it
Also you call
BST.delete_tree(BST.get_head());
BST.pre_display(BST.get_head());
pre_display after deleting tree. delete_tree after deleting the tree should also set the BST.head to NULL
Also a critique. BST is of type tree. It already has a head member variable indicating the root node. So delete_tree/pre_display do not need any parameters at all.
You can delete by:
//This is function of cleaning:
void cleantree(tree *root){
if(root->left!=NULL)cleantree(root->left);
if(root->right!=NULL)cleantree(root->right);
delete root;}
//This is where we call the cleaning function:
cleantree(a);
a=NULL;
//Where "a" is pointer to root of the tree.
The problem is here:
delete_tree(root->left);
delete_tree(root->right);
delete(root);
if(root->left!=NULL)
root->left=NULL;
if(root->right!=NULL)
root->right=NULL;
root=NULL;
You're trying to assign NULL to a member of root:
root->left=NULL;
which was already deleted. There's no need to do that since you're already freeing the memory in delete_tree(root->left);
Recursively delete left and right sub tree and your tree will be deleted as simple as:
void delete(node *root){
// If node is empty, don't bother
if (root == NULL) { return; }
// Delete subtrees
delete(root->left);
delete(root->right);
// Delete current node
free(root);
root = NULL;
}
You should not read from root after deleting it. Move the delete(root) line down.
Short answer: your implementation of the node descriptor missing the correct explicit destructor implementation (the default generated by the compiler will be used by calling the delete operator:calling destructor and releasing the allocated space on the heap)-the one that clear references to the siblings
here is my suggestion using recursivity..
template <class T> void Tree<T>::destroy(Noeud<T> ** r){
if(*r){
if(!(*r)->left && !(*r)->right){ //a node having no child
delete *r; *r=NULL;
}else if((*r)->left && (*r)->right){ //a node having two childs
destroy(&(*r)->left); //destroy the left tree
destroy(&(*r)->right); //destroy the right tree
destroy(r); //destroy the node
}else if((*r)->left){ //a node has only left child
destroy(&(*r)->left); //destroy the left tree
destroy(r); //destroy the node
}else if((*r)->right){ //a node has only right child
destroy(&(*r)->right); //destroy the right tree
destroy(r); //destroy the node
}
}
}
//in function main()
int main(){
Tree<int> a(5); // 'a' is a tree of int type with a root value equal 5
a.add(2);a.add(7);a.add(6);a.add(-1);a.add(10); // insert values into the tree
a.destroy(&a.root); //destroy the tree
}
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 trying to print all the elements using inorder traversal, but my code is giving incorrect output. I am not able to figure out what went wrong.
#include <iostream>
using namespace std;
struct node
{
int value;
struct node * left;
struct node * right;
};
class Btree
{
node * root;
void insert(int value, node * leaf);
node * search(int value, node * leaf);
void destroy(node * leaf);
public:
Btree() { root = NULL; }
~Btree() { destroy(); }
void insert(int value);
node * search(int value);
void destroy();
void inorder(node * ptr);
};
void Btree::inorder(node *ptr)
{
if (ptr != NULL)
{
inorder(ptr->left);
cout << ptr->value << "";
inorder(ptr->right);
}
}
void Btree::destroy(node *leaf)
{
if(leaf!=NULL)
{
destroy(leaf->left);
destroy(leaf->right);
delete leaf;
}
}
void Btree :: destroy()
{
destroy(root);
}
node *Btree::search(int value, node *leaf)
{
if(leaf!=NULL)
{
if(value==leaf->value)
return leaf;
if(value<leaf->value)
return search(value, leaf->left);
else
return search(value, leaf->right);
}
else return NULL;
}
node *Btree::search(int value)
{
return search(value, root);
}
void Btree::insert(int value, node *leaf)
{
if(value< leaf->value)
{
if(leaf->left!=NULL)
insert(value, leaf->left);
else
{
leaf->left=new node;
leaf->left->value=value;
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(value>=leaf->value)
{
if(leaf->right!=NULL)
insert(value, leaf->right);
else
{
leaf->right=new node;
leaf->right->value=value;
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
}
}
}
void Btree::insert(int value)
{
if(root!=NULL)
insert(value, root);
else
{
root=new node;
root->value=value;
root->left=NULL;
root->right=NULL;
}
}
int main()
{
Btree bst;
struct node * root = NULL;
root = new node;
bst.insert(10);
bst.insert(6);
bst.insert(14);
bst.insert(3);
bst.insert(8);
bst.insert(7);
bst.insert(9);
bst.insert(5);
bst.inorder(root);
return 1;
}
I have tried to create a memory pointer that is the root and then passing that root in my inorder function call. My inorder should print me the output
3 5 6 7 8 9 10 14
A pointer to a step-debugger would help me in solving the issue I believe.Or if anyone can provide me the corrected code, would be quite helpful
Edit:- I had previously passed ptr but used root in my inorder function definition (due to which I was getting Bus error), but now it is correected. However, I still do not get the right output. The output I get is 0
I've already debugged the code and did not find any mistake. Below code does not print all the data of binary search tree(BST).Only root node and last two node get display in inorder traversal.
struct node{
int key;
node *left;
node *right;
};
node* newNode(int data){
node *ptr=new node;
ptr->key=data;
ptr->left=ptr->right=NULL;
return ptr;
}
node* insert_node(node* root,int data){
if(root==NULL){
root=newNode(data);
}else if(data<=root->key){
root->left=newNode(data);
}else{
root->right=newNode(data);
}
return root;
}
void inorder(node* root){
if(root==NULL)
return;
inorder(root->left);
cout<<root->key<<" ";
inorder(root->right);
}
int main(){
node *root=NULL;
root=insert_node(root,10);
root=insert_node(root,12);
root=insert_node(root,15);
root=insert_node(root,1);
root=insert_node(root,20);
inorder(root);
return 0;
}
The insert function is not having any recursive or iterative implementation that will find the leaf node. So the new node will replace the child nodes of root node. And I think that is very well highlighted in comment section.
Here's a block of code in which the leaf node is located by use of iteration and then the new node is inserted.
node *insert_node( node *root, int data){
struct node *ptr, *nodeptr, *parentptr;
ptr = (struct node*)malloc(sizeof(struct node));
ptr->data = data;
ptr->left = NULL;
ptr->right = NULL;
if(root==NULL) //tree is empty
{
root=ptr;
root->left=NULL;
root->right=NULL;
}
else
{
parentptr=NULL; // keep the address of parent node
nodeptr=root;
while(nodeptr!=NULL)
{
parentptr=nodeptr;
if(data<nodeptr->data)
nodeptr=nodeptr->left;
else
nodeptr = nodeptr->right;
}
// now the parentptr contains address of the leaf node
if(data<parentptr->data)
parentptr->left = ptr;
else
parentptr->right = ptr;
}
return root;
}
You can also refer to some other sources for recursive implementation of the same.
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
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;
}