Loop in a linked list - java

I have the following code in Main.java trying to implement linked list taken from a book. It's a very basic question but makes me crazy. Would appreciate help!
class Node {
Node next = null;
int data;
public Node (int d) {
data = d;
}
void appendToTail (int d) {
Node tailNode = new Node (d);
Node currentNode = this;
while (currentNode.next != null) {
currentNode = currentNode.next;
}
currentNode.next = tailNode;
}
}
class Main {
public static void main (String args[]) {
Node n = new Node(10);
n.appendToTail (11);
n.appendToTail (12);
n.appendToTail (13);
}
}
So, on n.appendToTail(13);
the following loop runs twice:
while (currentNode.next != null) {...
and on n.appendToTail(14); the same loop runs three times
etc.
Why? I don't understand.
I also don't understand the purpose of that loop - why isn't currentNode.next always null?
Any education would be appreciated.
Thank you.

Simply beacuse currentNode.next = tailNode; is linking the new Node to the tail
> : represent a .next link
Node1 > Node2 > Node3
Calling appendToTail(4), the loop will gave currentNode the reference of Node3 (no > yet) and then put the new Node to this currentNode.next
Node1 > Node2 > Node3 > Node4
Calling appendToTail(5), same idea, currentNode will have Node4 because the is no next value
Node1 > Node2 > Node3 > Node4 > Node5
The loop is just here to find the end (represented by the absence of a next value)

n is pointing to the head of the list (Node(10)). Every time you add a node to the list by calling n.appendToTail(), the while loop will start at the head, and loop once for each node in the list, until it reaches the tail.
The first time you call it, it doesn't loop at all, because the condition on the while loop is false; there is only one node in the list, so it is already at the tail of the list (where currentNode.next == null). The second time, it runs once because there are now two items in the list: the first loop takes it from Node(10) to Node(11), and then it finds a null, which exits the loop.
For the third n.appendToTail(), it loops once to move from Node(10) to Node(11), and then a second time to move from Node(11) to Node(12). Only then is it at the tail of the list, exiting the loop.

The reference n is always pointing to the first node. When you do
Node currentNode = this;
On every function call currentNode points to first Node.
So when you do
n.appendToTail (11);
no loop will run because there is only one node. When you do
n.appendToTail (13);
there are already three node so it will loop twice

Related

Using sentinel nodes in Linked List operations

I was solving a problem on Remove Linked List elements on Leetcode, when I came across the concept of "Sentinel/Dummy Nodes" through the provided solution. Using such nodes is supposed to make operations in Linked Lists easier in certain cases, such as empty lists or lists with one element, etc.
The problem description is -
Remove all elements from a linked list of integers that have value
val.
Example:
Input: 1->2->6->3->4->5->6, val = 6 Output: 1->2->3->4->5
The given solution is -
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel, curr = head;
while (curr != null) {
if (curr.val == val) prev.next = curr.next;
else prev = curr;
curr = curr.next;
}
return sentinel.next;
}
}
Let's consider this linked list -
1 -> 1 -> 2 -> 3 -> NULL, and the value of nodes to be removed being 1.
So, the result list should be 2 -> 3 -> NULL with head of this list pointing to 2.
In this line - sentinel.next = head; we make the sentinel as the first node in the list, with it's next node being "head", like so -
0 -> 1 -> 1 -> 2 -> 3 -> NULL,
Note that head still points to 1 (the first node with value 1 in the list).
Before the while loop begins, we set prev to sentinel and curr to head.
During the loop, prev and curr move along the list, both pointing to other nodes in the list. Note that head still points to the first 1.
After the loop, prev points to the last node in the list (with value 3), while curr becomes null.
However, head still refers to the very first node in the list (with value 1), and sentinel.next refers to this very node. So, when we run return sentinel.next -> we get a reference to this first node in the list (with value 1), whose next property doesn't point to any other node. So this is a node by itself.
How does this work correctly then? The ListNode that should be returned should refer to the node with value 2, not 1.
This is based on my knowledge about how references work in Java. Because, when we start out with this -
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel, curr = head;
We get something like this - [sentinel] -> [head] with prev pointing to sentinel and curr pointing to head.
But the problem is that both prev and curr change references during the list, while sentinel and head do not. So, sentinel.next still points to the old head.
EDIT 1
To make my question clearer, here's a screenshot of the result. What I want to know is - how does sentinel.next refer to the node with the value 2? At the start, sentinel.next was set to head, and this didn't change anywhere. So, sentinel.next should refer to the original head of the list - the node with value 1.
EDIT 2
I think I got it now. The change happens in this line prev.next = curr.next;
Because prev and sentinel both refer to the same list element (at this stage), sentinel.next gets set correctly.
I guess this might be incorrect:
when we run return sentinel.next -> we get a reference to this first
node in the list
prev does not move for the first two values, I guess. Only its link is being moved to the next node.
Another thing is that sentinel is final, does not change:
class Solution {
public ListNode removeElements(
final ListNode head,
final int val
) {
final ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel;
ListNode curr = head;
while (curr != null) {
if (curr.val == val) {
prev.next = curr.next;
}
else {
prev = curr;
}
curr = curr.next;
}
return sentinel.next;
}
}
Maybe it would be good to note that also we are not removing any values (values are there in the memory), we are just changing the links of the Linked List.
Finally, we are only interested in the head of the Linked List, which would be sentinel.next, we are not interested to see where prev is.
Iteratively
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null)
return null;
head.next = removeElements(head.next, val);
return head.val == val ? head.next : head;
}
}
The link in between 1 and 1 is still there, forgot to draw that.

