Java pointer or node assignment understanding wrong? - java

A problem I'm solving is asking to insert a node inside a binary search tree, then return the root of the entire binary tree at the end.
The issue I seem to be having is saving the inserted node inside the original tree given it's root. My code is below:
static Node Insert(Node root,int value) {
insertAux(root, value);
return root;
}
static void insertAux(Node root, int value) {
if (root == null) {
root = new Node();
root.data = value;
root.left = root.right = null;
} else {
if (value > root.data) {
insertAux(root.right, value);
} else {
insertAux(root.left, value);
}
}
}
When I test this with the following tree:
4
/ \
2 7
/ \
1 3
it should result in:
4
/ \
2 7
/ \ /
1 3 6
I have tested this and my insertAux function does in fact assign root to a new Node() and the data for that node to the value 6 when it hits the null case at the end of the function. I have also tested and made sure that my Insert function returns the original root at the end of the entire call. However when I try to see if insertAux has assigned root.right.left to a new Node() and its data to 6 inside of the Insert function, I get a null pointer exception where root.right.left is null. Why is this, is my understanding of pointers or node assignment for Java wrong?

static Node insertAux(Node root, int value) {
if (root == null) {
root = new Node();
root.data = value;
root.left = root.right = null;
} else {
if (value > root.data) {
root.right = insertAux(root.right, value);
} else {
root.left = insertAux(root.left, value);
}
}
return root;
}
Your insertAux() method should be like this.
First of all it should have a return type as Node.
What your doing wrong here is that you are not creating a link between the parent node and child node. So in your case, a new Node with data 6 is created but it is actually never assigned to its parent.
So you need to assign the newly created node by returning it and assigning it to parent.In your method here
if (value > root.data) {
root.right = insertAux(root.right, value);
} else {
root.left = insertAux(root.left, value);
}

