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;
}
Related
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.
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.
I was doing an assignment in which I'm supposed to create a binary tree and define given functions from its abstract superclass (AbstractBinaryTree.java).
While working on a function called getNumbers() which is basically going to traverse through the whole tree whilst adding values from each node to an array list which it returns. There seems to be a null pointer in one of my if statements.
AbstractBinaryTree.java
import java.util.ArrayList;
public abstract class AbstractBinaryTree
{
protected Node root;
protected int sizeOfTree;
public AbstractBinaryTree()
{
root = null;
sizeOfTree = 0;
}
public int size(){ return sizeOfTree; }
/** compute the depth of a node */
public abstract int depth(Node node);
/** Check if a number is in the tree or not */
public abstract boolean find(Integer i);
/** Create a list of all the numbers in the tree. */
/* If a number appears N times in the tree then this */
/* number should appear N times in the returned list */
public abstract ArrayList<Integer> getNumbers();
/** Adds a leaf to the tree with number specifed by input. */
public abstract void addLeaf(Integer i);
/** Removes "some" leaf from the tree. */
/* If the tree is empty should return null */
public abstract Node removeLeaf();
// these methods are only needed if you wish
// use the TreeGUI visualization program
public int getheight(Node n){
if( n == null) return 0;
return 1 + Math.max(
getheight(n.getLeft()) , getheight(n.getRight())
);
}
public int height(){ return getheight(root); }
}
Node.java File.
public class Node{
protected Integer data;
protected Node left;
protected Node right;
public Node(Integer data)
{
this.data = data;
this.left = this.right = null;
}
public Node(Integer data, Node left, Node right){
this.data = data;
this.left = left;
this.right = right;
}
public Integer getData(){ return this.data; }
public Node getLeft(){ return this.left; }
public Node getRight(){ return this.right; }
public void setLeft(Node left){ this.left = left; }
public void setRight(Node right){ this.right = right; }
public void setData(Integer data){ this.data = data; }
}
BinaryTree.java
import java.util.ArrayList;
import java.util.*;
// Student Name: Adrian Robertson
// Student Number: 101020295
//
// References: Collier, R. "Lectures Notes for COMP1406C- Introduction to Computer Science II" [PDF documents]. Retrieved from cuLearn: https://www.carleton.ca/culearn/(Winter2016).//
// References: http://codereview.stackexchange.com/questions/13255/deleting-a-node-from-a-binary-search-tree
// http://www.algolist.net/Data_structures/Binary_search_tree/Removal
// http://www.geeksforgeeks.org/inorder-tree-traversal- without-recursion-and-without-stack/
public class BinaryTree extends AbstractBinaryTree
{
protected Node root = new Node(12);
public static BinaryTree create()
{
BinaryTree tempTree = new BinaryTree();
//creating all the nodes
Node temp10 = new Node(10);
Node temp40 = new Node(40);
Node temp30 = new Node(30);
Node temp29 = new Node(29);
Node temp51 = new Node(51);
Node temp61 = new Node(61);
Node temp72 = new Node(72);
Node temp31 = new Node(31);
Node temp32 = new Node(32);
Node temp42 = new Node(42);
Node temp34 = new Node(34);
Node temp2 = new Node(2);
Node temp61x2 = new Node(61);
Node temp66 = new Node(66);
Node temp3 = new Node(3);
Node temp73 = new Node(73);
Node temp74 = new Node(74);
Node temp5 = new Node(5);
//setting up the tree
if (tempTree.root.getData() == null)
{
tempTree.root.setData(12);
tempTree.root.setLeft(temp10);
tempTree.root.setRight(temp40);
}
temp10.setLeft(temp30);
temp30.setRight(temp29);
temp29.setRight(temp51);
temp51.setLeft(temp61);
temp51.setRight(temp72);
temp40.setLeft(temp31);
temp31.setLeft(temp42);
temp31.setRight(temp34);
temp34.setLeft(temp61x2);
temp61x2.setLeft(temp66);
temp61x2.setRight(temp73);
temp40.setRight(temp32);
temp32.setRight(temp2);
temp2.setLeft(temp3);
temp3.setRight(temp74);
temp74.setLeft(temp5);
return tempTree;
}
public int depth(Node node)
{
Node current = this.root;
int counter = 1;
while(node != current)
{
if (node.getData() > current.getData())
current = current.getRight();
if (node.getData() < current.getData())
current = current.getLeft();
}
return counter;
}
public boolean find(Integer i)
{
boolean found = false;
Node current = this.root;
if (i == current.getData())
found = true;
while (i != current.getData())
{
if (i > current.getData())
current = current.getRight();
if (i < current.getData())
current = current.getLeft();
if (i == current.getData())
found = true;
}
return found;
}
public ArrayList<Integer> getNumbers()
{
ArrayList<Integer> temp = new ArrayList<Integer>();
Node current = this.root;
Node Pre = new Node(null);
while (current.getData() != null )
{
if (current.getLeft().getData() == null)
{
temp.add(current.getData());
current = current.getRight();
}
else
{
/* Find the inorder predecessor of current */
Pre = current.getLeft();
while(Pre.getRight() != null && Pre.getRight() != current)
Pre = Pre.getRight();
/* Make current as right child of its inorder predecessor */
if (Pre.getRight() == null)
{
Pre.setRight(current);
current = current.getLeft();
}
/* Revert the changes made in if part to restore the original tree i.e., fix the right child of predecssor */
else
{
Pre.setRight(null);
temp.add(current.getData());
current = current.getRight();
}/* End of if condition Pre.right == NULL */
}/* End of if condition current.left == NULL*/
}/*End of while */
Collections.sort(temp);
return temp;
}
public void addLeaf(Integer i)
{
insert(this.root, i);
}
public static void insert(Node node, int value) //insert a node Based on provided argument where node is the root of tree
{
if (node == null)
{
Node first = new Node(value);
node = first;
}
else if (value < node.getData())
{
if (node.left != null)
{
insert(node.left, value);
}
else
{
System.out.println(" > Inserted " + value + " to left of node " + node.getData());
Node newNode = new Node(value);
node.left = newNode;
}
}
else if (value > node.getData())
{
if (node.right != null)
{
insert(node.right, value);
}
else
{
System.out.println(" > Inserted " + value + " to right of node " + node.getData());
Node newNode = new Node(value);
node.right = newNode;
}
}
}
public Node removeLeaf()
{
Node tempA = new Node(61); //create a new node with that value
deleteNodeBST(this.root, 61); //delete the node containing that leaf value
return tempA; //return the copy of that node
}
//delete given node with given value
public boolean deleteNodeBST(Node node, int data) {
ArrayList<Integer> temp = this.getNumbers();
if (node == null) {
return false;
}
if (node.getData() == data) {
if ((node.getLeft() == null) && (node.getRight() == null)) {
// leaf node
node = null;
return true;
}
if ((node.getLeft() != null) && (node.getRight() != null)) {
// node with two children
node.setData(temp.get(0));
return true;
}
// either left child or right child
if (node.getLeft() != null) {
this.root.setLeft(node.getLeft());
node = null;
return true;
}
if (node.getRight() != null) {
this.root.setRight(node.getRight());
node = null;
return true;
}
}
this.root = node;
if (node.getData() > data) {
return deleteNodeBST(node.getLeft(), data);
} else {
return deleteNodeBST(node.getRight(), data);
}
}
public static void main(String args[])
{
BinaryTree myTree = new BinaryTree();
myTree.create();
System.out.println(myTree.getNumbers());
}
}
The create function creates a binary tree and returns that binary tree. This is the predefined binary tree that I was supposed to create according to assignment guidelines. I understand that the tree values are not organised properly as they would be in a proper binary tree. Is that was causes the null pointer during traversal? Cause the traversal is taylored to work for a proper Binary tree.
In class BinaryTree, you initialize the left and right of your root node only if the haven't data. But the root node is create with data...
You should invert the condition in :
//setting up the tree
if (tempTree.root.getData() == null)
And add a test in getNumbers() :
if (current.getLeft() == null || current.getLeft().getData() == null)
In the BinaryTree class, getNumbers() method and while loop. Maybe your problem is here:
if (current.getLeft().getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
When you call current.getLeft(), it will return null when the left Node is null. And then, you call getData() it will throw a NullPointerException. If you're not sure that it always not null check it before you call any methods of it. Example you can change the if statement to:
if (current.getLeft() != null && current.getLeft().getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
Or:
Node left = current.getLeft();
if (left == null) {
//TODO something here
} else if (left.getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
Please update your getNumbers - method accordingly,
You need to put right checks before work with reference type.
public ArrayList<Integer> getNumbers()
{
ArrayList<Integer> temp = new ArrayList<Integer>();
Node current = this.root;
Node Pre = new Node(null);
while (current != null && current.getData() != null ) // Fix here... Add : current != null
{
if (current.getLeft() != null && current.getLeft().getData() == null) // Fix here... Add : current.getLeft() != null
{
temp.add(current.getData());
current = current.getRight();
}
else
{
/* Find the inorder predecessor of current */
Pre = current.getLeft();
while(Pre != null && Pre.getRight() != null && Pre.getRight() != current) // Fix here... Add : Pre != null
Pre = Pre.getRight();
/* Make current as right child of its inorder predecessor */
if (Pre != null && Pre.getRight() == null) // Fix here... Add : Pre != null
{
Pre.setRight(current);
current = current.getLeft();
}
/* Revert the changes made in if part to restore the original tree i.e., fix the right child of predecssor */
else
{
if(Pre != null){ // Fix here... Add : Pre != null
Pre.setRight(null);
}
temp.add(current.getData());
current = current.getRight();
}/* End of if condition Pre.right == NULL */
}/* End of if condition current.left == NULL*/
}/*End of while */
Collections.sort(temp);
return temp;
}
Been working on this for while with no luck. Hopefully someone can point in the right direction.
Code:
public class BST {
public BTNode<Integer> root;
int nonLeafCount = 0;
int depthCount = 0;
public BST() {
root = null;
}
class BTNode<T> {
T data;
BTNode<T> left, right;
BTNode(T o) {
data = o;
left = right = null;
}
public String toString() {
return String.valueOf(data);
}
}
}
The easy way to traverse a tree without recursive calls is to use a stack. Push the root on the stack, then enter a loop that - so long as the stack is not empty - pops a node from the stack and pushes the non-null children of that node. It's pretty obvious that this will eventually push every node onto the stack exactly once and pop it exactly once. Now all you need to do is count the popped nodes that have at least one child. Putting this together,
public int nonleaves() {
int nonLeafCount = 0;
BTNode<Integer> [] stack = new BTNode[2];
int p = 0;
stack[p++] = root; // push root
while (p != 0) {
BTNode<Integer> node = stack[--p]; // pop
if (node.left != null || node.right != null) ++nonLeafCount;
if (p + 1 >= stack.length) stack = Arrays.copyOf(stack, 2 * stack.length);
if (node.right != null) stack[p++] = node.right; // push right
if (node.left != null) stack[p++] = node.left; // push left
}
return nonLeafCount;
}
Note that in accordance with your description, I used a simple Java array for a stack, growing it by a factor of 2 whenever it fills up. Integer p is the stack pointer.
Also, this code assumes the root is non-null. If the root can be null, add a check at the start and return 0 in that case.
NB it's possible to traverse without even a stack by several methods, although at the cost of changing the tree during traversal. (It's back in its original shape when the traversal is complete.) The nicest IMO is Morris's algorithm, but all of them are considerably more complicated than the stack. Since it seems you're a new programmer, figure out the stack method first.
Edit
To find max depth:
public int maxDepth() {
int max = 0;
Pair<Integer> [] stack = new Pair[2];
int p = 0;
stack[p++] = new Pair(root, 1);
while (p != 0) {
Pair<Integer> pair = stack[--p];
if (pair.depth > max) max = pair.depth;
if (p + 1 >= stack.length) stack = Arrays.copyOf(stack, 2 * stack.length);
if (pair.node.right != null)
stack[p++] = new Pair(pair.node.right, 1 + pair.depth);
if (pair.node.left != null)
stack[p++] = new Pair(pair.node.left, 1 + pair.depth);
}
return max;
}
private static class Pair<T> {
BTNode<T> node;
int depth;
Pair(BTNode<T> node, int depth) {
this.node = node;
this.depth = depth;
}
}
Finally, I'd be remiss if I didn't point out that we can do some algebra on the algorithm to eliminate some tiny inefficiencies. You'll note that after the left child is pushed onto the stack, it is certain to be popped in the next loop iteration. The root push/pop is similar. We might as well set node directly. Also, there are some redundant comparisons. The details are too much for this note, but here is a reworked non-leaf counter (untested but ought to work fine):
public int nonleaves() {
int nonLeafCount = 0;
BTNode<Integer>[] stack = new BTNode[1];
int p = 0;
BTNode<Integer> node = root;
for (;;) {
if (node.left == null) {
if (node.right == null) {
if (p == 0) break;
node = stack[--p];
} else { // node.right != null
++nonLeafCount;
node = node.right;
}
} else { // node.left != null
++nonLeafCount;
if (node.right != null) {
if (p >= stack.length) {
stack = Arrays.copyOf(stack, 2 * stack.length);
}
stack[p++] = node.right;
}
node = node.left;
}
}
return nonLeafCount;
}
You can see that to eek out a tiny bit of efficiency we lose a lot of simplicity. This is almost always a bad bargain. I recommend against it.
A possible solution:
public class BST<T> {
public BTNode<T> root;
int depthCount = 0;
public BST() {
root = null;
}
public int nonleaves() { // Method must be declared like this. No
// parameters.
BTNode<T> current = root;
BTNode<T> previous = null;
int nonLeafCount = 0;
while (current != null) {
if (previous == current.parent) { // this includes when parent is
// null, i.e. current is the
// root.
previous = current;
if (current.left != null) {
nonLeafCount++;
current = current.left;
} else if (current.right != null) {
nonLeafCount++;
current = current.right;
} else {
current = current.parent;
}
} else if (previous == current.left) {
previous = current;
if (current.right != null) {
current = current.right;
} else {
current = current.parent;
}
} else {
// previous==current.right
previous = current;
current = current.parent;
}
}
return nonLeafCount;
}
private static class BTNode<T> {
BTNode<T> left, right, parent;
/* ... */
}
}
Using stacks:
public class BST2<T> {
public BTNode<T> root;
int depthCount = 0;
public BST2() {
root = null;
}
public int nonleaves() { // Method must be declared like this. No
// parameters.
BTNode<T> current = root;
BTNode<T> previous = null;
int nonLeafCount = 0;
MyStack myStack = new MyStack(); // New empty stack
while (current != null) {
if (previous == myStack.top()) { // this includes when stack is
// empty, i.e. current is the
// root.
myStack.push(current);
previous = current;
if (current.left != null) {
nonLeafCount++;
current = current.left;
} else if (current.right != null) {
nonLeafCount++;
current = current.right;
} else {
myStack.pop();
current = myStack.top();
}
} else if (previous == current.left) {
previous = current;
if (current.right != null) {
current = current.right;
} else {
myStack.pop();
current = myStack.top();
}
} else {
// previous==current.right
previous = current;
myStack.pop();
current = myStack.top();
}
}
return nonLeafCount;
}
private static class BTNode<T> {
BTNode<T> left, right;
/* ... */
}
}
I'm trying to remove all of the leaves. I know that leaves have no children, this is what I have so far.
public void removeLeaves(BinaryTree n){
if (n.left == null && n.right == null){
n = null;
}
if (n.left != null)
removeLeaves(n.left);
if (n.right != null)
removeLeaves(n.right);
}
n = null; won't help you, since n is just a local variable of your function. Instead, you'd need to set n.left = null; or n.right = null; on the parent.
I won't give you a complete solution, since this smells a lot like homework, but you could, for example, add a return value to your function to indicate whether the node in question is a leaf or not and take appropriate actions in the parent (after the call to removeLeaves).
It's much easier if you break this down like this:
public void removeLeaves(BinaryTree n){
if (n.left != null) {
if (n.left.isLeaf()) {
n.removeLeftChild();
} else {
removeLeaves(n.left);
}
}
// repeat for right child
// ...
}
isLeaf, removeLeftChild and removeRightChild should be trivial to implement.
Instead of n = null, it should be:
if(n.parent != null)
{
if(n.parent.left == n)
{
n.parent.left = null;
}
else if(n.parent.right == n)
{
n.parent.right == null);
}
}
Since Java passes references by values n = null; simply does not work. With this line n was pointing to the leaf and now points to nothing. So you aren't actually removing it from the parent, you are just rerouting a dummy local reference. For the solution do what Matthew suggested.
Here's a simple java method to delete leaf nodes from binary tree
public BinaryTreeNode removeLeafNode(BinaryTreeNode root) {
if (root == null)
return null;
else {
if (root.getLeft() == null && root.getRight() == null) { //if both left and right child are null
root = null; //delete it (by assigning null)
} else {
root.setLeft(removeLeafNode(root.getLeft())); //set new left node
root.setRight(removeLeafNode(root.getRight())); //set new right node
}
return root;
}
}
Easy method with recusrion .
public static Node removeLeaves(Node root){
if (root == null) {
return null;
}
if (root.left == null && root.right == null) {
return null;
}
root.left = removeLeaves(root.left);
root.right = removeLeaves(root.right);
return root;
}
/* #author abhineet*/
public class DeleteLeafNodes {
static class Node{
int data;
Node leftNode;
Node rightNode;
Node(int value){
this.data = value;
this.leftNode = null;
this.rightNode = null;
}
}
public static void main(String[] args) {
Node root = new Node(1);
Node lNode = new Node(2);
lNode.leftNode = new Node(4);
root.leftNode = lNode;
Node rNode = new Node(3);
rNode.rightNode = new Node(5);
root.rightNode = rNode;
printTree(root);
deleteAllLeafNodes(root, null,0);
System.out.println("After deleting leaf nodes::");
printTree(root);
}
public static void deleteAllLeafNodes(Node root, Node parent, int direction){
if(root != null && root.leftNode == null && root.rightNode == null){
if(direction == 0){
parent.leftNode = null;
}else{
parent.rightNode = null;
}
}
if(root != null && (root.leftNode != null || root.rightNode != null)){
deleteAllLeafNodes(root.leftNode, root, 0);
deleteAllLeafNodes(root.rightNode, root, 1);
}
}
public static void printTree(Node root){
if(root != null){
System.out.println(root.data);
printTree(root.leftNode);
printTree(root.rightNode);
}
}
}
This should work-
public boolean removeLeaves(Node n){
boolean isLeaf = false;
if (n.left == null && n.right == null){
return true;
//n = null;
}
if (n!=null && n.left != null){
isLeaf = removeLeaves(n.left);
if(isLeaf) n.left=null; //remove left leaf
}
if (n!=null && n.right != null){
isLeaf = removeLeaves(n.right);
if(b) n.right=null; //remove right leaf
}
return false;
}