reversing a singly linked list by recursion

This is the code for reversing a singly linked list by recursion:
public static LinkedListNode reverse_recursive(
LinkedListNode head) {
if (head == null ||
head.next == null) {
return head;
}
LinkedListNode reversed_list =
reverse_recursive(head.next);
head.next.next = head;
head.next = null;
return reversed_list;
}
I know recursion is not the best way to solve this problem, but I can't figure out the what the code "head.next.next=head" is doing. I'm confused, please help me clear my mind. Thank you!
head.next.next = head
is assigning the current node (head) as the link of the node that was last visited by the recursion.
The recursion will begin from the last node in the list and will end on the first node.
Assuming you have the linked list A --> B --> C --> D --> NULL
It will start reversing the above-mentioned list from node D and since node D's next is null, the recursion will immediately move to the next node, node C
What will happen is it's going to take head (which is now node C), and assign as node D's next
This will happen until there are no more nodes left to traverse
head --> A
.next --> B
.next --> C
So, in the above example head.next references the node B, and head.next.next referenced the node C.
head.next.next = something
is thus the equivalent of
nodeB.next = something
In your code, something is head. And head references the node A. So it assigns a new value to the next node of the node B, and this new value if the node A:
head --> A <---------------
.next --> B |
.next --
The following instruction is
head.next = null, which thus leads to
head --> A <---------------
B |
.next --
public static LinkedListNode reverse_recursive(LinkedListNode head) {
if (head == null || head.next == null) {
return head;
}
If the node(in our case head) equals to null or the next node equals to null
(meaning that there is only one node) then return that one node because you can't reverse a null reference or a list with only one node(basically it's already reversed). This is the base case for the recursive solution.
LinkedListNode reversed_list = reverse_recursive(head.next);
We send the next node into the recursive function e.g. if our list has three nodes 1->2->3 then we would be sending the second node into reverse_recursive function. The function would return 3->2 and reversed_list would point to node 3. And now we need to connect node 1 to the reversed list 3->2.
head.next.next = head;
head.next (node 2) will point to (head.next.next) node 1 (head).
head.next = null;
Since node 1 is the last node it should point to null, meaning that there are no more nodes.
return reversed_list;
And now we only need to return the correct reference (the first node of the reversed list).

Algorithm: Merge Sort with linked list missing items

