I'm attempting to write a method that would remove node from BST by the given value and I need it to return this deleted value. I found assorted examples of recursive implementations, but because of their nature, they can't return deleted node, but rather the root. Here's what I have now
public TreeNode remove(TreeNode node, int data) {
if (null == node) {
return null;
}
if (data < node.st.getkey()) {
node.left = remove(node.left, data);
} else if (data > node.st.getkey()) {
node.right = remove(node.right, data);
} else { // case for equality
if (node.left != null && node.right != null) {
TreeNode minInRightSubTree = min(node.right);
copyData(node , minInRightSubTree);
node.right = remove(node.right, minInRightSubTree.st.getkey());
} else {
if (node.left == null && node.right == null) {
node = null;
} else {// one child case
TreeNode deleteNode = node;
node = (node.left != null) ? (node.left) : (node.right);
deleteNode = null;
}
}
}
return node;
}
Can I come up with some hack to make it return deleted node or should I look into iterative algorithm( and if so I would really appreciate it if you could hook me up with the link).
You can return not just root but a pair of root and deleted node (or null if nothing was deleted).
You can use Map.Entry or new class to store 2 fields (I would recommend new class since it's more descriptive).
So your possible new signature will be public Map.Entry<TreeNode, TreeNode> remove(TreeNode node, int data)
Related
Could you tell me why this code wont delete a node in a BST? Is there any logical error in my code?
// To delete a node from the BST
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) return null;
else if (toDel < myRoot.data) myRoot.left = deleteNode(myRoot.left, toDel);
else if (toDel > myRoot.data) myRoot.right = deleteNode(myRoot.right, toDel);
else {
// Leaf node
if (myRoot.right == null && myRoot.left == null) {
myRoot = null;
} else if (myRoot.left == null) { // No left child
myRoot = myRoot.right;
} else if (myRoot.right==null){ // No right child
myRoot = myRoot.left;
}
}
return myRoot;
}
NOTE :- This code only deletes the nodes with one child or no child. I am currently working on deleting a node with 2 children so please dont solve that for me.
If 0 children, simply delete node (return null for it).
If there is 1 child, simply replace the node with the child that is not null.
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) {
return null;
} else if (myRoot.data == toDel) {
if (myRoot.left != null) {
return myRoot.left;
} else if (myRoot.right != null) {
return myRoot.right;
} else {
return null;
}
}
...
return myRoot;
}
I wrote the following code for finding the height of the binary tree, this is wrong, its failing the test cases, but why it is wrong, how to prove logically that this is wrong?
// WRONG CODE
public static int height(Node root) {
if(root != null){
if(root.left != null && root.right != null){
return Math.max(height(root.left), height(root.right)) + 1;
}else if(root.left != null){
return height(root.left);
}else{
return height(root.right);
}
}
return 0;
}
Whereas this following code is right!!
//RIGHT WORKING CODE
public static int height(Node root) {
if(root != null){
if(root.left != null || root.right != null){
return Math.max(height(root.left), height(root.right)) + 1;
}
}
return 0;
}
What is the big difference between the two codes that makes one of them right and other the wrong one?
For clarity the class code for the Node is added here.
class Node {
Node left;
Node right;
int data;
Node(int data) {
this.data = data;
left = null;
right = null;
}
}
And this is the logic to insert a node into the binary tree.
public static Node insert(Node root, int data) {
if(root == null) {
return new Node(data);
} else {
Node cur;
if(data <= root.data) {
cur = insert(root.left, data);
root.left = cur;
} else {
cur = insert(root.right, data);
root.right = cur;
}
return root;
}
In the second and third cases (just a left node, or just a right node) you're not adding one to account for the node you're currently on.
By the way your code also has a potential bug, in that it's possible for both left and right to be null. Your height function can handle null so really none of this checking is necessary, except for the check on the first line of the height function itself. But if it's important to check for null in the second case, then you should check for null in the third case too.
So I've been trying to insert or add a node to a BST recursively and I'm stumped. I keep getting
Exception in thread "main" java.lang.StackOverflowError
which I'm assuming is being caused by the recursion, but I don't exactly know where to go from here and would love some direction if anyone could help provide it. :)
public void add(Type obj) {
TreeNode<Type> newNode = new TreeNode<Type>(obj);
if (root == null) {
root = newNode;
} else {
addNode(root, newNode);
}
}
private void addNode(TreeNode<Type> current, TreeNode<Type> newNode) {
current = root;
if (current == null) {
current = newNode;
} else if (newNode.getValue().compareTo(current.getValue()) < 0) {
if (current.getLeft() == null) {
current.setLeft(newNode);
} else {
addNode(current.getLeft(), newNode);
}
} else if (newNode.getValue().compareTo(current.getValue()) > 0) {
if (current.getRight() == null) {
current.setRight(newNode);
} else {
addNode(current.getRight(), newNode);
}
}
}//end add
private void addNode(TreeNode<Type> current, TreeNode<Type> newNode) {
current = root;
if (current == null) {
current = newNode;
} else if (newNode.getValue().compareTo(current.getValue()) < 0) {
if (current.getLeft() == null) {
current.setLeft(newNode);
} else {
addNode(current.getLeft(), newNode);
}
Look you are again and again setting the current point equal to root. Which causes StackOverFlow, you should not point to root. You can change it like this: You need to remove this line:
current = root
if(root == null){
root = newNode;
return;
}
First, you're assigning current = root; and then on the next line you're checking:
if (current == null)
This condition will always return false (assuming root is not null).
What you're doing inside the "else if"s is good but you should remove the first if part.
Second, you need to handle the case in which root is null, better do it in a separate method that first check if root is null and only if it's not - calls this method (addNode) with root and the inserted node
I am doing an assignment, implementing own Binary Search Tree. The thing is, we have our own implementation of Node its parent is not directly accessible.
I have searched for answers, but I do not want to copy the solution entirely and I still don't seem to get it right, though. I miss some cases when the element is not removed.
Can you please help what am I doing wrong?
This is the remove method:
void remove(E elem) {
if(elem != null){
if (root != null && contains(elem)) {
removeFromSubtree(elem, root, null);
}
}
}
void removeFromSubtree(E elem, Node<E> current, Node<E> parent) {
if(elem.less(current.contents)){
if(current.left == null) return ;
removeFromSubtree(elem, current.left, current);
} else if(elem.greater(current.contents)){
if(current.right == null)return;
removeFromSubtree(elem, current.right, current);
} else {
if(current.left != null && current.right != null){
//both children
if(parent == null){
Node<E> n = new Node<>(null, null);
n.left = root;
removeFromSubtree(root.contents, n, null);
root = n.left;
root.setParent(null);
}
E min = subtreeMin(current.right);
current.contents = min;
removeFromSubtree(min, current.right, current);
} else if(current.left != null){
//left child
if (parent == null) {
root = current.left;
current.left.setParent(null);
return ;
}
setParentChild(current, parent, current.left);
} else if(current.right != null){
//right child
if (parent == null) {
root = current.right;
current.right.setParent(null);
return ;
}
setParentChild(current, parent, current.right);
} else {
if (parent == null) {
root = null;
return ;
}
setParentChild(current, parent, null);
}
}
}
Nodes use generic interface
class Node<E extends DSAComparable<E>>
which has just methods for comparation. It looks like this
interface DSAComparable<E extends DSAComparable<E>> {
boolean less(E other);
boolean greater(E other);
boolean equal(E other);
}
I use another methon inside remove that sets node's parent's child, depending if its left child or right child.
void setParentChild(Node<E> node, Node<E> parent,Node<E> value){
if(parent!= null){
if (parent.left == node) {
parent.left = value;
} else {
parent.right = value;
}
if(value!= null) value.setParent(parent);
}
}
Method subtreeMin(Node node) finds the smallest value in a subtree (the most left one)
Understanding your code is not so easy, since it still lacks of details.
I would refer to such an implementation of the Binary Search Tree that you can find online.
See for instance the one from Algorithms, 4th Ed..
I have a Binary Search Tree that contains nodes. Each node contains a key value and data value, and the nodes are sorted by key. I am trying to write a method to remove an object from my BST provided a key. Here is the code:
public Object remove(Comparable theKey) {
return remove(theKey, rootPtr).data;
}
public Node remove(Comparable theKey, Node node) {
Object o;
if(node == null)
return node;
if(theKey.compareTo(node.key) < 0) {
// go to left subtree
node.leftChild = remove(theKey, node.leftChild);
}else if(theKey.compareTo(node.key) > 0) {
//go to the right subtree
node.rightChild = remove(theKey, node.rightChild);
}else if(theKey.compareTo(node.key) == 0) {
if(node.leftChild != null && node.rightChild != null){
Node foundNode = findMin(node.rightChild);
node.key = foundNode.key;
node.data = foundNode.data;
node.rightChild = remove(node.key, node.rightChild);
}else{
if(node.leftChild != null){
node = node.leftChild;
}else{
node = node.rightChild;
}
}
}
numNodes--;
return node;
}
I would like to return the data value associated with the DELETED node. The issue I have is that: in the public Object remove() method, wouldn't the returned value always be the data value of the root node? I believe this would occur because the final returned call from the second method would be a reference to the rootPtr (root pointer). If this is the case, how can I save the data from the deleted node?
The simplest solution seems to be to add an output parameter than hands back the result:
public Object remove(Comparable theKey) {
Object[] result = new Object[1];
rootPtr = remove(theKey, rootPtr, result); // fix for deletion from a one-node tree
return result[0];
}
public Node remove(Comparable theKey, Node node, Object[] result) {
if(node == null) {
return node;
}
int diff = theKey.compareTo(node.key);
if (diff < 0) {
node.leftChild = remove(theKey, node.leftChild, result);
} else if (diff > 0) {
node.rightChild = remove(theKey, node.rightChild, result);
} else {
result[0] = node.key;
if (node.rightChild == null) {
node = node.leftChild;
} else if (node.leftChild == null) {
node = node.rightChild;
} else {
Node foundNode = findMin(node.rightChild);
node.key = foundNode.key;
node.data = foundNode.data;
node.rightChild = remove(node.key, node.rightChild, new Object[1]);
}
numNodes--;
}
return node;
}
Returning the found node doesn't work without significant changes because the return parameter is used to replace nodes as needed, and in the case where the found node has two children, you'd need to make a copy or insert a new node. Handling the case where the root node gets removed would be an issue, too.
p.s. I am assuming this is not a "trick question" and you can't just return theKey -- which has to equal the found key after all :)
You have to return the value, that you are receiving from the recursive remove-call.
p.ex:
if(theKey.compareTo(node.key) < 0) {
// go to left subtree
return remove(theKey, node.leftChild);
}else if ...
Now you will run throught the tree, until you find the correct node and that node will be given to the node which is the parent of the node to remove, and the parent will than give it to his parent and so on, until the root will return the node to his caller.