Java - Binary Tree pointer still null after initialization? - java

This question is very abstract and thus very hard to describe or search for, thus why I am here. It's a very simple question however.
I have the following class:
class Node<T>
{
Comparable data;
Node<T> left, right;
public Node(Comparable data)
{
this.data = data;
}
}
What happens if I have:
/*
* Imagine this root looks like the following:
* 10 (root)
* / \
null null
*/
Node root;
// Imagine we are inside of the insert method and this
// is the current value that is going to be inserted.
int valueIAmTryingToInsert = 5;
// As we see from the tree above, "child" WILL be null.
Node child = (valueIAmTryingToInsert.compareTo(root.data) < 0 ? root.left : root.right);
if (child == null)
{
child = new Node(data);
return true;
}
// Recursive statement would happen here.
Notice that child is a pointer that points to either the left or the right child of root. BUT, what happens if I instantiate the Node that child is pointing to? After calling child = new Node(data);, does the tree currently look like:
10 (root)
/ \
5 null
If It doesn't look like that, explain why. Because my understanding is even though Node child is null, the pointer is still pointing to one of root's children. I am pretty sure this doesn't work, as my editor underlines child in the statement child = new Node(data); and claims The value new Node(data) assigned to 'child' is never used (even though it is being used).

You are never assigning it to the root node as its "left".
In plain English this is what your code does:
-Is the left (or right) of the root null?
-Yes
-Create a new node please.
But there's no association between this new Node and the root Node.
You might need something like this:
Node root;
Node child;
Integer valueIAmTryingToInsert = 5;
if(valueIAmTryingToInsert.compareTo(root.data) < 0){
if(root.left == null){
root.left = new Node(valueIAmTryingToInsert);
}
child = root.left;
}else{
if(root.right == null){
root.right = new Node(valueIAmTryingToInsert);
}
child = root.right;
}
return true;
EDIT:
This code is just an example, but if root.data is null you'll get a NullPointerException because of the comparision. That's something you might be aware and take care of.
EDIT 2:
I can see you're still confused and the main issue is that you have to keep in mind that null is not a reference to an object. It is a "mark" that indicates that the object has not been yet initialized. So when I say a = null; b = a is not like a and b are pointing to the same object (Because nullis not a valid object or reference), it means they both have not yet been initialized. They are separate independent variables. Then when I initialize one a = new MyClass() I'm asking for a memory reference for a, but b remains pointing to nowhere in memory.
See null as a way of telling "This object is pointing to nowhere".
If things were as you are thinking (If I initialize a then b should point there too); then every single null object in the program should point to where a is now pointing to.

You need to understand that child = new Node() will change what object your pointer points to, not any values of the object the pointer pointed to before and definitely not what object other pointers point to (like root.left).
root.left and child are NOT the same variable, even after calling child = root.left! They only point to the same object. So changing what one points to does not influence the other.
Basically, new Node() creates a new object somewhere in your memory. child = new Node() does the same thing, except afterwards it tells the variable child to point to that newly created object instead of whatever it pointed to before.

Related

Leetcode208, different execution sequences lead to different results [duplicate]

