This removes almost all of what is supposed to, except for the last item.
This is what I get back when I submit it:
Input: [thing, word, stuff, and, both, zoo, yes]
----------Expected size: 0 BST actual number of nodes: 1
Invalid tree after removing thing
Code Below:
#SuppressWarnings("unchecked")
public boolean remove(Object o) {
Node n = root;
while (n != null) {
int comp = n.value.compareTo(o);
if (comp == 0) {
size--;
remove(n);
return true;
} else if (comp > 0) {
n = n.left;
} else {
n = n.right;
}
}
return false;
}
private void remove(Node root) {
if (root.left == null && root.right == null) {
if (root.parent == null) {
root = null;
} else {
if (root.parent.left == root) {
root.parent.left = null;
} else {
root.parent.right = null;
}
}
} else if (root.left == null || root.right == null) {
Node child = root.left;
if (root.left == null) {
child = root.right;
}
if (root.parent == null) {
root = child;
} else if (root.parent.left == root) {
root.parent.left = child;
} else {
root.parent.right = child;
}
child.parent = root.parent;
} else {
Node successor = root.right;
if (successor.left == null) {
root.value = successor.value;
root.right = successor.right;
if (successor.right != null) {
successor.right.parent = root;
}
} else {
while (successor.left != null) {
successor = successor.left;
}
root.value = successor.value;
successor.parent.left = successor.right;
if (successor.right != null) {
successor.right.parent = successor.parent;
}
}
}
}
Removal of a node in a Binary-search-tree consists of the following steps:
Find the node
You need to make sure that you have a function which is used for searching in order to find the node to be removed.
Handle the node's subtree
If the node has less than two children, then the subtree can be trivially changed. If there is a child, then the current node will be replaced by its child. Otherwise, if there are two children of the node to be removed, then you will just need to replace the node to be removed with the rightmost node of the left subtree or the leftmost node of the right subtree of the element to be removed.
Ensure that if you have replaced your current node with something else, then the other node will not exist as a duplicate.
In order to achieve this you will need methods like:
- search
- find leftmost/rightmost node of subtree
- remove
Your current code is over-complicated. I would rewrite it using atomic methods.
Related
I'm trying to remove the root of my binary search tree so I can update it's value, but this method can't do it. My idea is to remove the root, and then insert it again in the binary search tree but with another value. It works with every Node in the tree, but not the root cause I cannot delete it. Anyone knows why this happens? Thanks.
public V remove(K key) {
Node node = remove(key, root);
return node.value;
}
private Node remove(K key, Node current) {
if (current == null) {
return null;
}
if (current.key.equals(key)) {
if (current.left == null && current.right == null) {
return null;
}
else if (current.left == null && current.right != null) {
return current.right;
} else if (current.left != null && current.right == null) {
return current.left;
} else {
Node plowest = current.right;
Node parent = current;
while (plowest.left != null) {
parent = plowest;
plowest = plowest.left;
}
plowest.left = current.left;
if (plowest != current.right) {
parent.left = plowest.right;
plowest.right = current.right;
}
return plowest;
}
}
if (key.compareTo(current.key) < 0) { // Subarbre esquerra
current.left = remove(key, current.left);
} else {// Subarbre dret
current.right = remove(key, current.right);
}
return current;
}
And this is the main code where I call the method to delete any Node, in this case I would like to delete the root.
public static void main(String[] args) {
BSTMapping<String, Integer> arbre = new BSTMapping();
arbre.put("G", 4);
arbre.put("A", 1);
arbre.put("C", 2);
arbre.remove("G");
Iterator it = arbre.iterator();
while (it.hasNext()) {
BSTMapping.Pair p = (BSTMapping.Pair) it.next();
System.out.println(p.getKey() + " - " + p.getValue());
}
}
When removing root, remove(K key, Node current) never reaches the bottom where it would assign a node to current.left or current.right. You can address this in remove(key) by assigning directly to the root variable when appropriate.
public V remove(K key) {
Node node = remove(key, root);
if (root.key.equals(key)) {
root=node;
}
return node.value;
}
I am wondering how I can switch my remove method from being recursive to being iterative. My recursive method is working perfectly fine, but all my attempts at making it iterative are not. Where am I going wrong and how can I fix it?
So here's my recursive method:
public boolean remove(E someElement) {
return remove(root, someElement);
}
private boolean remove(Node<E> node, E dataItem) {
if (node == null) {
return false;
}
int val = dataItem.compareTo(node.data);
if (val < 0)
return remove(node.left, dataItem);
else if (val > 0)
return remove(node.right, dataItem);
else
return false;
}
BST manipulation is much easier to do iteratively in C/C++ than in Java because of the possibility to get a pointer to a variable.
In Java, you need to treat differently the case where the element is found at the root; in all other cases the node you're considering is either at the left or at the right of it's parent; so you can replace C's pointer (or reference) to pointers with the parent node and a boolean indicating at which side of the parent the current node is:
public boolean remove(E someElement) {
if (root == null) {
return false;
}
int val = someElement.compareTo(root.data);
if (val < 0) {
return remove(root, false, someElement);
} else if (val > 0) {
return remove(root, true, someElement);
} else {
root = removeNode(root);
return true;
}
}
private boolean remove(Node<E> parent, boolean right, E dataItem) {
Node<E> node = right ? parent.right : parent.left;
if (node == null) {
return false;
}
int val = dataItem.compareTo(node.data);
if (val < 0) {
return remove(node, false, dataItem);
} else if (val > 0) {
return remove(node, true, dataItem);
} else {
node = removeNode(node);
if (right) {
parent.right = node;
} else {
parent.left = node;
}
return true;
}
}
I have omitted method removeNode for the time being, right now, we can make the second method iterative:
private boolean remove(Node<E> parent, boolean right, E dataItem) {
while (true) {
Node<E> node = right ? parent.right : parent.left;
if (node == null) {
return false;
}
int val = dataItem.compareTo(node.data);
if (val < 0) {
right = false;
} else if (val > 0) {
right = true;
} else {
node = removeNode(node);
if (right) {
parent.right = node;
} else {
parent.left = node;
}
return true;
}
parent = node;
}
}
Now the method removeNode must remove the top node and return the new top node after removal. If either left or right is null, it can just return the other node, otherwise, we must find a node to replace the topnode, and it can be either the rightmost node of the left subtree, or the leftmode node of the right subtree.
private Node<E> removeNode(Node<E> parent) {
if (parent.left == null) {
return parent.right;
} else if (parent.right == null) {
return parent.left;
}
boolean right = random.nextBoolean();
Node<E> node = right ? parent.right : parent.left;
Node<E> last = removeLast(node, !right);
if (last == null) {
if (right) {
node.left = parent.left;
} else {
node.right = parent.right;
}
return node;
} else {
last.left = parent.left;
last.right = parent.right;
return last;
}
}
private Node<E> removeLast(Node<E> parent, boolean right) {
Node<E> node = right ? parent.right : parent.left;
if (node == null) {
return null;
}
while (true) {
Node<E> next = right ? node.right : node.left;
if (next == null) {
break;
}
parent = node;
node = next;
}
if (right) {
parent.right = node.left;
node.left = null;
} else {
parent.left = node.right;
node.right = null;
}
return node;
}
I'll give you the algorithm, you can try to code it yourself.
You can use a Stack to iterate through the tree.
So here's how you iterate:
push the tree to stack
loop until the stack isn't empty
pop a node
Null check. If null then continue.
push the left and the right sub-tree onto the Stack
Now in the midst of the iteration, you simply need to check if the popped node is the one you are looking for.
Yes? Check if it has children or not.
Has children? Implement the children snatching logic as usual for recursive deletion
Doesn't have children (a.k.a. leaf node)? Simply assign it to null
Break
No? Continue iterating
Although I feel that Trees are by nature recursive and using recursion is simply a better choice in terms of boosting conceptual understanding of the general working principal of this data structure.
As noted in comments, remove as it is now does nothing, and can be safely replaced with return false;.
Assuming that in the else case you want to do something sensible, as in
private boolean remove(Node<E> node, E dataItem) {
if (node == null) {
return false;
}
int val = dataItem.compareTo(node.data);
if (val < 0)
return remove(node.left, dataItem);
else if (val > 0)
return remove(node.right, dataItem);
else
return do_something(node);
}
the standard strategy is to transform it into a tail recursion. Consolidate the multiple recursive calls into a single one, and make it a last statement in the function:
private boolean remove(Node<E> node, E dataItem) {
if (node == null) {
return false;
}
int val = dataItem.compareTo(node.data);
if (val == 0) {
return do_something(node);
}
if (val < 0)
node = node.left;
else
node = node.right;
return remove(node);
}
So far, just a rewrite to achieve a tail recursive form.
Now, any tail recursive function
foo(args) {
if (interesting_condition(args)) {
return do_something_important(args);
}
args = recompute_arguments(args);
return foo(args);
}
could be mechanically transformed into iterative:
foo(args) {
while (!interesting_condition(args)) {
args = recompute_arguments(args);
}
return do_something_important(args);
}
I hope I answered your question.
This method is supposed to remove all leaves from a binary (no left and right branches) tree, but for some reason, it only removes one instance of a leaf from the binary tree. Why is that? I though the base case is responsible for severing the ties the parent node by setting parent.left or parent.right to null. If it isn't a leaf, it would recursively call until it hits a leaf.
Here is what I have so far:
private IntTreeNode overallRoot; // Beginning of the chain of nodes
// post: Removes All leaves from a tree
public void removeLeaves() {
if (overallRoot == null) { // If empty tree
return;
} else {
removeLeaves(overallRoot);
}
}
// helper for removeLeaves
private void removeLeaves(IntTreeNode root) {
if (root.left != null) { // tests left root
if (root.left.left == null && root.left.right == null) { // if next left node is leaf (base case)
root.left = null; // delete
} else if (root.left.left != null && root.left.right == null) { // If next right is empty
removeLeaves(root.left.left); // only check second left
} else if (root.left.right != null && root.left.left == null) { // If next left is empty
removeLeaves(root.left.right);
} else if (root.left.left != null && root.left.right != null) { // If next left/right isn't empty
removeLeaves(root.left.left);
removeLeaves(root.left.right);
}
}
if (root.right != null) {
if (root.right.left == null && root.right.right == null) { // if next left node is leaf (base case)
root.right = null; // delete
} else if (root.right.left != null && root.right.right == null) { // If next right is empty
removeLeaves(root.right.left); // only check second left
} else if (root.right.right != null && root.right.left == null) { // If next left is empty
removeLeaves(root.right.right);
} else if (root.right.left != null && root.right.right != null) { // If next left/right isn't empty
removeLeaves(root.right.left);
removeLeaves(root.right.right);
}
}
}
Here is the individual node class:
public class IntTreeNode {
public int data;
public IntTreeNode left;
public IntTreeNode right;
// constructs a leaf node with given data
public IntTreeNode(int data) {
this(data, null, null);
}
// constructs a branch node with given data, left subtree,
// right subtree
public IntTreeNode(int data, IntTreeNode left, IntTreeNode right) {
this.data = data;
this.left = left;
this.right = right;
}
}
Structural modification on trees is often cleaner when approached in a bottom-up manner:
public IntTreeNode removeLeaves(IntTreeNode root) {
if (root == null || root.isLeaf()) {
return null;
}
root.left = removeLeaves(root.left);
root.right = removeLeaves(root.right);
return root;
}
If in your recursive calls, instead of doing
removeLeaves(root.left.left);
you do
removeLeaves(root.left);
it should work. As Wallace points out in the comment, it looks like your're getting down two levels at a time. Also, the code could be reduced in the following way (the equivalent for the right tree)
if (root.left != null) { // tests left root
if (root.left.left == null && root.left.right == null) {
root.left = null; // delete
} else {
removeLeaves(root.left);
}
}
Take into account also that this do not solve the problem of a root being itself a leave!
It looks like you're looking too far ahead in each pass through the recursion. If the left has leaves, call removeLeaves(root.left). Do the same with the right. Then set left and right to null as needed.
I think this would do it:
public void removeLeaves(IntTreeNode root) {
if (root != null) {
removeLeaves(root.left);
removeLeaves(root.right);
root.left = null;
root.right = null;
}}
This will search the tree depth first and then remove the leaf nodes as encountered.
public class RemoveLeafNode {
public static void removeLeaves(Node root){
if(root!=null){
removeL(root.leftChild);
removeL(root.rightChild);
}
}
private static void removeL(Node node){
if(node==null){
return;
}
if(node.leftChild == null && node.rightChild == null){
node=null;//delete leaf
}
removeL(node.leftChild);
removeL(node.rightChild);
}
}
By using post-order traversal we can solve this problem (other traversals would also work).
struct BinaryTreeNode* removeLeaves(struct BinaryTreeNode* root) {
if (root != NULL)
{
if (root->left == NULL && root->right == NULL)
{
free(root);
return NULL;
}
else
{
root->left = removeLeaves(root->left);
root->right = removeLeaves(root->right);
}
}
return root;
}
Time Complexity: O(n). Where is number of nodes in tree.
I need to create a recursive method that takes as a parameter the root node of a binary search tree. This recursive method will then return the int value of the total number of inner nodes in the entire binary search tree.
This is what I have so far:
int countNrOfInnerNodes (Node node) {
if(node == null) {
return 0;
}
if (node.left != null && node.right != null){
return 1;
}
return countNrOfInnerNodes(node.left)+countNrOfInnerNodes(node.right)
}
}
Is there a better way? I also stuck to find a iterativ solution.
Here's the recursive method fixed:
int countNrOfInnerNodes (Node node) {
if(node == null) {
return 0;
}
if (node.left == null && node.right == null) {
// not an inner node !
return 0;
} else {
// the number of inner nodes in the left sub-tree + the number of inner
// nodes in the right sub-tree, plus 1 for this inner node
return countNrOfInnerNodes(node.left) + countNrOfInnerNodes(node.right) + 1;
}
}
Here's the iterative method:
int countNrOfInnerNodes(Node node) {
if (node == null)
return 0;
Stack<Node> nodesToCheck = new Stack<Node>();
nodesToCheck.push(node);
int count = 0;
while (!nodesToCheck.isEmpty()) {
Node checkedNode = nodesToCheck.pop();
boolean isInnerNode = false;
if (node.left != null) {
isInnerNode = true;
nodesToCheck.push(node.left);
}
if (node.right != null) {
isInnerNode = true;
nodesToCheck.push(node.right);
}
if (isInnerNode)
count++;
}
return count;
}
In a recent interview, I was asked this question.
Given a left-child, right sibling tree, find the first node in the tree that holds a true value. (first defined as on the highest level, answer could be implemented in either C++ or Java
My answer is below and I believe it works based on the test cases I have run so far. I was wondering if there is a more elegant solution. I'm using 3 queues right now and that does not seem optimal.
private class Node{
Node child;
Node sibling;
boolean data;
}
Node findFirstTrue(Node n)
{
if (n == null)
{
return null;
}
if (n.data == true)
{
return n;
}
Queue<Node> searchNextSibling = new ArrayDeque<Node>();
Queue<Node> searchNextChildren = new ArrayDeque<Node>();
searchNextSibling.add(n);
while(!searchNextSibling.isEmpty() || !searchNextChildren.isEmpty())
{
while(!searchNextSibling.isEmpty())
{
Node current = (test.Node) searchNextSibling.remove();
if (current.data == true)
{
return current;
}
if (current.sibling != null)
{
searchNextSibling.add(current.sibling);
}
if (current.child != null)
{
searchNextChildren.add(current.child);
}
}
Queue<Node> tempQueue = new ArrayDeque<Node>();
while (!searchNextChildren.isEmpty())
{
Node current = (test.Node) searchNextChildren.remove();
if (current.data == true)
{
return current;
}
if (current.sibling != null)
{
searchNextSibling.add(current.sibling);
}
if (current.child != null)
{
tempQueue.add(current.child);
}
}
searchNextChildren.addAll(tempQueue);
}
return null;
}
Here is a more concise solution written in C#, but would be almost identical to a java one:
private Node VisitSiblings(Node node, Queue<Node> q)
{
if (node == null || node.Flag) return node;
q.Enqueue(node);
return VisitSiblings(node.Sibling, q);
}
public Node ReturnFirstTrueNode(Node root)
{
Queue<Node> q = new Queue<Node>();
Node node = VisitSiblings(root, q);
if (node != null) return node;
while (q.Count > 0)
{
node = q.Dequeue();
Node x = VisitSiblings(node.Child, q);
if (x != null) return x;
}
return null;
}