Java pass parameters by value (i.e not by reference), internal assignment to root is lost after return from function. Try return in different way, maybe
static Node insertAux(Node root, int value) {

Related

Clarification regrading Java pass-by-value

I am solving a coding question where we need to remove all the sub-trees of a binary tree that only has 0 as its value . Question link https://leetcode.com/problems/binary-tree-pruning/
The solution that worked for me is this
public TreeNode pruneTree(TreeNode root) {
if (root == null)
return null;
root.left = pruneTree(root.left);
root.right = pruneTree(root.right);
if (root.val == 0 && root.left == null && root.right == null)
root = null;
else
return root;
// pruneTree1(root);
// printTree(root);
return root;
}
The solution I tried submitting earlier was this
public TreeNode pruneTree(TreeNode root) {
pruneTree1(root);
return root;
}
TreeNode pruneTree1 (TreeNode root) {
if(root ==null)
return root ;
root.left = pruneTree1(root.left);
root.right = pruneTree1(root.right);
if(root.left==null && root.right==null && root.val==0) {
System.out.println(root.val);
root =null;
}
return root;
}
My question/doubt is why the second solution wasn't changing the original tree. My understanding was Java is pass by value but when we pass an Object by its variable name its a reference to original object and we can change its content.
Why was it not working in this case. Is it because I am trying to set the whole object as null and not just its value ?
I tired recreating the scenario with another example and the code behaves differently in this case . Here's what i tried
public void run1() {
TreeNode root = new TreeNode();
root.val = 2;
TreeNode left = new TreeNode();
left.val = 3;
TreeNode right = new TreeNode();
right.val = 4;
TreeNode leftLeft = new TreeNode();
leftLeft.val = 5;
TreeNode rightRight = new TreeNode();
rightRight.val = 6;
root.left = left;
root.right = right;
left.left = leftLeft;
right.right = rightRight;
System.out.println(root.left.left.val);
TreeNode root2 = makeNull(root);
System.out.println(root.left.left);
System.out.println(root2.left.left);
};
public TreeNode makeNull (TreeNode root){
if(root ==null)
return root ;
root.left = makeNull(root.left);
root.right = makeNull(root.right);
if(root.val==5)
root=null;
// left.left = null;
return root;
}
In the example i both root.left.left and root2.left.left is set as null when i print it . Why it acts like parameter is passed as reference in this case but not in the above example.
In the second example you nowhere worked with the result of pruneTree1(). But the parameter of that method never got modified for its caller (due to pass-by-value).
Update for your added example:
root.left and root2.left are referring to the same object. As root.left.val != 5 you also don't change that.
You assign root.left and root.right to the return value of the method, but return the input parameter in the most cases. So as long as you don't return null, the same objects are still referenced.

How to find a Node of a Binary Search Tree without using a recursive method

If I have a Method that only takes value as an argument (not Node) called public Node finder (E val) how can I find the respective Node regardless of the height and width of the tree. If the method took Node as an argument then it would be an easy solution to use recursion. But unfortunately I am not allowed to change the method signature. How can I do this the smart way rather than the dumb way I am trying below which would just end up with a ton of embedded if functions
public class BinarySearchTree<E extends Comparable<E>> {
class Node {
E value;
Node leftChild = null;
Node rightChild = null;
Node(E value) {
this.value = value;
}
}
public Node finder(E val) {
if (val == null) return null;
if (root == null) return null;
boolean flag = false;
Node temp = root;
//find if Root Node matches value
if(temp.value.compareTo(val) == 0) {
flag = true;
return temp;
}
//if value is less than root check the left branch
else if (temp.value.compareTo(val) > 0) {
if(temp.leftChild.value.compareTo(val) == 0) {
flag = true;
return temp.leftChild;
}
//more if statements here
}
//if value is more than root check the right branch
else {
if(temp.rightChild.value.compareTo(val) == 0) {
flag = true;
return temp.rightChild;
}
//more if statements here
}
return null;
}
}
Binary search trees have this interesting property:
The left subtree of a node contains only nodes with values lesser than the node’s value.
The right subtree of a node contains only nodes with value greater than the node’s key.
Assuming your class BinarySearchTree holds a reference to the root, you can traverse the binary tree iteratively till you either reach the value or reach a leaf node which means your value does not exist in your binary search tree. The time complexity of this search operation is O(log(n)).
Here's some pseudocode
Find-Node(val):
node = root
while node != null:
if val == node.val then return root
if val < node.val then node = node.left
if val > node.val then node = node.right
return null

Binary Tree: Node frequency count for 0, 1, or 2 children

I have an assignment:
You’re given the root node of a binary tree T. We distinguish between 3 types of nodes in T: nodes with 0 children, nodes with 1 child, and nodes with 2 children. Determine, for each type, the number of nodes in T. Return your result as an integer array of length 3.
I am given a Java file that generates random test cases for this algorithm.
I am only allowed to create one function to do all of this. I am not allowed to pass any additional parameters into the method below. I am also not allowed to make any other modifications outside of the function that I create.
In the file, there is a base case already inserted. I have been told to traverse the tree in post-order, using recursion.
I am aware of the current issues with my code. But I don’t know how to fix them.
My current code is as follows:
private static int[] problem1(Node root) {
int[] arr = new int[3];
if (root == null) {
return new int[] {
-1, // nodes with 0 children
-1, // nodes with 1 child
-1 // nodes with 2 children
};
}
//problem1(root.left);
//problem1(root.right);
if (root.left != null && root.right != null) {
arr[2]++;
problem1(root.left);
problem1(root.right);
} else if (root.left != null && root.right == null) {
arr[1]++;
problem1(root.left);
} else if (root.left == null && root.right != null) {
arr[1]++;
problem1(root.right);
} else {
arr[0]++;
}
return arr;
}
The Node class is defined as:
static class Node {
public int value;
public Node left;
public Node right;
}
class Playground {
public static void main(String[ ] args) {
Node root = new Node(1, new Node(2, null, null), new Node(3, null, null));
int[] counts = problem1(root);
System.out.println(counts[0]); // 2 node(s) with 0 children
System.out.println(counts[1]); // 0 node(s) with 1 children
System.out.println(counts[2]); // 1 node(s) with 2 children
}
// recursively count number of childs for each root/node. Post-order
// traversing means both left and right node will be traversed before
// any computations.
public static int[] problem1(Node root) {
// always need a base-case to stop recursive call.
if(root == null) {
return new int[]{0,0,0};
}
// post-order traversing
int[] leftChildCounts = problem1(root.left);
int[] rightChildCounts = problem1(root.right);
int [] counts = new int[]{0,0,0};
counts[0] = leftChildCounts[0] + rightChildCounts[0];
counts[1] = leftChildCounts[1] + rightChildCounts[1];
counts[2] = leftChildCounts[2] + rightChildCounts[2];
if(root.left == null && root.right == null) {
counts[0]++;
} else if(root.left != null && root.right != null) {
counts[2]++;
} else {
counts[1]++;
}
return counts;
}
}
public class Node {
int value;
Node left;
Node right;
public Node(int value, Node left, Node right) {
this.value = 0;
this.left = left;
this.right = right;
}
}
I think you've come pretty close, the only thing you should fix is handling the array of result.
Currently you create a new arr that is supposed to stored the results for every call of problem1 and its wrong because this new array has nothing to do with previously created arrays.
Consider to create it outside the call of problem1 method. You can always pass it as an additional parameter and "accumulate" the result (there is even a term called "accumulator" for this, so arr will be an accumulator).
Think also about the return result (hint: with the accumulator approach you don't really need to return anything)
Since its an assignment, obviously I won't give a full solution leaving to you all the fun ;)

Remove Subtree with specific value

The problem I'm trying to solve is that given a binary tree, remove subtree which has the same value as the parameter value passed. Here's my code but I don't believe it works as the altered tree is the exact same as the original tree.
Before:
5
/ \
3 2
/ \ / \
2 1 4 3
After removal of subtree of value 2:
5
/
3
\
1
public TreeNode removeSubtree(TreeNode root, int value){
TreeNode copy = root;
removeSubtreeRecursion(copy, value);
return root;
}
public void removeSubtreeRecursion(TreeNode root, int val){
if(root == null) return;
else if(root.val == val) root = null;
else{
removeSubtreeRecursion(root.left, val);
removeSubtreeRecursion(root.right, val);
}
}
You can use parent node instead of current node to be able to modify it. It could be something like this:
public TreeNode removeSubtree(TreeNode root, int value){
if (root != null && root.val == value) return null;
removeSubtreeRecursion(root, value);
return root;
}
public void removeSubtreeRecursion(TreeNode parent, int val) {
if (parent.left != null && parent.left.val == val) parent.left = null;
else removeSubtreeRecursion(parent.left, val);
if (parent.right != null && parent.right.val == val) parent.right = null;
else removeSubtreeRecursion(parent.right, val);
}
In your implementation root = null modifies local reference. You can read more about this in Pass by reference in Java.

Recursive Binary Search Tree Insert

So this is my first java program, but I've done c++ for a few years. I wrote what I think should work, but in fact it does not. So I had a stipulation of having to write a method for this call:
tree.insertNode(value);
where value is an int.
I wanted to write it recursively, for obvious reasons, so I had to do a work around:
public void insertNode(int key) {
Node temp = new Node(key);
if(root == null) root = temp;
else insertNode(temp);
}
public void insertNode(Node temp) {
if(root == null)
root = temp;
else if(temp.getKey() <= root.getKey())
insertNode(root.getLeft());
else insertNode(root.getRight());
}
Thanks for any advice.
// In java it is little trickier as objects are passed by copy.
// PF my answer below.
// public calling method
public void insertNode(int key) {
root = insertNode(root, new Node(key));
}
// private recursive call
private Node insertNode(Node currentParent, Node newNode) {
if (currentParent == null) {
return newNode;
} else if (newNode.key > currentParent.key) {
currentParent.right = insertNode(currentParent.right, newNode);
} else if (newNode.key < currentParent.key) {
currentParent.left = insertNode(currentParent.left, newNode);
}
return currentParent;
}
Sameer Sukumaran
The code looks a little confusing with overloaded functions. Assuming member variables 'left' and 'right' to be the left child and right child of the BSTree respectively, you can try implementing it in the following way:
public void insert(Node node, int value) {
if (value < node.value)
{
if (node.left != null)
{
insert(node.left, value);
}
else
{
node.left = new Node(value);
}
}
else if (value > node.value)
{
if (node.right != null)
{
insert(node.right, value);
}
else
{
node.right = new Node(value);
}
}
}
........
public static void main(String [] args)
{
BSTree bt = new BSTree();
Node root = new Node(100);
bt.insert(root, 50);
bt.insert(root, 150);
}
You should have a look to this article. It helps to implement a tree structure and search, insert methods:
http://quiz.geeksforgeeks.org/binary-search-tree-set-1-search-and-insertion/
// This method mainly calls insertRec()
void insert(int key) {
root = insertRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node insertRec(Node root, int key) {
/* If the tree is empty, return a new node */
if (root == null) {
root = new Node(key);
return root;
}
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = insertRec(root.left, key);
else if (key > root.key)
root.right = insertRec(root.right, key);
/* return the (unchanged) node pointer */
return root;
}
You can use standard Integer (wrapper for primitive int) object instead of creating a new object type Node. On latest java Integer/int auto-boxing is supported. Hence your method insertNode(int key) can take in Integer argument too (ensure it is not null).
EDIT: Pls ignore above comment. I did not understand your real question. You will have to overload insertNode(). I think you are right.
but where is temp when you insertNode?? With your current implementation temp is lost if root is not null.
I think you want something like
root.getLeft().insertNode(temp);
and
root.getRight().insertNode(temp);
i.e. To insert the new Node (temp) to either the left or the right subtree.

Categories

Resources