Removing All Leaves from a BinaryTree - java

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.

Related

Does not remove last item in Boolean remove(object o) method

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.

how to check if a tree is complete?

this is my class of A binary search tree:
public class BinarySearchTree {
class BSTNode {
int data;
BSTNode rchild;
BSTNode lchild;
//constructor
public BSTNode(int n){
data=n;
lchild=rchild=null;
}
}
private BSTNode root;
private int size;
public BinarySearchTree() {
root = null;
size = -1;
}
public boolean insert(int n) {
if (root == null)
root = new BSTNode(n);
else
insert(n, root);
return true;
}
private void insert(int n, BSTNode r) {
if (r.data > n)
if (r.lchild == null)
r.lchild = new BSTNode(n);
else
insert(n, r.lchild);
else
if (r.data < n)
if (r.rchild == null)
r.rchild = new BSTNode(n);
else
insert(n, r.rchild);
}
}
Actually I am finding a difficulty in writing a method that checks if my tree is a Complete Binary Tree. Can someone provide me with the solution please.
I will follow this definition:
Complete binary tree : Every level except the last level is completely filled and all the nodes are left justified.
You're going to have to modify this a bit for your your implementation of BSTNode, but I believe this should fit your needs. The basic idea is to recursively traverse the tree and make sure that the "complete" property is fulfilled for each subtree.
boolean checkBinaryTreeCompleteness(TreeNode root) {
if (root != null) {
if (root.right == null && root.left == null) {
return true;
}
if (root.right != null && root.left != null) {
return checkBinaryTreeCompleteness(root.left) && checkBinaryTreeCompleteness(root.right);
}
}
return false;
}

Searching in Pre Order Traversal way

I have a binary search tree. I know how to search using the search property. But my task is to search the tree without using search property.(Say, search in binary tree) This is how I have to search.
1. If you find the value in the current node return it.
2. else search in right. If not found in right, then search in left
3. If not found in the whole tree return null.
This is what i tried.
public Node search(int val)
{
Node target = this;
if(target.getVal() == val)
return this;
else if(target.getRight() == null && target.getLeft() == null)
return null;
if(target.getRight() != null)
{
return target.getRight().search(id);
}
if(target.getLeft() != null)
{
return target.getLeft().search(id);
}
return null;
}
Problem with my code is, if right child exists and val is not found in right I'm getting null value. (Not searching in left). How to resolve this?
public Node search(int val)
{
Node target = this;
if(target.getVal() == val)
return this;
else if(target.getRight() == null && target.getLeft() == null)
return null;
if(target.getRight() != null)
{
return target.getRight().search(id); //here lies the problem
}
if(target.getLeft() != null)
{
return target.getLeft().search(id);
}
return null;
}
The problem in your code is that you are returning the result of search in right subtree of the node being searched.
Here's the updated code
public Node search(int val)
{
Node target = null;
if(this.getVal() == val)
{
return this;
}
else if(this.getRight() == null && this.getLeft() == null)
return target;
if(this.getRight() != null)
{
target = this.getRight().search(id);
}
if(target==null && this.getLeft() != null)
{
target = this.getLeft().search(id);
}
return target;
}
This is untested code, but I'd change your logic a bit:
public Node search(int val)
{
if(this.getVal() == val)
return this;
if (this.getRight() != null) {
Node right = this.getRight().search(id);
if (right != null)
return right;
}
if (this.getLeft() != null) {
Node left = this.getLeft().search(id);
if (left != null)
return left;
}
return null;
}
In your version you are returning a solution with the sole requirement that the node on the right or left is not null. You have to return a solution only if a solution is found.

Iterate through binary search tree to find all leaves

I am pretty new to trees, and I am trying to create kind of a "leaf iterator". I'm thinking it should put all nodes that does not have a .left and .right value onto a stack, but I'm not sure how or even if it's the right thing to do. I have tried searching for it, but every example I come over starts with going to the leftmost leaf, and going p = node.parent, and I am avoiding linking to the node's parent.
I don't understand how I can repeatedlty start from the root and go through the vines without visiting the same vines over and over.
EDIT
I see people suggests using a recursive method to solve this, and I agree now. But I have been banging my head trying to find the solution for an iterator-class-way to do this for a while, and I still would like to know if that's possible, and how!
Use recursion:
public void visitNode(Node node) {
if(node.left != null) {
visitNode(node.left);
}
if(node.right != null) {
visitNode(node.right);
}
if(node.left == null && node.right == null) {
//OMG! leaf!
}
}
start it by supplying root:
visitNode(root);
In order to translate this into an Iterator<Node> you'll have to translate recursion to loop and then to traversal with state. Non-trivial, but should give you a lot of fun.
class Node {
public Node left = null;
public Node right = null;
// data and other goodies
}
class Tree {
public Node root = null;
// add and remove methods, etc.
public void visitAllLeaves(Node root) {
// visit all leaves starting at the root
java.util.Stack<Node> stack = new java.util.Stack<Node>();
if (root == null) return; // check to make sure we're given a good node
stack.push(root);
while (!stack.empty()) {
root = stack.pop();
if (root.left == null && root.right == null) {
// this is a leaf
// do stuff here
}
if (root.left != null) {
stack.push(root.left);
}
if (root.right != null) {
stack.push(root.right);
}
}
}
}
I'm not sure if the above code works, but that's somewhere along the lines of what needs to be done. Another option is javax.swing.TreeModel (half-joking).
Here is how one could implement an Iterator that would only return the leaf nodes, i.e. nodes without a left or right subtree.
The iterator searches for leaf nodes in the tree by doing a depth-first search, remembering the current state of the search in a stack and "pausing" when it has found a leaf node (see fetchNext() method).
The search is resumed when the client "consumes" the leaf node by calling next().
class Node {
public Node left;
public Node right;
}
class LeaveIterator implements Iterator<Node> {
private final Stack<Node> stack = new Stack<>();
private Node nextNode = null;
public LeaveIterator(Node root) {
if (root != null) {
stack.push(root);
nextNode = fetchNext();
}
}
private void fetchNext() {
Node next = null;
while (!stack.isEmpty() && next == null) {
Node node = stack.pop();
if (node.left == null && node.right == null) {
next = node;
}
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return next;
}
public boolean hasNext() {
return nextNode != null;
}
public Node next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Node n = nextNode;
nextNode = fetchNext();
return n;
}
public void remove() {
throw new UnsupportedOperationException();
}
}

How do I remove the leaves of a binary tree?

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;
}

Categories

Resources