Clarification regrading Java pass-by-value - java

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.

Related

Deleting Node from BST

I think I got most of the cases to work except for case 2 (deletion node has only one subtree). My test case is the tree below without the 1, 2, 3 and 4 nodes:
This program is telling me that 6 was deleted from the tree but when I try printing the tree, it still shows that 6 is in the tree.
public class RandomNode {
static int size;
public static class Node {
int data;
Node left;
Node right;
public Node(int data) {
this.data = data;
left = null;
right = null;
size++;
}
}
// delete node in right subtree
public Node delete(Node root, int data) {
// base case - if tree is empty
if (root == null)
return root;
// search for deletion node
else if (data < root.data)
root.left = delete(root.left, data);
else if (data > root.data) {
root.right = delete(root.right, data);
} else {
// case 1: deletion node has no subtrees
if (root.left == null && root.right == null) {
root = null;
size--;
System.out.println(data + " successfully deleted from tree (case1)");
// case 2: deletion node has only one subtree
} else if (root.left != null && root.right == null) {
root = root.left;
size--;
System.out.println(data + " successfully deleted from tree (case2a)");
} else if (root.left == null && root.right != null) {
root = root.left;
size--;
System.out.println(data + " successfully deleted from tree (case2b)");
// case 3: deletion node has two subtrees
// *find min value in right subtree
// *replace deletion node with min value
// *remove the min value from right subtree or else there'll be
// a duplicate
} else if (root.left != null && root.right != null) {
Node temp;
if (root.right.right == null && root.right.left == null)
temp = findMinNode(root.left);
else
temp = findMinNode(root.right);
System.out.println(root.data + " replaced with " + temp.data);
root.data = temp.data;
if (root.right.right == null || root.left.left == null)
root.left = delete(root.left, root.data);
else
root.right = delete(root.right, root.data);
size--;
System.out.println(temp.data + " succesfuly deleted from tree (case3)");
}
}
return root;
}
// find min value in tree
public Node findMinNode(Node root) {
while (root.left != null)
root = root.left;
System.out.println("min value: " + root.data);
return root;
}
public void preOrderTraversal(Node root) {
if (root == null)
return;
preOrderTraversal(root.left);
System.out.println(root.data);
preOrderTraversal(root.right);
}
public static void main(String[] args) {
RandomNode r = new RandomNode();
Node root = new Node(6);
//root.left = new Node(2);
root.right = new Node(9);
//root.left.left = new Node(1);
//root.left.right = new Node(5);
//root.left.right.left = new Node(4);
//root.left.right.left.left = new Node(3);
root.right.left = new Node(8);
root.right.right = new Node(13);
root.right.left.left = new Node(7);
root.right.right.left = new Node(11);
root.right.right.right = new Node(18);
r.delete(root, 6);
r.preOrderTraversal(root);
}
}
When you do root = root.left; and size --, you must also make root.left = null.
Here you are simply making root as root.left but are not making root.left as null.
It's rather hard for me to follow since I'd write it functionally.
However,
if (root.right.right == null || root.left.left == null)
root.left = delete(root.left, root.data);
else
root.right = delete(root.right, root.data);
Is probably wrong, since it should mirror your earlier findMinNode() calls, and thus should probably be
if(root.right.right == null && root.right.left == null)
root.left = delete(root.left, root.data);
There is more wrong when debugging it.
First off, java is pass by value, so if you're deleting the top node (root), your pointer should be updated too. Hence, the call should be root = r.delete(root, 6);
Second, there's another bug. Case 2a assigns root to root.left... which is null. It should be root.right.
Having made those changes, the output then becomes:
6 successfully deleted from tree (case2b)
7
8
9
11
13
18

Moving around Java references

So I am creating a Binary Tree through recursion, When I insert a new node I would like to jump back up to the root to start the insert from scratch again. to do that I follow this routine.
BinaryTree node = new BinaryTree();
node = this;
node = root; // this is where I want to get to
So when I coded this out and attempted to set the $this variable to root it did not set as can be seen in this picture.
Why is 'this' not set this to root? how can I jump to the top of a tree?
public void addNode(List teams, BinaryTree tree, BinaryTree root){
while(teams.size() > 1){
print(root);
//Half's the list
halfA = teams.subList(0, teams.size() / 2);
halfB = teams.subList(teams.size() / 2, teams.size());
if(parent == null){
left = new BinaryTree(halfA);
left.parent = this;
right = new BinaryTree(halfB);
right.parent = this;
}
if(countChildren(tree.left) >= countChildren(tree.right)) {
if (right == null) {
setRight(new BinaryTree(halfB));
BinaryTree temp = new BinaryTree();
parent = this;
temp = this;
temp = tree;
} else if (right != null)
right.addNode(halfB, tree, root);
}
if(countChildren(tree.right) >= countChildren(tree.left)) {
if (left == null) {
setLeft(new BinaryTree(halfA));
BinaryTree temp = new BinaryTree();
parent = this;
temp = this;
temp = tree;
} else if (left != null)
left.addNode(halfA, tree, root);
}
}
}