I am trying to sort my linked list with merge sort. The list is actually sorted but it is kind of missing first item(s).
Merge sort functions:
public Node mergeSort(Node head) {
if (head == null || head.next == null) {
return head;
}
Node middle = middleElement(head);
Node nextofMiddle = middle.next;
middle.next = null;
return merge(mergeSort(head), mergeSort(nextofMiddle));
}
public Node merge(Node left, Node right) {
Node temp = new Node();
Node newHead = temp;
while (left != null && right != null) {
if (left.info <= right.info) {
temp.next = left;
temp = left;
left = temp.next;
} else {
temp.next = right;
temp = right;
right = temp.next;
}
}
temp.next = (left == null) ? right : left;
return newHead;
}
public Node middleElement(Node head) {
if (head == null) {
return head;
}
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
So I printed the list to the screen using traverse:
public static void main(String[] args) {
MyLinkedList mll = new MyLinkedList();
mll.insert(3);
mll.insert(5);
mll.insert(9);
mll.insert(1);
mll.insert(8);
mll.insert(7);
mll.insert(2);
mll.mergeSort(mll.head);
mll.traverse();
}
I have result like this:
1 and 2 missing!
After checking, i noticed that the "tail" of the linked list value is still 2. I don't know why can someone help?. I'm really new to programming so sorry for any inconvenience. Thank you for reading!
You're not far from a correct solution. I was able to get a working sort by adding 1 line and changing 3.
Your merge isn't doing what you think it is.
Allocating a false head node (what you call temp, not a good choice of name; try falseHead) is a fine idea. Then falseHead.next is the true head. That's what you'll finally return as the sorted list. Note that initially it's null, which is what you'd expect.
What you're missing is a variable tail to reference the current last node in the merged list. Since there is initially no last node at all, this should be initialized equal to falseHead. Consequently, when you append the first element to the tail of the current result by setting tail.next, you'll also be setting falseHead.next, i.e. creating the head element. It all works out.
Now, what is the logic for, say, removing the current head of the right list and appending it to the merge result? It's just 3 steps:
Do the append operation by making tail.next the current head of right.
Update tail to tail.next.
Remove the head of right by updating right to right.next.
Of course the left side is similar.
Good luck. You're close.
You have a couple problems that I can see. One, mentioned by #rcgldr, in the comments is that you merge method is returning the temp node newHead, but that node was no value and is not part of your graph. You need to return it's child newHead.next.
The other problem is that you never reset the head of your list. So after all the sorting, the head of mll still points to the original head, which in this case is 3. So when you traverse the list you skip 1 and 2. I'm not sure what your linked list class looks like but something like this should be close -- just assign the final node returned by mergeSort to the head of the list. Then when you traverse you should be starting in the right spot:
mll.head = mll.mergeSort(mll.head);
mll.traverse();

linked list java refernce

I got a linked list java implementation.But one part i dont understand.my class is
class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
}
and i have a fn to insert
public static Node insert(Node head,int data) {
Node current = head;
if(head!=null){
while(current.next!=null){
current = current.next;
}
current.next = new Node(data);
return head;
} else {
return head=new Node(data);
}
}
the thing i dont understand is ,first we set the head to a current variable.
and passing next node to the current object for traversal.
My question how it works, since current has ref of head, so when you assign another value technically you are changing head. i could see that with int data.if i update current.data to 0 then i see head is get affected..
may be it is a below par question but please help me to understand whats happening here...
Basically this function is adding new element as a HEAD element of the linked list collection. Every element has a reference to a NEXT element, so it traverses as long as next element does not exist and then it sets it to the new element (having the data that you passed to the function).
I'm not sure if I understand your concerns, but by changing "current" variable, you are simply changing the "reference" to an object, not changing objects themselves. So you just change the reference as long as the next item does not exist and then you create a new object and set is as referenced by former head (and this object becomes a new head)
I rearranged the code, to make it easier to understand, and added comments :
/**
*Insert a leaf node in a linked list
*#param head represents the head node of the list.
*#return the head node
*/
public static Node insert(Node head,int data) {
//if head does not exist, create it and return it
if (head==null) {
return head=new Node(data);
}
else{//head exist
//search for the end of the linked list (leaf, has no next node)
Node current = head;
while(current.next!=null){
current = current.next;
}
//at the end of loop the current.next == null (leaf)
//add new node as leaf
current.next = new Node(data);
return head; //return head unchanged
}
}
I hope it help to clarify.
When you are assigning a certain node (not just value) to the current node, you are NOT changing that certain node. Here, you have assigned head to be the current node. But that does not mean both nodes are now the same. They are still different. The head node will always have the same value UNTIL someone specifically types head = [enter another node here], assigning a different node to the head node. In Java, = means assignment and == means equals. So assignment and equals are two different concepts.
Example Singly Linked List: 1 -> 2 -> 3 -> NULL
(we know head = Node(1))
Now, suppose user calls insert(head, 4)?
Execution steps:
Node current = head, so current == Node(1) and head == Node(1) (current and head are two different nodes, but with same values for now)
head is null, so execute statements in if statement
current.next == Node(2) so it's not null. Execute statement in while loop
current = current.next so current is assigned Node(2)
current.next == Node(3) so it's not null. Execute statement in while loop
current = current.next so current is assigned Node(3)
current.next == NULL, so stop while loop
current.next = new Node(4), so we assigned Node(4) to current.next
Now we return list starting at head. And head = Node(1) still.
Result : 1 -> 2 -> 3 -> 4 -> NULL

given a node how can I find previous node in a singly linked list

