I am sending a LinkedListNode into a method (removeLinkListNodeDuplication) to remove duplicates entry. It iterate through the LinkedListNode and find the duplicate value with the help of Hashtable.
I wonder why the instance of my LinkedListNode is null at the end of my delete method(removeLinkListNodeDuplication), but after it comes out of my deletion method it change to my expectation.
Here is my LinkedListNode class
public class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
public void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
}
}
and in below I am creating a instance of above class and pass it to my delete method.
Node linkList =new Node(1);
linkList.appendToTail(1);
linkList.appendToTail(1);
linkList.appendToTail(2);
removeLinkListNodeDuplication(linkList);
// link list values are as expected i.e. 1,2 ?!
and below is my delete method
public void removeLinkListNodeDuplication(Node listNode) {
Node previous =null;
Hashtable<Integer,Boolean> hashtable=new Hashtable<Integer, Boolean>();
while (listNode!=null){
if(hashtable.containsKey(listNode.data)){
previous.next =listNode.next;
}
else{
hashtable.put(listNode.data,true);
previous =listNode;
}
listNode = listNode.next;
}
//listNode is null
}
Your while loop is executed till the last Node (listNode!=null)
So For the last iteration, listNode.next will be null and the same is assigned to listNode.
Before calling removeLinkListNodeDuplication(linkList);, linkList refers to the address of first Object.
Inside removeLinkListNodeDuplication(linkList); at the last iteration, listNode refers to the last Node, and you are making that Node as Null. It will not modify the previous Nodes.
So after the execution of removeLinkListNodeDuplication(linkList);, linkList still refers to the firstNode which is not modified. Only thing that was modified during the removeLinkListNodeDuplication exectuion was the link from firstNode to the nextNode which is now pointing to the lastNode after skipping the duplicateNode. Please check the comments inside the code snippet which explains it in detail.
Node linkList =new Node(1); // linkList now Points to 1stNode
linkList.appendToTail(1); // linkList still points to 1stNode - add a link inside 1st Node to 2nd Node
linkList.appendToTail(1); // linkList still points to 1stNode - add a link inside 2st Node to 3rd Node
linkList.appendToTail(2); // linkList still points to 1stNode - add a link inside 3rd Node to 4th Node
DateTest dt = new DateTest();
dt.removeLinkListNodeDuplication(linkList);
//linkList still points to 1stNode - but the link is now modified from 2ndNode to 4thNode
public void removeLinkListNodeDuplication(Node listNode) {
Node previous =null;
Hashtable<Integer,Boolean> hashtable=new Hashtable<Integer, Boolean>();
while (listNode!=null){
if(hashtable.containsKey(listNode.data)){
previous.next =listNode.next;
// 2nd Iteration - previous points to 1stNode - modify link inside 1stNode to 3rd Node
// 3rd Iteration - previous points to 1stNode - modify link inside 1stNode to 4th Node
}
else{
hashtable.put(listNode.data,true);
previous =listNode;
//1st Iteration previous points to 1stNode
//4thIteration previous points to 4thNode
}
listNode = listNode.next;
//1st Iteration listNode points to 2ndNode
//2nd Iteration listNode points to 3rdNode
//3rd Iteration listNode points to 4thNode
//4th Iteration listNode points to Null
}
//listNode is null ?!
// listNode now points to Null
}
Hi the linklist in method is a reference to the object whose value is assigned by the parameter.
I think you are talking about call by reference.
If you modify the content of the object. You could get that in the calling method.
But if you modify the reference itself you can't get that back in the calling method.
Related
Say I am given a linked list (Java) with definition,
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
I am given an instance of the linked list:
1->2->3->4
In this function below I am given access to the node with value 3 Ie. 3
public void remove (ListNode node){
node = node.next;
}
Does the linked list become 1->2->4?
I tried submitting this solution to an online judge and it didn't do anything. Help?
Java parameters are passed by value.
When you call remove, a copy of the reference to node is passed in. Your code attempts to change this reference locally by setting node = node.next(), but this won't affect the original list.
What the remove method needs to do is locate the node in the list that has a next that refers to the node you want to remove, and change that to point to the node after the node you want to remove. Assuming there's a method to find the parent of a given node called findParentOf():
ListNode parentNode = findParentOf(nodeToRemove);
parentNode.next = nodeToRemove.next;
public void remove (ListNode node){
node = node.next;
}
This will only affect the local reference you are currently holding. To remove a node, you have to manipulate the next variable of its predecessor, which is not available, as it is a single-linked list.
All you can theoretically do is:
public void removeNext (ListNode node) {
node.next = node.next.next;
}
When calling this method on your sample list you'll have to use the node with value 2, respectively.
public void remove (ListNode node){
node = node.next;
}
it doesn't do anything because when local reference variable node is set to node.next, it goes from pointing to the node with val of 3 to to the node with val of 4.
||
\/
1->2->3->4
becomes
||
\/
1->2->3->4
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.
I have checked few posts that we have in SO.
Insert new node at the beginning of Linked-List
How do I insert a node at the beginning of a linked list?
And implemented a simple LinkedList in java that works just fine.
What I can't get my head around is how adding a new Node to the beginning of the LinkedList would actually work.
Here is how my code snippet for adding a Node to the beginning of the LinkedList looks like:
public class SinglyLinkedList
{
//Private variable to keep tab of the HEAD of the linked list.
private ListNode head;
//Private variable to keep track of the node count in this singly linked list.
private int length;
.
.
.
/**
* Insert a ListNode at the beginning of this List.
*/
public synchronized void insertAtBegin(ListNode newNode)
{
//Set current head as the next of input ListNode
newNode.setNext(head);
//Set the input ListNode as the new head of this SinglyLinkedList
head = newNode;
//Increment the SinglyLinkedList length
length++;
}
.
.
.
}//End of class SinglyLinkedList
The ListNode class represents a Single Node like so:
/**
* Represents a Node of the Linked List.
*/
public class ListNode
{
private ListNode next;
private int data;
/**
* Constructors
*/
public ListNode()
{
next = null;
data = Integer.MIN_VALUE;
}
public ListNode(int data)
{
next = null;
this.data = data;
}
/**
* Accessor methods.
*/
public int getData()
{
return this.data;
}
public void setData(int data)
{
this.data = data;
}
public ListNode getNext()
{
return next;
}
public void setNext(ListNode listNode)
{
this.next = listNode;
}
public String toString()
{
return Integer.toString(data);
}
}//End of class ListNode
The 2 lines that really confuse me are:
//Set current head as the next of input ListNode
newNode.setNext(head);
//Set the input ListNode as the new head of this SinglyLinkedList
head = newNode;
The more I try to analyze these two lines, I feel it will create a circular reference structure instead of pushing in the "newNode" in place of "head".
May be I don't quite understand how Java references are passed around.
Is there an explanation as to why the above two lines won't end up in a circular reference?
It seems you understand conceptually how the LinkedList gets a new head node. Your question is more related to Java itself.
Remember that Java is pass-by-value; When you are passing objects around, you aren't passing the value of the object - you are passing the value of the pointer to that object. Is Java "pass-by-reference" or "pass-by-value"?
So with that in mind, let me break down those 2 lines.
newNode.setNext(head)
The value in head is a pointer to a node. So the setNext function is receiving, in accordance to pass-by-value, a pointer to a node. It is NOT receiving a pointer to head.
head = newNode;
in this line, we reassign head's VALUE to be a POINTER to the newly created node. The value in newNode.next is still a pointer to the previous head.
You are encountering a very common confusion with Java, and believe me it is VERY VERY common (hence the 2k upvotes on the SO I referenced above). I hope this addresses your main source of confusion!
Imagine you have the following LinkedList:
2 -> 3 -> 4 -> 5
and you want to insert a node with a value of 1 at the beginning. Let's call this node newNode.
Now look at this line: newNode.setNext(head); You are making newNode's next value point to head, which in this case is pointing to the node with a value of 2. This is what your list looks like now:
1 -> 2 -> 3 -> 4 -> 5
However, head is still pointing to the node with the value of 2, so you have to fix that by making head point to the node with a value of 1, which is newNode. That is what the line head = newNode; does.
When your list is moving from right to left, i.e. 1 then after new node insertion it becomes 2->1 then after fresh insertion it becomes 3->2->1, In this case you need to take care of two things only : head (the first element of the list) & temporary node which is to be inserted next. Here is the pseudo code for that:
` while(you_want_to_insert_new_node) //temporary is the node to be inserted freshly
{
Insert(temporary->data); //Insert data in temporary node
temporary->next=head;
head=temporary;
}
`
When your list is moving from left to right, i.e 1->2 then it becomes 1->2->3 and so on, you need to take care of 3 things: head, the current node and the temporary. Here is the pseudo code for that:
`
current=head;
while(you_want_to_insert_new_node) //temporary is the node to be inserted freshly
{
Insert(temporary->data); //Insert data in temporary node
current->next = temporary;
current=temporary;
}
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.
I have an interesting situation: When I add a node into a queue, only two nodes added.
Here's how I add nodes into a queue:
Queue queue = new Queue();
Node a = new Node("1");
Node b = new Node("2");
Node c = new Node("3");
Node d = new Node("4");
queue.add(a);
queue.add(b);
queue.add(c);
queue.add(d);
Now, here's the add method:
public void add(Node newNode)
{
// assigning first Node
if (head == null){
head = newNode;
return;
}
// since first Node assigned, assigning second one
if (head.next == null){
head.next = newNode;
}
}
It prints:
1
2
I want to print all of them, but only first two are printed. Also, it is like stack, but FIFO, not LIFO.
Here's the print if it helps:
public void print()
{
Node p;
// Display all the nodes in the stack
for( p = head; p != null; p = p.next )
p.print();
}
Please let me know if additional info needed.
Thanks!
Queue is a FIFO data structure, the first element added to the queue will be the first one to be removed. In a Queue, you add elements from rear end while you remove elements from the head. Every time you add an element, you just need to move the rear pointer, while you remove an element, you need to move the head pointer.
Try this:
public void add(Node newNode)
{
// assigning first Node
if (head == null){
head = newNode;
rear = newNode;
return;
}
// since first Node assigned, use rear pointer for assignment
rear.next=newNode;
rear = newNode;
}
You need a recursive approach:
public void add(Node newNode) {
// assigning first Node
if (next == null) {
next = newNode;
} else {
next.add(newNode); // recursive call
}
}
This method walks along the chain of nodes until it finds the tail, then adds the node there.
The first call is to the head:
head.add(newNode);
The recursive form of the method will take care of the rest.
You only update the head when you take from the head of the queue - you take the head and update the reference to be head.next.
If you look at the code carefully, you are only updating the head and its next pointer.
A solution would be to include a secondary pointer called current where you can update current.next to the newNode and set current to newNode after doing so.
The problem is this code
// since first Node assigned, assigning second one
if (head.next == null){
head.next = newNode;
}
You're always only going to assign the second node when there isn't a second node, and it won't work for the third node and so on, change it to:
// since first Node assigned, assigning next one
Node x = head; // Start from head
while(x.next != null){
x = x.next; // Find the last node in the queue
}
x.next = newNode; // Link the new node to the last node
Another simplification is to always keep a pointer to the last node in the queue. So you can replace the above code with:
public void add(Node newNode)
{
// assigning first Node
if (head == null){
head = last = newNode;
return;
}
// since first Node assigned, assigning to end of queue
last.next = newNode
last = last.next;
}
This will be much faster