I'm currently writing a program that will delete a node from a binary search tree (among other things, but the deletion is my issue) and I'm having a problem with the final step of deletion, specifically the final step of deleting a node with 2 children.
The way that I'm deleting is the way described here.
I take the farthest down left child-node (if on the right side of root) or the farthest down right child-node (if on the left) and replace the value of the node I want to delete with that value, then delete the node I just copied from.
I have all the steps complete except deleting the node I copied from; for some reason my code does not properly delete it and creates a random number value as well as a random parent value for the node I just tried to delete. I believe this is caused by an unrepaired link in the tree somewhere but being a non-experienced programmer, I cannot find it. Hopefully someone more well versed in BSTs can help me.
Here is my code (I only included code that influences the deletion function, I didn't think it necessary to include things that come after such as the destroy function):
#include <iostream>
using namespace std;
struct node
{
int data; //Stores data within the trees pointers
node * parent; //Used to move up in the tree
node * left; //Used to move left in the tree
node * right; //Used to move right in the tree
};
node * create (int data, node **tree); //Function to insert elements into the tree
void printTree (node * tree); //Function to print the tree
node *search(int key, node *tree); //Function to find data in the tree
node * delNode (node * tree, node * root); //Function to delete data from the tree
node * findSmallestRight (node * tree, node **smallest);
node * findLargestLeft (node * tree, node **smallest);
int main()
{
node * root = NULL; //Root will be the first element in the tree
node * current = NULL; //Return value for insert function to keep changes
int value; //Value entered by user
while (true) //Loop to fill tree with data
{
cout << "Enter an integer, 0 to quit" << endl;
cin >> value;
if (value == 0) //Quit when 0 is entered, BEFORE entering it into the tree
break;
current = create(value, &root); //Insert value into the tree
cout << "After inserting " << value << " tree is:" << endl;
printTree(root); //Print the tree
}
while (true) //Loop to delete data from tree
{
cout << "Search for a value to delete from the tree, 0 to quit" << endl;
cin >> value;
if (value == 0)
break;
current = search(value, root); //Find the value in the tree
if (current == NULL)
cout << value << " is not in tree. Could not delete." << endl;
else
{
root = delNode(current, root); //Delete the data
cout << value << " has been deleted. The tree is now:" << endl;
printTree(root); //print the tree
}
}
destroy(root); //Destroy the tree
return 0;
}
void printNode (node * Node) //Function to print a node in the tree
{
cout << "addr= " << Node << " parent= " << Node->parent << " left= " << Node->left << " right= " << Node->right << " data= " << Node->data << endl;
}
node * createNode (int data) //Function to create a new node in the tree
{
node * newNode = NULL; //Create a new pointer
newNode = new node; //Make that pointer a node
newNode->data = data; //Fill it with data
newNode->left = NULL; //Make it point left to NULL
newNode->right = NULL; //and right to NULL
return newNode;
}
node * create (int data, node **tree) //Function to insert elements into the tree
{
node * newNode = NULL; //Create a new pointer
if ((*tree) == NULL) //Check if tree exists already
{
//If it doesn't, create a new node and make it the root
newNode = createNode(data);
*tree = newNode;
(*tree)->parent = NULL; //Root has a parent of NULL
}
else if (data < (*tree)->data) //If the data is smaller than root, insert on the left
{
if ((*tree)->left == NULL)//If there is no node on the left, create a new one and point to it
{
newNode = createNode(data);
(*tree)->left = newNode;
newNode->parent = *tree;
}
else
{
newNode = create(data, &((*tree)->left));//If there is a node on the left, repeat function until there isn't
}
}
else //If the data is greater than or equal to root, insert on the right
{
if ((*tree)->right == NULL)
{
newNode = createNode (data); //If there is no node on the right, create a new one and point to it
(*tree)->right = newNode;
newNode->parent = *tree;
}
else
{
newNode = create(data, &((*tree)->right)); //If there is a node on the right, repeat function until there isn't
}
}
return newNode; //Return the new node to keep the changes to the value
}
void printTree (node * tree) //Function to print the tree
{
if (tree != NULL) //Check if tree actually existsreturn root;
{
//Recursively print the left side, then the root, then the right side
printTree(tree->left);
printNode(tree);
printTree(tree->right);
}
}
node *search(int key, node *tree) //Function to find data in the tree
{
if (tree == NULL || tree -> data == key)
{
return tree; //If the data either does not exist or has been found, return
}
if (key < tree->data)
{
return search(key, tree->left); //If the data is less than the current data, keep checking the left
}
else
{
return search(key, tree->right); //If the data is more than the current data, keep checking the right
}
}
node * delNode (node * tree, node * root)
{
node * parent; //Node for quick-reference and manipulation of tree's parent
if (tree->parent != NULL) //If tree value is not root assign a parent (root has parent of NULL so assigning would crash)
{
parent = tree->parent;
}
node * curr = tree;
//Removing node with 2 children on right
//There would also be cases for no children, 1 child, and 2 children on left but I did not include them as the two former are done and the latter can be copied once this is solved :)
else if (tree->left != NULL && tree->right != NULL && parent->right == tree && parent != NULL)
{
node * smallest; //Node to find smallest data value on left side
//Initialise and make it point to nothing
smallest = new node;
smallest->left = NULL;
smallest->right = NULL;
smallest->parent = NULL;
node * nReplace = NULL; //Node to replace data in tree
//Initialise and make it point to nothing
nReplace = new node;
nReplace->left = NULL;
nReplace->right = NULL;
nReplace->parent = NULL;
nReplace = findSmallestRight(tree, &smallest); //Function to find smallest data value on right side
tree->data = nReplace->data; //Replace tree's data with the new data
cout << nReplace << " " << nReplace->data << endl; //Debugging code
delete nReplace; //Delete nReplace
cout << nReplace << " " << nReplace->data << endl; //Debugging code
}
return root; //Return root to keep changes in tree
}
node * findSmallestRight (node * tree, node **smallest) //Function to find smallest data value on right side
{
node * parent = tree->parent; //Node for easy manipulation of tree's parent
//Check if current value is a potential candidate for smallest
if (tree->left == NULL && tree->right == NULL && parent->left == tree)
{
*smallest = tree; //If it is, make smallest equal to it
}
if (tree->left == NULL && tree->right != NULL) //Check if the are only branches on the right
{
findSmallestRight (tree->right, smallest); //Recurse through the right
}
else if (tree->left != NULL && tree->right == NULL) //Check if there are only branches on the left
{
findSmallestRight (tree->left, smallest); //Recurse through the left
}
else if (tree->left == NULL && tree->right == NULL) //Check if there are no branches on both sides
{
return *smallest; //Return the smallest
}
else
{
//If there are branches on both sides recurse through both
findSmallestRight (tree->left, smallest);
findSmallestRight (tree->right, smallest);
}
return *smallest; //Return the smallest
}
I think your findSmallestRight() is all messed up from recursion to returning the values.
You just have to find the SMALLEST element on the Right subtree i.e for the right child go on iterating it's Left children until last one, that'll be minimum one.
Code is as simple as : (First see picture for name associations)
if (current->left != NULL && current->right != NULL) //condition if you Current Node (to be deleted) has 2 Children
{ if((current->right)->left!=NULL) //If Right Child has left child go till last leftmost child.
{
Node* leftCurrent;
Node* leftCurrentPred;
leftCurrentPred=current->right;
leftCurrent=(current->right)->left;
while(leftCurrent->left != NULL)
{
leftCurrentPred=leftCurrent;
leftCurrent=leftCurrent->left;
}
current->data=leftCurrent->data;
delNode(leftCurrent, root); //Delete leftCurrent node i.e node with no child
leftCurrentPred->left=NULL;
cout<<item<<" has been removed from the Tree."<<endl;
}
else
{ //If Right Child of current doesn't has Left child it is itself smallest one.
Node* temp=current->right;
current->data=temp->data;
current->right=temp->right;
delNode(temp,root); //Delete temp node i.e node with no child
cout<<item<<" has been removed from the Tree."<<endl;
}
}
Related
I have to find the node with the minimum value in a binary search tree.I wrote the function but I can't display the node with the minimum value.This is the tree
struct Node
{
int key;
void *info;
Node *left, *right;
};
and this is the function
Node* findMin(Node* r)
{
if (r == 0)
return 0;
else if (r->left == 0)
return r;
else
return findMin(r->left);
}
I call the function like this in main file:
Node *root = makeTree(); // I enter the values and insert them into a binary search tree with an insert function.
root = findMin(root);
cout << root;
It displays the adress and not the value.What should I make to display the node with the minimum value?
In this statement
root = findMin(root);
you are overwriting the pointer to the root node of the tree.
The function can look the following way
Node * findMin( Node *node )
{
return node == nullptr || node->left == nullptr ? node : findMin( node->left );
}
To display the found value write
auto node = findMin( root );
if ( node ) std::cout << node->key << '\n';
int minValue(struct node* node)
{
struct node* current = node;
/* loop down to find the leftmost leaf */
while (current->left != NULL)
{
current = current->left;
}
return(current->data);
}
It displays the adress and not the value.What should I make to display the node with the minimum value?
It is because you need to dereference the pointer to display the value. Inside your main function:
Node *root = makeTree();
root = findMin(root);
if (root)
cout << root->key;
else
cout << "Tree empty\n";
I have a left child right sibling as below:
10
* |
* 2 -> 3 -> 4 -> 5
* | |
* 6 7 -> 8 -> 9 */
I want to traverse from root to the last node, the traversal function is as below:
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child);
root = root->next;
}
}
As I understood, if the node has a child, then the pointer points to its child, otherwise points to the sibling (next). In this case, when the pointer points to element 6, it will go to the root->next element (which is NULL). However, the function can still be able to print the remaining element (5,7,8,9). Can any one help me explain how traverseTree works?
Here's the code to recreate the tree:
// CPP program to create a tree with left child
// right sibling representation.
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int data;
struct Node *next;
struct Node *child;
};
// Creating new Node
Node* newNode(int data)
{
Node *newNode = new Node;
newNode->next = newNode->child = NULL;
newNode->data = data;
return newNode;
}
// Adds a sibling to a list with starting with n
Node *addSibling(Node *n, int data)
{
if (n == NULL)
return NULL;
while (n->next)
n = n->next;
return (n->next = newNode(data));
}
// Add child Node to a Node
Node *addChild(Node * n, int data)
{
if (n == NULL)
return NULL;
// Check if child list is not empty.
if (n->child)
return addSibling(n->child, data);
else
return (n->child = newNode(data));
}
// Traverses tree in level order
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child);
root = root->next;
}
}
//Driver code
int main()
{
Node *root = newNode(10);
Node *n1 = addChild(root, 2);
Node *n2 = addChild(root, 3);
Node *n3 = addChild(root, 4);
Node *n4 = addChild(n3, 6);
Node *n5 = addChild(root, 5);
Node *n6 = addChild(n5, 7);
Node *n7 = addChild(n5, 8);
Node *n8 = addChild(n5, 9);
traverseTree(root);
return 0;
}
After executing traverseTree(root->child) the control flow will continue from the next line. You're not returning from the function, just calling another function from within this function.
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child); // First, if child exists, traverse child. No return statement following here.
root = root->next; // Next, traverse sibling
}
}
If you still have doubts it would do you good to read about the program flow when calling a function.
Update(completely irrelevant to the question): As requested by OP, solution using stack:
void traverseTree(Node * root)
{
if (root == NULL)
return;
stack<Node*> s;
s.push(root);
while (!s.empty())
{
Node* top = s.top();
cout << " " << top->data;
s.pop();
if (top->next) s.push(top->next);
if (top->child) s.push(top->child);
}
}
I wrote a function to delete a node with its value equals given key in a BST, I tried a simple example [5,3,6], and delete key = 3. But when I ran this code, 3 is not deleted.The output of this code:
root = 5 left = 3 right = 6
Why? Thanks!
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// delete key in the tree
TreeNode* deleteNode(TreeNode* root, int key) {
TreeNode* cur = root;
// find the node to delete
while(cur) {
if(cur->val == key) break;
if(cur->val > key) cur = cur->left;
else cur = cur->right;
}
if(!cur) return root;
// I want to delete the node of val 3 here
// here cur == root->left, I though when I do cur = 0, root->left will also be set to 0
if(!cur->left && !cur->right) {
assert(cur == root->left);
delete cur;
cur = 0;
}
if(root) cout << "root = " << root->val << endl;
// but root->left is not nullptr when I ran this, and 3 still exists
if(root->left) cout << "left = " << root->left->val << endl;
if(root->right) cout << "right = " << root->right->val << endl;
return root;
}
int main() {
TreeNode* root = new TreeNode(5);
TreeNode* l = new TreeNode(3);
TreeNode* r = new TreeNode(6);
root->left = l;
root->right = r;
deleteNode(root, 3);
}
The problem is that you have a dangling pointer. You need to set left in the "parent" node to NULL. Similarly, if you delete a node on the right, you need to set the parent's right pointer to NULL.
root->left is not a null pointer because you never set it to NULL. You set cur to NULL. AS such, you go on to dereference a deleted pointer, which is undefined behavior. In your case, the memory previously allocated for the left node has remain unchanged and appears to still be there when you query it.
I'm having a hard time to get the insert function to work correctly. The cout statement isn't matching the one for my assignment. If I try to insert 5, I get inserted: 5 right child of: 3 but it should be inserted: 5 right child of: 22 Can someone help me out?
Node* insert(Node *root, int value){
Node *tmp = root;
while(tmp != NULL){
if (tmp->key == value){
return tmp;
}
else if (value > tmp->key){
Node *tm = new Node(NULL, NULL, NULL);
tm->key = value;
tm->left = tmp->right;
tm->right = tmp->left;
tmp->right = tm;
cout << "inserted: " << tm->key << " right child of: " << tmp->key <<endl;
tmp = tmp->right;
}
else if (value < tmp->key){
Node *tm = new Node(NULL, NULL, NULL);
tm->key = value;
tm->left = NULL;
tm->right = NULL;
tmp->left = tm;
cout << "inserted: " << tm->key << " left child of: " << tmp->key <<endl;
tmp = tmp->left;
}
}
return tmp;
}
There are a few problems with your insertion code:
You always insert the new node as a child of the root (which does not always produce a BST)
When you link your tree, you either (if you place as right child) make the left child of the root also the left child of the new node, or (if left child) lose track of the original left subtree of root.
What happens if root is NULL
The following code should work for you
//The following code assumes the following definition of Node
struct Node {
Node(int val, Node* l, Node* r):key(val),left(l),right(r){}
int key;
Node* left;
Node* right;
}
// Returns the root of the tree after inserting val into tree (no duplicates)
Node * insert (Node * root, int val){
if (root == NULL) return new Node(val, NULL, NULL);
if (root->key == val) return root;
if (root->key > val) return insert(root->left, val);
return insert(root->right, val);
}
The above code defines insert recursively. Base case : tree is empty. Insert new value as the root. If the root is the key then you're done (no duplicated keys). Otherwise, insert the value into the left or right subtree (left if value is less than root->key or right otherwise).
Or you can define insert iteratively using a while loop.
Node * insert (Node * root, int val){
// is this an empty tree?
if (root == NULL) return new Node(val, NULL, NULL);
Node* tmp = root;
while (tmp != null){
if (tmp->key == val) break;
if (tmp->key > val){
if (tmp->left == NULL){
tmp->left = new Node(val, NULL, NULL);
break;
} else {
tmp = tmp->left;
}
} else {
if (tmp->right == NULL){
tmp->right = new Node(val, NULL, NULL);
break;
} else {
tmp = tmp->right;
}
}
}
return root;
}
In either case you can use insert the same way.
Node * tree1 = NULL;
tree1 = insert(tree1, 3);
tree1 = insert(tree1, 1);
tree1 = insert(tree1, 2);
tree1 = insert(tree1, 4);
Aftewards tree1 will be the following tree.
3
/ \
1 4
\
2
I was trying to implement a simple Binary Search Tree for practice. I tried to just add values and print the values in the nodes. However, I am not getting the proper ascending order of values in the nodes. Here is what I have:
struct Node
{
int data;
Node* leftN;
Node* rightN;
};
typedef Node* Node_ptr;
Node_ptr head;
//INSERT_VALUE FUNCTION
Node* insert_value(Node_ptr leaf, int key)
{
//Root case when there is no set value yet
if(leaf == NULL)
{
leaf = new Node;
head = leaf;
cout << "Make the first node" << endl;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
//Left child Node
if(key < leaf->data)
{
//Search for a spot in the tree to add a Node (left value < root value < right value)
//This is only true for the left child Node
if(leaf->leftN != NULL)
insert_value(leaf, key);
//We have found a spot in the tree to add a new Node and add the value of key
else
{
cout << "Insert-left" << endl;
leaf->leftN = new Node;
leaf = leaf->leftN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
//Right child Node
else if(key >= leaf->data)
{
//Search for a spot to add a new Node in the tree (only amongst the right child Nodes)
if(leaf->rightN != NULL)
insert_value(leaf, key);
//Once we have found a spot to add a new Node, append the new Node
else
{
cout << "Insert-right" << endl;
leaf->rightN = new Node;
leaf = leaf->rightN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
}
//PRINT FUNCTION
void printTree(Node_ptr leaf)
{
if(leaf == NULL)
return;
printTree(leaf->leftN);
cout << "Data element: " << leaf->data << endl;
printTree(leaf->rightN);
}
//MAIN
int main()
{
Node_ptr root = NULL;
int i;
//initialize values
for(i = 1; i < 12; i+=2)
root = insert_value(root, i);
root = head;
for(i = 0; i < 11; i+=2)
root = insert_value(root, i);
root = head;
printTree(root);
root = head;
cout << "Head Node: " << root->data << endl;
return 0;
}
When I printed the results, this is what I got:
0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11 and the value of the head node is 1
Because you are calling the insertion as:
root = insert_value(root, i);
the location at which you insert is always using a subtree starting at the last insertion. Except the time that you re-start to add the odd numbers, when you start inserting at the head.
If you create a class BinarySearchTree that contains a head pointer, and an insert method taking an int value that calls Node::insert( head, value ), then you can just call insert on that class, without passing it a node, and it can always see to it that the insertions use the root of the tree for the start of the recursion.
Just me, but I would have a constructor for Node that takes an int and initializes the pointers to NULL. That way you don't have to do that in the insert method.
In the leaf->node? != NULL case, I think instead of calling
insert_value(leaf, key);
you want to say
leaf->node? = insert_value(leaf->node?, key)
where ? is either L or R, of course.
Something you might consider is adding a comment to the method like so:
// Adds the given key to the (sub-)tree rooted at node* then returns the new root
// of that (sub-)tree.
node *insert_value_and_return_root(node *root, int value) { ... }