I have written two functions for adding a new node to a tree: one public and one private. The private one is recursive. The public one calls the recursive one. First question: Is this acceptable practice?
public void addNode(int val) {
addNode(val, root, null, 0);
System.out.println("Root is null: " + (root == null));
}
private void addNode(int val, Node node, Node parent,int height) {
if(node == null) {
node = new Node(val, height, 0);
System.out.println("is new node equal to root?"+(node == root));
System.out.println("Added node on height: " + node.getHeight());
return;
}
height++;
addNode(val, node.left, node, height);
addNode(val, node.right, node, height);
}
Now here is the problem: The root variable does not get initialized. It is declared in the tree class. public Node root;
This is very confusing to me since I am aware that Java is pass-by-reference, not pass-by-value. Why is root null after these functions have been called?
Console output:
is new node equal to root?false
Added node on height: 0
Root is null: true
If in Java code a function assigns a new value to a function parameter, this never impacts the variable that the caller may have passed as argument. You may have been confused with what happens when a parameter variable is mutated: for instance, if it is an object and you assign a different value to one of its properties, then this change is visible to the caller's object, since it really is the same object. But a plain assignment to a parameter will always have an effect on that local variable only.
To make it work, design your function to return the node that you provided to it (whether it got a new value or not).
There is another issue: you are currently adding a new node in both the left and right subtree (if they exist), and this repeats recursively. I will assume you were trying to insert values in a binary search tree, and so you should choose in which subtree you will add the node.
Finally, it is not needed to pass parentNode or height as argument, since you seem to store the height in each node, and so you know that the new node's height must be one more than the height stored in its parent node (or, when absent, 0).
public void addNode(int val) {
root = addNode(val, root);
}
private void addNode(int val, Node node) {
if (node == null) {
return new Node(val, 0, 0); // NB: height will be updated when backtracking
}
if (val < node.val) {
node.left = addNode(val, node.left);
node.left.height = node.height + 1;
} else {
node.right = addNode(val, node.right);
node.right.height = node.height + 1;
}
return node;
}
Finally, the name "height" is a bit misleading here, as this term is supposed to denote the height of the (sub)tree of which the node is the root. But height in this code represents the depth of the node in the tree. See What is the difference between tree depth and height?.
Of course there is nothing wrong in calling private method (even recursive) from public method.
Root is null simply because you are assigning new value to node argument, you are not changing object, but you are creating new one.
following
private void addNode(int val, Node node, Node parent,int height) {
...
node = new Node(val, height, 0);
will not change argument node in caller. So after calling
addNode(val, root, null, 0);
root stays unchanged (with null value)
Also keep in mind objects are passed by value in Java.
Actually (inside Java) in function you receive only memory address (value) for node (e.g. 000000D5098FFA70 in x64 arch). So if you modify e.g. node.left you are actually changing memory at address 000000D5098FFA70 + 4. However if you change
that address - value - you lose access to this object. And from that moment you are working only with local variable. This is why it is called passed by value.

Why we can use Node head = null without instantiate the 'head' in Java?

I am reading someone's code. It is about getting input numbers and convert those number into a Linked list. The part of the code is like this:
class Node {
int value;
Node next;
Node() {
next = null;
}
}
Firstly We need to create a head node to indicate head and we let the head be null like this Node head = null.
My limited experiences of java tell me that head is supposed to be a Node type object here. So why we can use Node head = null without instantiate the head?
I think at least I should create Node head = new Node(); then we can use Node head = null;
Anyone can explain it to me?
Node head = null;
This line states that there are no items in the linked list. This is valid in Java and indicates that although head can contain a Node object (or an object of a derived class), it is currently empty.
To add an item to the list, there is likely some code such as:
public void addItemToLinkedList(int value) {
if (head == null) {
head = new Node();
head.value = value;
} else {
...
}
}
So if there is no first Node (when head equals null) then head is created. Otherwise if head already exists, the else block would execute which would look for the end of the list and add another Node.
head is supposed to be a Node type object here
This is optional. Java allows head to be a Node object, or null, to indicate that head is not referencing any nodes at all.
The value of null is special in Java. It is allowed to go wherever an object can go. It indicates that the variable to which you assign null is empty. This is perfectly fine, assuming that the rest of your program deals with null checking.

What does "this" refer to in Linked List example?

So I'm skimming through Cracking the Coding Interview to brush up on some interview stuff and I ran across this linked list implementation, and maybe it's been a while but it's completely going over my head. I understand most of it, except for one specific line, and it's throwing me off. I'll post the code below (for reference, the book doesn't mention language but it appears to be Java.)
class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while(n.next != null) {
n = n.next;
}
n.next = end;
}
}
I'm a little confused on the line: Node n = this - I'm not sure what this is referring to, unless it's talking about next - why not just set it to null in that case?
this refers to a specific instance of an object of a class. Since objects are constructed there can be multiple instances of a class, but using the this keyword allows you to obtain a reference to itself, meaning a reference to the the specific instance of the object whose method is being called.
The linked list is a collection of nodes that are, well, linked together. When you call appendToTail() the node will look at all of the Node objects linked to itself and follow the chain. For it to get a reference to itself to follow its own chain the this keyword is used.
You also ask why null isn't used in this case to initialize n. This would cause a NullPointerException when n.next is first called in the loop constraint, so instead its own reference is used as the starting point for the iteration of the linked-list.
This (pun intended) can be a confusing topic at first, but lets use the example you provided.
Node n = this;
while(n.next != null) {
n = n.next;
}
Let's pretend that there are 4 objects currently linked in our list and for simplicity's sake the Node object that appendToTail() is being called on is the head of the list. Here's the reference value of Node n that's held on each loop iteration from the above snippet.
We're pointing to ourself - this
Pointing to the second item in the linked list. - this.next
Pointing to the following item - this.next.next
Pointing to the last item in the list - this.next.next.next
The loop ended so currently the reference of n = this.next.next.next. We then set n's next value (where n is currently pointing to the end of the linked chain) to the new object we created at the beginning of our method, which makes it the new end of the list. (n.next = end is now equivalent to this.next.next.next.next = end).
Semi-Unnecessary Edit: This is explained in terms of Java. It appears that someone added the C++ tag after I wrote this answer
This is Java.
"this" refers to the specific instance of the class in which the call is being made. In this case, "this" is in reference to the specific class Node you are dealing with. While the variable "end" creates a new and separate version of the Node class which is constructed using the passed int "d".
Since this is a Linked List all Nodes are connected and you have a start Node (root). So when using it it would look like this:
Node root = new Node(6); //need an instance first
root.appendToTail(5);
root.appendToTail(3);
//6->5->3
Since this the nodes are connected I need one start Node and need to check if this has a next node when yes I need to search deeper. When a node did not have a next Node it is the current last one and can add my new Node. So this in Java refers to the current instance of a class. In my example the root Node(because I call root.appendToTail). So the method will search from the root Node (value 6) the next Node without a next Node (the one with value 3) and append it there. If I can get a child reference and would call child3.appendToTail the method would search from child3 instead of starting from my root.
When setting n to null and rewriting the while to go from this.next you would have a problem when the current node you use appendToTail did not have a next Node and an NullPointerException would be thrown.
Node n = this; means n object references to the object which is calling this method.
So method is looping to next object till next object is null and assigning end node to the end.
Lets see
1 -- 2 -- 3 -- 4
*
|
*
obj
you have an obj object that is pointing to node 1. When u call obj.appendToTail(5)
Node end = new Node(d); //new node is created to add to the end.
Node n = this; //local n object is referenced to node 1(or obj)
while(n.next != null) {
n = n.next;
}
//n here is node 4 since there is no next node to 4
n.next = end; //node 5 is tail now
End result:
1 -- 2 -- 3 -- 4 -- 5
As you can see in this code
class Node {
//
void appendToTail( int d ) {
Node *end = new Node( d );
Node n = this;
// ...
}
}
Your class Node has a reference to a Node in it's definition.
The line: Node *end = new Node( d ); means inside a Node there is a reference to another node.
The line Node n = this; means inside a Node the reference to that node itself, is represented by this. Ergo, n is also a reference to said node itself.
Any Node instance can call appendToTail().
Notice howebet, here in fact Node does not append itself to tail of the list, what happens here is that new node is created and added to tail, not the one on which method is invoked.
For this to happen, first we need to find the tail of the list given the current Node.
// n is pointing to current Node
while(n.next != null) {
n = n.next;
}
Once we find node which has next == null, this is tail of the list so we can now append new Node to the tail:
// n points to current tail before next line is invoked
n.next = end;
As to why there is line:
Node n = this;
Well since there is no LinkedList class which maintains reference to the head, you have to be able to iterate from any given Node. That is what happens here, you start iteration from Node on which appendToTail is called, but that Node can be anything at this point, from head to tail.
As a side note, if you implement Linked List by hand, make sure to actually have class LinkedList which will offer methods such as add, get, size, appendToTail and so on, rather then putting these into Node class.

