Why is head.data = 0 when head.next == null? - java

Working on a HW assignment. The assignment is to reverse a linked list recursively. I just don't understand why at my System.out.println(head.data) line head.data always prints as 0. Assuming I enter 4,5,6 (the fill and read methods for this work, if I put a print in my final else it will show that head is still 4, 5, 6) and head.next is null, doesn't that mean that head.data is equal to 6? I know I've got a lot of other problems going on with trying to reverse this, but I just don't understand why when head.next is null the head.data is 0. I thought head.next was the next item in the list, not the current one.
public static Node reverse(Node head)
{
Node n = new Node();
if (head == null)
{
return n;
} else if (head.next == null)
{
System.out.println(head.data);
n.data = head.data;
head.next = null;
n.next = reverse(head.next);
return n;
} else
{
reverse(head.next);
return n;
}
}

The following:
Node n = new Node();
if(head == null) {
return n;
}
results in the reverse of an empty list being a single-element list with the default value of data (presumably zero?)
Also, the final else is clearly not right, as it never does anything to n before returning it.

Related

Why can't I reverse a linked list in this way without getting a null pointer exception?

this is my first question here. This may be a dumb question but I am having issues with understanding why the order specifically matters when reversing a linked list in this way.
So here I'm reversing a linked list, which works
ListNode prev = null, curr = head, next = head;
while (curr != null){
next = next.next;
curr.next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
which works just fine.
But why can't I do the following?
//edge cases:
if (head == null || head.next == null){
return head;
}
ListNode prev = null, curr = head, next = head.next; //change here
while (curr != null){
//line was previously here
curr.next = prev;
prev = curr;
curr = next;
next = next.next; //moved here
}
head = prev;
return head;
Why does it matter that I set next = next.next at the beginning of the while loop, rather than the end? Why can't I set next = head.next first and then iterate it at the end of the loop without getting a null pointer exception?
Just for the record, you can think of the reverse operation as popping from the input list and pushing onto the result. Less epic code results:
ListNode reverse(ListNode head) {
ListNode result = null;
while (head != null) {
ListNode elt = head; // pop into elt
head = head.next;
elt.next = result; // push elt onto result
result = elt;
}
return result;
}
When you make such a change, you change the state at which the loop condition will be verified. And this causes the issue.
In the working code, we have this loop invariant:
curr and next are equal. They are either both null or both reference the same node.
In the non-working code, this is not true, as now next is one step ahead. The corresponding loop invariant is now next == curr.next. So when curr is the tail node, next will be null. In the next iteration of the loop, next = next.next is executed, which is invalid as next was null, so this raises an exception.
It would work if you would make that statement conditional:
if (next != null) next = next.next;
Or this would also work:
if (next == null) break;
next = next.next;
But both these alternatives are not as elegant as the original code, as now there are two checks to be made in each iteration (the loop condition, and this extra check). In fact, this extra check is just the repetition of the loop condition as at that moment next and curr are equal.

Remove Duplicates from Linked List

So I have a linked list that I am trying to remove duplicates from.
My basic algorithm that I thought up is to pretty much use the runner technique. Where I keep two pointers to compare adjacent elements. If they are the same I change the pointer of p1 to point to p1.next.next if not I keep traversing the list. However I keep getting a null pointer exception in the solution I have typed.
Node RemoveDuplicates(Node head) {
// This is a "method-only" submission.
// You only need to complete this method.
if (head == null){
return null;
}
Node current = head;
Node runner = head;
while(current != null && runner != null && runner.next != null){
runner = runner.next;
if(runner.data == current.data){
if(current.next != null){
current = current.next.next;
}
}else{
current = current.next;
}
}
return current;
}
At the point that I exit the while loop current is null. Which I think is the problem. How would I return the head of the altered list.
OK, although you've already accepted an answer, here's some example code using recursion to remove the dups from an ordered list per your request in the comments. (if your list isn't ordered, order it :) )
public Node removeDups(Node root) {
if (root.next == null)
return root;
root.next = removeDups(root.next);
if (root.data == root.next.data)
return root.next;
return root;
} // call as root = removeDups(root);
As you mentioned, recursion isn't really necessary here but you're using a Node-based linked list which is recursively defined. So, when it makes sense, the elegance of the solution has its benefits.
What I like about it is that you're not doing any node.next.next or needing to check for that null case. Once the stack starts unwinding, you're already in a position to start checking for dups. Then it's just a matter of comparing root.data and root.next.data; both of which you already know exist.
You can do this with single traversal with 2 pointer.and also this code works with single while loop.
public Node deleteDuplicates(Node head) {
Node current=head;
if (head == null)
return null;
else
{
Node runner=head.next;
while(head.next!=null && runner!=null)
{
if(head.val == runner.val)
prev=runner.next;
else
{
head.next=runner;
head=head.next;
prev=runner.next;
}
}
head.next=runner;
}
return current;
}
First of all, you'll want to return head at the end, so that you are returning the list, not just the last element.
Second thing, you'll want to modify the .next references instead of assigning them in some of the cases.
Note this doesn't work if the list isn't sorted.
Before: 1 1 3 3
After: 1 3
This code works (and I've tested it)
static Node RemoveDuplicates(Node head) {
if (head == null) return null;
Node current = head;
Node runner = head;
while (current != null && current.next != null) {
runner = current.next;
while (runner != null && runner.data == current.data) {
current.next = runner.next; // skip the repeat
runner = runner.next;
}
current = current.next;
}
return head;
}
You can do this in a single traversal. Just maintain two pointers temp
and next_of_next. Make temp iterate for each node and when the data of temp and the next node is equal, point next_of_next to the alternate node after temp and delete the node after temp.
Node removeDuplicates(Node head)
{
Node temp = head;
Node next_of_next;
if (head == null)
return;
while (temp.next != null)
{
if (temp.data == temp.next.data)
{
next_of_next = temp.next.next;
temp.next = null;
temp.next = next_of_next;
}
else
temp = temp.next;
}
return head ;
}
Here an apporach without recursion using a HashSet:
public void RemoveDuplicates()
{
if (head != null)
{
var hm = new HashSet<T>();
Node current = head;
Node prev = null;
while (current != null)
{
if (!hm.Contains(current.Value))
{
hm.Add(current.Value);
prev = current;
current = current.Next;
}
else
{
prev.Next = current.Next;
current = prev.Next;
}
}
}
return head;
}

Add method for custom LinkedList class

I have been working on this add method for a custom linkedlist lab I am working on. I cannot figure out how to shift values over by one index, once I insert the new node. Here is my source code.
public void add(int index, Object element) throws IndexOutOfBoundsException {
if(index > size() || index < 0) {
throw new IndexOutOfBoundsException();
}
ListNode newNode = new ListNode(element, null);
if(head == null) {
head = newNode;
return;
}
ListNode nextNode = head.nextNode;
ListNode currNode = head;
int i = 0;
while(currNode!= null) {
if(index == i) {
break;
}
currNode = nextNode;
//Breaks down here with null pointer exception
nextNode = nextNode.nextNode;
}
currNode = newNode;
currNode.nextNode = nextNode;
}
It is throwing null pointer as when you are iterating last node, next node points to null. Check for next node point to null also if you have to add new node in last.
Also in your code you are not increasing the value of i always it is iterating the whole list.
I don't really know what you are trying to achieve here, and I agree with #Pritam Banerjee's comment. But an obvious problem in your code is that you are never incrementing i, so you'll never break out of your while loop and at some point you are going to hit the end of your list and nextNode.nextNode is going to be null, hence your exception. (Also note that nextNode.nextNode will be null before currNode is.)

Why can't I remove occurrences in the linked list?

Problem: Given a value, remove all instances of that value from a linked list. More info below: JAVA
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode n = head; //1, 2, 6, 3, 4, 5, 6
while(n.next == null){
if(n.next.val == val){
n.next = n.next.next;
}
n = n.next;
if(n == null){break;}
}
return head;
}
}
Since its a pass by reference, it should be updating shouldn't it?
I tried:
removeElements([1,2,6,3,4,5,6], 6)
But it didn't remove anything. So what I am doing incorrectly?
There are a couple of issues:
you want to loop until a node is null not until is not null (i.e. while( ... != null))
you might want to loop until n is null, not until n.next is null, otherwise you'd skip the last element
you want to check for n.val == val not n.next.val == val, otherwise you'd skip the first element
if you check n you want to keep track of the previous node in case you need to remove n, i.e. prev.next = n.next.
if the first element (the head) is to be removed you need to replace the head, i.e. return the second element (this can be done by checking prev == null which would mean that n is the current head).
As mentioned by Thomas in his first point, you wrote the while loop incorrectly. Also, because you have a single linked list, you need to keep track of the previous node (also mentioned by Thomas).
public static ListNode removeElements(ListNode head, int val)
{
ListNode n = head;
ListNode prev = null; //the previous node.
while (n != null)
{
if (n.value == val)
{
//if prev is null it means that we have to delete the head
//and therefore we need to advance the head
if (prev == null)
{
head = n.next;
prev = null;//remains at null because there's nothing before head
n = head;//new head, let's start from here
} else
{
prev.next = n.next; //let's skip the element to delete
n = n.next;//let's advance to the next node
}
} else
{
//nothing to delete, let's advance to the next node and make
//the current node the previous node in the next iteration
prev = n;
n = n.next;
}
}
return head;
}
Its always a good practice to solve these questions with proper test cases. Design the possible test cases including the corner cases. Then follow your algorithm and see if it solves the problem for the test cases. Write the code and dry run it, this will do a sanity check of the code as well as of the logic.
Below are the cases for this question for which test cases must be written.
Null list,
List with one element and value being equal to the value to be deleted
List with one element and value not being equal to the value to be deleted
List with two elements and first node value being equal to the value to be deleted
List with two elements and last node value being equal to the value to be deleted
List with three elements and first node value being equal to the value to be deleted
List with three elements and second node value being equal to the value to be deleted
List with three elements and last node value being equal to the value to be deleted
Below is the code for the problem of removing nodes with a given value in a linked list.
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val){
head = head.next;
}
if(head == null){
return null;
}
ListNode node = head;
while(node.next != null){
if(node.next.val == val){
node.next = node.next.next;
}else{
node = node.next;
}
}
return head;
}

