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
Related
I have node class as
class Node{
int data;
Node next;
}
I have to insert nodes to the list.
It works properly. But always the head value is zero.
public void createlist(Node n,int p)
{
Node newone = new Node();
newone.data=p;
newone.next=null;
if(n==null)
n=newone;
else
{
while(temp.next!=null)
temp=temp.next;
temp.next=newone;
}
}
In main function I have created head node as
public static void main(String args[] ) {
Scanner s = new Scanner(System.in);
Node head=new Node();
createlist(head,5);
}
after creating this implementation the list starting from head looks like
0->5. Why did the 0 come?.
Zero comes from the head node itself:
Node head=new Node();
It is never modified by createList method, so the default value of zero remains in the data field.
It boils down to inability to change head inside main by assigning n in the code below:
if(n==null)
n=newone;
That is why you are forced to create new Node inside main, so in fact n is
never null.
You can fix this problem in several ways:
Treat the head node in a special way - ignore the head node in for printing, deletions, etc., or
Change methods that operate on Node objects to return the modified list - this would let you insert new nodes or delete the head node, or
Introduce a MyList class that owns all nodes - move all list operations on the "umbrella" class, and deal with the head node there.
I've made a remove method that removes an object from a singly linked list.
So far the method removes the first node and the second node without a problem. When removing the third node and onward the method removes everything between the specified node and the head node. My question is how can I make my method remove the specified node and not everything before it?
I know I need to keep a reference to the previous node in order to assign its next node to the specified nodes next node. This will close the gap and remove the node. I understand the logic but can't seem to implement it.
public class List_test{
public Node head;
public List(){
head = null;
}
public List(Node head_) {
this.head = head_;
Node ref = head;
}
public void remove(Node node) {
Node ref= head;
if (ref.equals(node)) {
head = head.next;
return;
}
while (ref != null) {
if (ref.equals(node)) {
head.next = node.next;
}
ref = ref.next;
}
}
public static void main(String[] args) {
new List_test();
}
For removing a node, why are you changing the head pointer? You should be using the previous node and point it to the next node of the node to be removed.
I think this page have nice explanation for this topic:
deleting node in linked list c/c++, java, python
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 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.