I got the following code from one book for implementing a singly linked list. And I don't understand some lines of code in the removeFirst() method, which removes the first node from the LinkedList.
class ListNode{
private String element;
private ListNode next;
public ListNode(){
element = null;
next = null;
}
public ListNode(String s, ListNode n){
element = s;
next = n;
}
//Access method
public String getElement(){
return element;
}
public ListNode getNext(){
return next;
}
//Modify method
public void setNext(ListNode n){
next = n;
}
}
public String removeFirst(){
if(head == null)
return null;
else{
ListNode temp = head;
head = head.getNext();
temp.setNext(null); //Which I don't understand, is it necessary?
size --;
return temp.getElement();
}
}
It seems that the statement temp.setNext(null); can be omitted. So why it is here, does it has anything to do with the garbage colletion in java. Since I am new to Java, any suggestions or ideas?
It depends on the entire implementation of the linked list, which you have not included in your question. However if it is possible for objects to hold a reference to a node even after if has been removed from the list, then the line is necessary.
Suppose we have a long chain of nodes A -> B -> C -> .... Suppose all of these nodes have been removed from the list, but that we still hold onto a reference to A. If all the nodes still held a reference to the next, this would prevent all of the nodes from being garbage collected. Simply setting the next node to be null ensures that only A cannot be garbage collected.
It is likely that implementations of a linked list do mean that references to nodes can be retained. For example, many implementations of Iterator hold a reference to the current node.
Consider this code:
Iterator<String> iterator = list.iterator();
while (i.hasNext()) {
if ("foo".equals(i.next())) {
i.remove();
break;
}
}
// lots more code
This code searches a list for the first occurrence of the String "foo". If it is found, it removes the "foo" from the list and breaks from the loop. The trouble with this is that the Iterator i is still in scope for the remaining code and still holds a reference to a node. This node may be in the middle of the list if the break occurred. Without setting next to be null, this would prevent all subsequent nodes from being garbage collected while i is still in scope, even if the list is cleared.
Note that you should generally make an iterator local to a loop anyway, like this
for (Iterator<String> i = list.iterator();;i.hasNext())
Let us suppose, single linked list of nodes is : A --> B --> C --> D with head node as A. Now, lets go though your removeFirst() method. When it get called, if(head == null) condition doesnt satisfy because our head node "A" is not NULL. Then it execute else statement,
temp = head //take head reference into temporary variable
head = head.getNext(); //As we want to delete first Node which is head so we are setting head to next node (i.e. head --> next) which is Node "B"
Now, to delete A (first Node) we need to break connection between A (which is previous head)--> B (current head) and that will done by
temp.setNext(null); //so out linked list became A B-->C-->D
and then as one node is deleted so in next statement it decreases size of link by size--.
I think we also set the temp reference to NULL as temp=NULL to make deleted node eligible for garbage collection.
Related
I have seen similar questions asked, but none of the answers really address my confusion.
I'm working through some Linked List content, trying to write methods to solve leetcode-like problems. I'm working with singly-linked lists, defined as:
public class LinkedListy {
ListNode head;
LinkedListy(){};
public static class ListNode {
int val; //integer variable
ListNode next; //pointer
ListNode() {}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val; this.next = next;
}
}
...
I'm trying to write a function that will reverse my linked list, but will not destroy my original linked list. The code I have written works to reverse the list, but destroys the original list:
public ListNode reverse() {
//use copyList function to avoid altering head --> DOESN'T WORK
ListNode current = head;
ListNode temp = null;
ListNode copied_result = null;
while(current != null){
temp = current.next;
current.next = copied_result;
copied_result = current;
current = temp;
}
return copied_result;
}
From reading on here and other places, I understand that by setting current = head, I'm just creating a new reference for the same ListNode. Thus, when I run my code, I'm mutating the original list.
Main Confusion: I'm confused because I have written methods that do NOT destroy the original list, but use the same kind of reference to head. For example, in my "length()" method, I set dummy = head and alter dummy to find the length of the list. But, then the original list doesn't get changed (I wrote a print function to print the list and I verified it prints the same before and after calling length().)
public int length() {
ListNode dummy = head;
int length = 0;
while(dummy != null) {
dummy = dummy.next;
length++;
}
return length;
}
So, I'm clearly not understanding something fundamental about LinkedLists.
Why does my reverse() method destroy the original list when my length() method does not?
Is the only way to write a reverse method for a linked list without destroying the original list to make a copy of the original list in your main method and reverse the copy?
Any help or resources would be greatly appreciated. Thanks!
In the length method, you're using a locally accessible variable named dummy to iterate through the nodes in the list; when you set dummy = dummy.next, this sets the value of the local variable to refer to the next node. This is very different from doing something like dummy.next = null, which would affect the content of node to which dummy currently refers.
To that end, your reverse method doesn't actually 'destroy' the original list - the main issue is that head isn't being set to the first element when you're finished. Thus, head still 'points' to the same node it did before the function started, which is now the last node.
If you want to reverse the list in-place, then just updating head properly at the end of your function will work fine - if you want to return a reversed copy of your original list without modifying the original, you'll need to copy all of the nodes. See #Hank_interprize's description of deep/shallow copies.
I believe the issue here is you are not actually copying any new information over to the new list but instead the code is just using the same list as before under a new name. This can be done with a deep copy.
To create a new list you will need to copy the old data over to a new list with a whole new system of pointers and simply copying the data over to the new linked list which is different than copying the pointer.
Node class is given as follows:
// I have not added class modifiers for simplicity
class Node{
int data;
Node next;
//Constructor
Node(int data){
this.data = data;
next = null;
}
}
Suppose I have a simple linked list of numbers n1 , n2 , n3 etc (it has atleast 2 nodes). We can reference linked list only using head pointer. Head pointer points to n1 node. Now there is a delete node function where we pass head node.
Node deleteNode(Node head){
if(head==null)
return null;
else
return head.next;
}
Suppose we run delete Node function one time.
Will garbage collector of java, deletes n1 node , because now we cannot access it but still node n1 points to n2 (in delete Node function we have not made "next" parameter pointing to null)? We have just changed head pointer.
An object will be garbage collected if there are no reachable references to it.
For example if you initialize your linked list like this:
Node head = new Node(0);
Node n1 = new Node(1);
Node n2 = new Node(2);
head.setNext(n1); //Let's assume that you have the basic getters and setters implemented
n1.setNext(n2);
Then your original head will be flagged for garbage collection if you do this:
head = deleteNode(head); //Here head will be referencig n1, so nothing is referencing the original head anymore, so it will be garbage collected somewhere in the future
(Side note: you don't have to initialize fields of a class to null in the constructor, because they are null by default)
From your snippet the garbage collector wont run.
Your Node deleteNode(Node head) is not deleting anything, you are simply returning the next node if there is one.
In order for for garbage collector to run you have to discard every reference to an object which is not happening here.
I am trying out my own implementation of a double-linked list. While my code is currently functioning, I can't really figure out why. Below is an exerpt of the code:
public class DLList<E> {
public class Node {
/** The contents of the node is public */
public E elt;
protected Node prev, next;
Node() {
this(null);
}
Node(E elt) {
this.elt = elt;
prev = next = null;
}
}
Node first, last;
DLList() {
first = last = null;
}
// inserts an element at the beginning of the list
public Node addFirst(E e) {
Node node = new Node(e);
if(first==null){
first = node;
last = node;
}else{
node.next = first;
first.prev = node;
first = node;
}
return node;
}
}
In the else-block of the addFirst-function the variable next is set to the reference first and two lines later the reference first is set to the Node-object node. Surspringly (to me) this works. Shouldn't this mean that node.next is actually set to node as we basically get node.next = first = node?
EDIT:
Answers:
You're changing references (pointers) - which is why it does [work]. The last line first = node; simply changes first from pointing to the previous node to point to the current node. – alfasin
I think I figured it out. In my code I am not changing the actual object, I am just changing what objects are being referenced. In plain english my code in the else-block can be read as:
1. Set node.next to reference the object that first is referencing.
2. Set first.prev to reference the object that node is referencing.
3. Lastly, reassign first to reference the object that node is referencing. – erikejan
There are some issues in your code as mentioned in the comments, but to answer your question, no, it's not the same. In Java, you assign variables by value and not by reference. So, if you modify first after assigning it to node, it doesn't modify the value of node.
It's like,
a = 5;
b = a;
a = 4;
Here, value of b will be 5. It doesn't get changed to 4.
Compiler executes each statement sequentially. So it will not know that the value of a will be modified in the future or not.
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.
So I have this code for Linked Node Stack (in short Linked Stack) and It confuses me very much! I have an exam tomorrow on that and it confuses me a lot! So take a look:
class Node<T> {
T item; // data in node
Node<T> next = null; // successor node
Node(T item0, Node<T> next0) {
item = item0; next = next0;
}
}
That is easy to understand no problem, we create a class called Node (it's a data structure) which contains an item of type T (can be String, Integer etc..) and another Node called next to indicate the next Node in line. Everything is clear. Off with that!
Now's time for the Stack itself, so here's the code:
class Stack<T> {
private Node<T> head = null; // first node (null if empty)
Stack() {}
Stack(int n) {}
boolean isEmpty() {return(head==null);}
boolean push(T t) {
head = new Node<>(t,head);
return true; // always space available
}
T pop() {
if (head==null) return null;
T t = head.item;
head = head.next;
return t;
}
}
Now here's where I lose my mind! OK so! First off when we initiate the Stack we create a Node with name head okay! Got it and it's null yes! Next, black magic to me is when we use the push(T t) method. So we say head = new Node<>(t, head) okay okay! slow down there fellow! We replace the existing null head with a new Node which contains the data t and as the next node, it carries itself?? so head = data, head(null,null)..? What if we add a 2nd element? it's going to be again head = data, head(data, head(null, null)... ?
Please explain this to me in plain english! :(
The line
head = new Node<>(t,head);
is executed in the order
1) new Node<>(t,head)
2) head = ...
So when you create the new Node object you pass in the old value of head, not a reference to itself.
To be less confusing this line can be rewritten as
Node<T> oldHead = head;
head = new Node<>(t, oldHead);
So when the stack is empty head = null
When we add one item head = (item1, null)
When we add another item head = (item2, (item1, null))
The Node created by push does not contain a reference to itself. When you perform an assignment in Java, the variable being assigned (on the left-hand side of the equal sign) is not altered until after everything on the right side is fully resolved and constructed.
Therefore, at the time that Java executes the Node constructor to create the new head node, the value of head within the Stack object still points to the previous head. The new Node for head is thus created with the new data, plus a reference to the previous head Node. Then, only after the new Node object is fully created (and has a next value pointing to the previous head), the value of head within the Stack object is assigned to the newly-created object.
I think you are over thinking this. So the way a stack works is similar to a linked list. So if you have an empty list, head = null. You got that part right.
So what you are doing when you call push is adding that new node to the top, so it would be the new head node.
head = new Node<>(t,HEAD);
now the new node is at the top of the list and the second argument of Node (which is HEAD)is pointing to the old node that was the head of the linked list.
so on first push, it isn't hard to understand:
first call to push: head = new node(t, NULL) because the old head node is NULL
second call to push: head = new node(t, head) and head (the second argument here) is pointing to what was the old head and is now the next item on the list
When you do head = new Node<>(t, head), you are updating the head of the stack to a Node with Node.item = tand Node.next = oldHead, which in this case is null
because you haven't put anything in it.
If we add 1 element to an empty stack we get Node(data1,null). If we add a second item to the stack we get Node(data2, Node(data1, null))