Why doesn't this merge-sort function cause an infinite loop?

I'm working on a project that requires me to implement merge-sort on a linked list and I am using the code from this post Here to help me. Can someone explain to why on line 6, when I call return merge(merge_sort(head),merge_sort(sHalf)); the method merge_sort(head) inside of it, which contains the same head pointer doesn't cause an infinite loop? It seems to me that it is starting all over again with the same head pointer.
public Node merge_sort(Node head) {
if(head == null || head.next == null) { return head; }
Node middle = getMiddle(head); //get the middle of the list
Node sHalf = middle.next; middle.next = null; //split the list into two halfs
return merge(merge_sort(head),merge_sort(sHalf)); //recurse on that
}
//Merge subroutine to merge two sorted lists
public Node merge(Node a, Node b) {
Node dummyHead, curr; dummyHead = new Node(); curr = dummyHead;
while(a !=null && b!= null) {
if(a.info <= b.info) { curr.next = a; a = a.next; }
else { curr.next = b; b = b.next; }
curr = curr.next;
}
curr.next = (a == null) ? b : a;
return dummyHead.next;
}
//Finding the middle element of the list for splitting
public Node getMiddle(Node head) {
if(head == null) { return head; }
Node slow, fast; slow = fast = head;
while(fast.next != null && fast.next.next != null) {
slow = slow.next; fast = fast.next.next;
}
return slow;
}
It's because of the previous line:
Node sHalf = middle.next; middle.next = null;
Specifically, the middle.next = null; part.
Understand that even though the head pointer is the same, we are splitting the list into half, using middle.next = null. So, in the next recursive call, it's only half the linked list which was sent originally.
And at one point, it will reach head.next == null condition.

Categories