Java code to delete whole Binary tree.

I read a postorder traversal application to delete a binary tree and a code which is written in c++.
I am wondering how to write this code for java. I think we have to set the node as null in postorder way.
void delete(Node root)
{
if (root!=null){
delete(root.left);
delete(root.right);
}
root=null;
}
root = null
C++ isn't garbage collected, but Java is. In Java, once an object no longer has any references to it, it will be automatically removed from memory. All of the referenced objects of the garbage collected object will also be removed if they have no other references to them. That bit addresses your question: if the nodes under root don't have any external references, they will be automatically removed after root.
Trivially root = null;. However there is a difference with C++ as Java cannot change a passed variable:
delete(root);
will never set root to something else. This was a design principle to make Java more qualitative in software engineering sense (less error prone) than C++ (Node*&).
You need to use return values, as there are no output values.
A modified example:
Node deleteSubtree(Node tree, Object value) {
if (tree == null) {
return null;
}
if (value.equals(tree.value)) {
return null; // Deleting a subtree
}
tree.left = delete(tree.left, value);
tree.right = delete(tree.right, value);
return root;
}
NOde root = ...
root = delete(root, "war");
This would delete the subtree rooted at "war".
You simply need to unlink the left and right nodes from the root:
void delete(Node root)
{
if (root!=null){
delete(root.left);
root.left = null;
delete(root.right);
root.right = null;
}
}
Setting root to null is useless, because it is a local variable that will be unlinked when the method returns anyway. Also it does not affect the value in the calling method, so it has no effect at all.
Just do root = null and the garbage collector will delete the whole tree during the garbage collection as no reference to the tree root is available in the program.
public class BinaryTree {
Node root;
public BinaryTree() {
root = null;
}
void deleteTree(Node node){
if(node==null)
return;
deleteTree(node.left);
deleteTree(node.right);
System.out.println("The deleted node is " + node.key);
node = null;
}
void deleteTreeRef()
{
deleteTree(root);
root=null;
}
}
And client will call like following:
tree1.deleteTreeRef();

Setting myself to null - Java

I came across the following problem:
Delete a node in the middle of a singly linked list, given only access to that node. (head is not given)
Now there are a lot of solutions and they all do not work when the element to be deleted is the last node.
Why wouldn't this work?
public static void removeNode (Node n){
if(n.next == null){ //n is the last node
n= null;
return;
}
//handling general case here
}
Java passes parameters by value, so setting n to null has no effect outside of the method. This means the method essentially does nothing when passed the last node of a list.
You need to set null the reference in the previous node, not the variable that references to your last node, something like this:
if(n.next == null) {
prev.next = null;
return;
}
n is local to the method, so changing its value won't affect the list itself. You need to modify the next of the previous node, which you do not have access to.

Categories