Java pointer or node assignment understanding wrong?

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) {

Inverting/Mirroring a Binary Tree. Method isn't leaving the input tree intact?

I'm new to Java (only been programming a month) and so I've been practicing some concepts. So if this is a naive or stupid question please be patient with me. I've only ever programmed in MATLAB before!
I just successfully inverted a binary tree (on my first try too!). However, I'm struggling with why my method is actually modifying the tree that I'm passing as input as opposed to leaving it intact and simply returning an inverted variant. In short, after the following line in my main function:
inverse = invertBinaryTree(root);
'inverse' and 'root' are both equal and they're the inverted version of 'root' BEFORE I passed 'root' into the method 'invertBinaryTree'. Please, I'm losing my mind trying to understand this behavior!
Matter of fact, I even tried creating a secondary method 'invertBinaryTree2' and this variant copies the input to a placeholder node and operates on the placeholder node instead of the input; however, this doesn't help things, my input still remains changed!
Here is my first entire main function with the supporting functions. Both invertBinaryTree and invertBinaryTree2 behave the same way, even though I'm copying root into a placeholder variable!
public class leetCode_InvertBinaryTree {
public static void main(String[] args) {
/*
* initializing some binaryNodes for the tree
*/
binaryNode a = new binaryNode(4);
binaryNode b = new binaryNode(2);
binaryNode c = new binaryNode(7);
binaryNode d = new binaryNode(1);
binaryNode e = new binaryNode(3);
binaryNode f = new binaryNode(6);
binaryNode g = new binaryNode(9);
binaryNode inverse;
/*
* just building the tree
*/
a.left = b;
a.right = c;
b.left = d;
b.right = e;
c.left = f;
c.right = g;
/*
* Here is the issue!
*/
System.out.println("Before inverting, root's left branch contains: " + a.left.data);
inverse = invertBinaryTree(a);
System.out.println("After inverting, root's left branch contains: " + a.left.data);
System.out.println("After inverting, inverse's left branch contains: " + inverse.left.data);
}
public static binaryNode invertBinaryTree(binaryNode root){
if(root.right == null && root.left == null){
return root;
}
else if(root.right == null){
root.right = root.left;
root.left = null;
}
else if (root.left == null){
root.left = root.right;
root.right = null;
}
else {
binaryNode temp = root.left;
root.left = root.right;
root.right = temp;
}
root.left = invertBinaryTree(root.left);
root.right = invertBinaryTree(root.right);
return root;
}
public static binaryNode invertBinaryTree2(binaryNode root){
binaryNode placeholder = root;
if(placeholder.right == null && placeholder.left == null){
return placeholder;
}
else if(placeholder.right == null){
placeholder.right = placeholder.left;
placeholder.left = null;
}
else if (placeholder.left == null){
placeholder.left = placeholder.right;
placeholder.right = null;
}
else {
binaryNode temp = placeholder.left;
placeholder.left = placeholder.right;
placeholder.right = temp;
}
placeholder.left = invertBinaryTree(placeholder.left);
placeholder.right = invertBinaryTree(placeholder.right);
return root;
}
Not that it matters, but here's the binaryNode class in case it helps you help me. I've also included the output of the main function that I have posted above.
Before inverting, root's left branch contains: 2
After inverting, root's left branch contains: 7
After inverting, inverse's left branch contains: 7
public class binaryNode {
public int data;
public binaryNode left;
public binaryNode right;
/*
* constructor for binaryNode
*/
public binaryNode(int d){
data = d;
}}
I'd recommend you add a lot more debug statements (for example in println) to show the state of your structure at every stage of your code. It will help illustrate to you what the code is doing.
The reason for your problem is:
In this method:
public static binaryNode invertBinaryTree(binaryNode root){
...you are passing in the node, a pointer (a reference) to an object of class binaryNode. **Incidentally, most style conventions dictate you call that something more like BinaryNode (the capitalization is standardized)...
In this line in class binaryNode:
public binaryNode left;
...you declare the node "left" as a member which can be modified by anyone. This member is of type "binaryNode," which means it refers to the address of a object of type "binaryNode."
In this code:
else if (root.left == null){
root.left = root.right;
...you are setting the field called "left," which is the address of a binaryNode, to the thing returned by "right," which is the address of another binaryNode.
...and so on. You are setting the values of references, and are therefore changing the structure of the data structure.

Finding node in binary tree

Disclaimer: This is for a problem I am stuck with on a homework assignment. I need to refactor my add method and my findnodelocation method so that when finddnodelocation returns the parent node of where the new value would be added, it goes ahead and uses the add method to add the value to the binary search tree where it needs to go.
public void add(int val) {
/*Adds a new node to the binary tree after traversing the tree and figuring out where it belongs*/
Node nodeObjToAdd = new Node(val);
if(root == null){
//if node root is not null root = new node value
root = nodeObjToAdd;
}
Node nodeTraversed = root;
traverseAdd(nodeTraversed, nodeObjToAdd);
}
public Node findNodeLocation(Node focusNode, int val) {
/*returns where a new node with the given value will be placed based on the RootNode, and passed in value.*/
if(val < focusNode.value && focusNode.leftChild != null){
return focusNode.leftChild;
}
if(val >= focusNode.value && focusNode.rightChild != null){
return focusNode.rightChild;
}
else
return this.root;
}
You need to check the data IN the node, before movingo to another node. It goes like this:
// Case where the data would be child of my left child
if(data < node.Data && node.leftChild != null)
return node.leftChild.find(data);
// Case where the data would be child of my right child
if(data >= node.data && node.rigthChild != null)
return node.rightChild.find(data);
// If it is not a child of either, then it would be added as my own child
else
return this;

Categories

Resources