Given the current node, how can I find its previous node in a Singly Linked List. Thanks. Logic will do , code is appreciated. We all know given a root node one can do a sequential traverse , I want to know if there is a smarter way that avoids sequential access overhead. (assume there is no access to root node) Thanks.
You can't.
Singly-linked lists by definition only link each node to its successor, not predecessor. There is no information about the predecessor; not even information about whether it exists at all (your node could be the head of the list).
You could use a doubly-linked list.
You could try to rearrange everything so you have the predecessor passed in as a parameter in the first place.
You could scan the entire heap looking for a record that looks like a predecessor node with a pointer to your node. (Not a serious suggestion.)
If you want to delete the current node, you can do that without finding previous node as well.
Python Code:
def deleteNode(self, node):
node.val = node.next.val
node.next = node.next.next
# Delete Node in a Linked List
Walk through the list from the beginning until you meet a node whose next link points you your current node.
But if you need to do this, perhaps you oughtn't be using a singly linked list in the first place.
Your only option for a singly-linked list is a linear search, something like below (Python-like pseudo code):
find_previous_node(list, node):
current_node = list.first
while(current_node.next != null):
if(current_node.next == node):
return current_node
else:
current_node = current_node.next
return null
Assuming that you're talking about a forward singly linked list (each node only has a pointer to 'next' etc) you will have to iterate from the start of the list until you find the node that has 'next' equal to your current node. Obviously, this is a slow O(n) operation.
Hope this helps.
Keep two-pointer(curr, prev) initially both will point to head of the list.
do a loop on the list until you either reach at the end of the list or at the required node.
for each iteration move curr node to the next of it but before moving to next store its pointer in prev pointer.
prev = curr; // first store current node in prev
curr = curr->next // move current to next
at the end of loop prev node will contain previous node.
getPrev(head, key) {
Node* curr = head;
Node* prev = head;
while(curr !=null && curr->data==key){
prev = curr;
curr = curr->next
}
return prev
}
Example:
list = 1->5->10->4->3
We want prev node of 4 So key = 4 and head point at 1 here
initially:
temp will point to 1
prev will point to 1
iteration 1:
First, assign prev=temp (prev point to 1)
move temp; temp->next (temp point to 5)
iteration 2:
First, assign prev=temp (prev point to 5)
move temp; temp->next (temp point to 10)
iteration 3:
First, assign prev=temp (prev point to 10)
move temp; temp->next (temp point to 4)
iteration 4:
temp->data == key so it will return out of loop.
return prev node
This is some kind of hack which I found out while solving the problem(Delete every even node in a list)
internal void DeleteNode(int p)
{
DeleteNode(head, p);
}
private void DeleteNode(Node head, int p)
{
Node current = head;
Node prev = null;
while (current.next != null)
{
prev = current;
current = current.next;
if (current.data == p)
{
prev.next = current.next;
}
}
}
Now here, in prev you assign the current and then move the current to next thereby prev contains the previous node.
Hope this helps...
You can do it like this.. you can replace the value of current node by value of next node.. and in the next of 2nd last node you can put null. its like delete a element from a string. here is code
void deleteNode(ListNode* node) {
ListNode *pre=node;
while(node->next)
{
node->val=node->next->val;
pre=node;
node=node->next;
}
pre->next=NULL;
}
Use a nodeAt() method and pass the head,size and the index of the current node.
public static Node nodeAt(Node head,int index){
Node n=head;
for(int i=0;i<index;i++,n=n.next)
;
return n;
}
where n returns the node of the predecessor.
Here is a small trick with linear search: just pass in the node or its position whose previous node you are searching for:
private MyNode findNode(int pos) {
//node will have pos=pos-1
pos-- = 1;
MyNode prevNode = null;
int count = 0;
MyNode p = first.next; // first = head node, find it however you want.
//this is for circular linked list, you can use first!=last for singly linked list
while (p != first) {
if (count == pos) {
prevNode = p;
break;
}
p = p.next;
count++;
}
return prevNode;
}
We can traverse through the LinkedList using slow and fast pointers.
Let's say
fast pointer fast = fast.next.next
slow pointer slow = slow.next
Slow pointer will be always a previous of the fast pointer, and so we can able to find it.
It can possible to deleteNode if only given node not root or head. How ?
It can achieve by reversing value in node
4-> 2 -> 1 -> 9 given 2 as node to remove. as above other can't access previous node which is correct because singly linked list we don't store predecessor. What can do is swap value of next of give node to given node and change link to next of next of give node
nextNode = node.next // assigning given node next to new pointer
node.val = nextNode.val // replacing value of given node to nextNode value
node.next = nextNode.next // changing link of given node to next to next node.
I tried this approach and its working fine.
assuming you are using forward singly linked list your code should look like
while(node)
{
previous = node
node = node.next
// Do what ever you want to do with the nodes
}

Categories