I am trying to see how I can update a reference variable in Java methods in a better way. I know that Java references are pass by value - in other words, if I change the value of the reference in a method, it wont retain it in the caller method. But at the same time, I am trying to see how I can deal with these situations better. In most cases we need to return value from a method in recursion, say its base case, just like below where I resort to maintaining a static variable to hold the new head of a linked list that is being reversed. What are the more sensible options that I can use here?.
public static LinkedList _head = null;
public static LinkedList reverseLinkedList(LinkedList head)
{
reverseLinkedListInternal( head );
return _head;
}
public static LinkedList reverseLinkedListInternal( LinkedList node )
{
if( node.next == null )
{
_head = node;
return node;
}
LinkedList tmp = reverseLinkedListInternal( node.next );
tmp.next = node;
node.next = null;
return node;
}
You just don't need the static variable here. You should be just using the return value, whereas at the moment it's simply being ignored.
This is the kind of solution I would write. Obviously this might not fall into the constraints of your exercise as it is written as if it were a method of a LinkedList, which would make a lot more sense in the real world. However the concept is the same, so hopefully it will help you to spot your mistakes.
public void reverse() {
reverseInternal(head);
}
public Node reverseInternal(Node node) {
if (node.next == null) {
return node;
}
Node reversedTail = reverseInternal(node.next);
reversedTail.next = node;
node.next = null;
return reversedTail;
}
Related
public class Reverse {
public static void printLL(Node head) {
while(head!=null){
System.out.print(head.getData()+"-->");
head=head.next;
}
}
public static Node reverseLL(Node head){
if(head == null) {
return head;
}
return reverseLL(head.next);
}
public static void main(String[] args) {
Node first=new Node(10);
Node head=first;
Node second=new Node(20);
first.next=second;
Node third=new Node(30);
second.next=third;
Node fourth=new Node(40);
third.next=fourth;
printLL(head);
System.out.println("\nReverse of Linked List is \n");
head=reverseLL(head);
printLL(head);
}
}
Here is my code. It is not printing anything.
I think that due to recursion, it is pointing to the null pointer and hence no data is present at null position.
Please tell me what can I do to make the code correct.
Thanks in advance
Your reverseLL simply goes through all the Nodes and when it reaches the last one doing if(head==null), null is returned.
You need to fix the reverseLL function. Try adding traces into the function to understand what it does step by step.
You seemn to have missed a crucial point about recursion - you have to call yourself.
I will suggest a change to printLL that should demonstrate one possible recursive solution that should work.
public static void printLL(Node head) {
if (head != null) {
System.out.print(head.getData() + "-->");
printLL(head.next);
}
}
Note how the code basically says if there is a head, print it's data and then print it's head.next.
The problem is that your reverseLL does not do anything to the head after calling itself recursively.
The base case is right: when head is null, you return null. The recursive step, however, is not complete: you need to reverse the rest of the list, but then you have to attach it back to the head.
The simplest way to accomplish this is to pass an extra parameter for the prior node, so that you could do
head.next = prior;
inside your recursive method. Here is how your "wrapper" method would look:
public static Node reverseLL(Node head) {
if(head==null){
return null;
}
return reverseLL(head, null);
}
Note that it is not recursive - all it does is calling a two-argument overload.
The recursive method knows that head is never null, so its base case is head.next == null:
public static Node reverseLL(Node head, Node prior) {
Node res;
if (head.next == null) {
res = head;
} else {
res = reverseLL(head.next, head);
}
head.next = prior;
return res;
}
The reversal of the head node is done in the assignment prior to the return. Note how the method returns the last non-null node in the chain.
Demo
I'm revising Linked Lists and in the book I'm using they suggest the following code to search for a specific value:
public ListElement<Integer> find( ListElement<Integer> head, int data ){
ListElement<Integer> elem = head;
while( elem != null && elem.value() != data ){
elem = elem.next();
}
return elem;
}
But, cannot we iterate on head directly?
You can - but then it would be a somewhat misleading piece of code. If I look at a variable called head, I'd expect it to be the head of a list - whereas if I do:
head = head.next();
... then head refers to something which isn't the head of the list. It's always worrying when a variable name implies something that isn't true. It would technically work, but it would be a bad idea.
I would personally write the code more like this:
public ListElement<Integer> find(ListElement<Integer> head, int data) {
for (ListElement<Integer> current = head;
current != null;
current = current.next()) {
if (current.value == data) {
return current;
}
}
// No entry found
return null;
}
That way the "not found" case is more naturally distinct from the "found" case - it would be easier to change it to throw an exception if the value isn't found, for example.
I'm learning Java & Data structures.
I made a method that removes all the linked list. Here is the code:
public class LinkedList {
...
public void purge() {
SLLNode nextNode, iterator = headNode;
while(iterator != null) {
nextNode = iterator.getNext();
iterator = null;
iterator = nextNode;
}
}
...
}
And here is the main method:
public class SinglyLinkedList {
public static void main(String[] args) {
SinglyLinkedList test = new SinglyLinkedList();
test.insert(1, 0); // insert(data, position)
test.insert(2, 1);
test.insert(3, 2);
test.insert(4, 1);
test.purge();
test.printList(); // Still prints elements!
}
}
So after all of insertion, the list is: 1-> 4 -> 2 -> 3, but the method purge() doesn't remove elements - the method printList() still prints the values in the linked list. But I can purge the linked list like:
public void new_purge() {
headNode = null;
}
But the purge() method doesn't look like have a problem.. probably it's lack of Java understanding, but why the method purge() doesn't work here?
The problem is that you are assigning headNode to a local variable SLLNode nextNode, iterator = headNode; and then set it to null but your global (class instance) variable headNode is not affected.
As a side node, In Java, you should not worry about manual memory management in such cases as the Garbage Collector will free the memory. Assuming that the nodes are internally handled by the linked list class, setting the head to null is enough.
Small mistakes in your purge method.
public void purge() {
SLLNode nextNode, iterator = headNode;
while(iterator != null) {
nextNode = iterator.getNext();
// iterator = null; -- does nothing.
iterator.setNext(null); // You want to remove the pointer on the next element
iterator = nextNode;
}
headNode = null; // Remember to clear also your head pointer.
}
But you should use LinkedList in the JAVA api.
Basically, the problem is that you are overwriting your iterator pointer rather than the node's pointer. You are not actually affecting your nodes at all.
Your new_purge method should actually work and in fact is much faster (~n rather than ~2n).
Firstly, the method purge() could be more efficient regarding memory. It'd be:
public class LinkedList {
...
public void purge() {
SLLNode iterator = headNode;
while(iterator != null) {
iterator = null;
iterator = iterator.getNext();
}
}
...
}
You can remove the variable nextNode. And can you post your method insert?
I'm preparing for interviews and wrote up this simple function for recursively reversing a singly linked list. The first node is a sentinel node, head. The following code works fine for: list.reverse(list.head.next), but I can't seem to get it to work if I just pass it head.
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
reverse(current.next).next = current;
current.next = null;
return current;
}
I assume it doesn't work when I pass it head instead of head.next because I say current.next = null, but even if I check if current == head or if current.data == null and only use current.next = null when those aren't true, it still doesn't work. I'm sure there's a really simple fix, but I'm just not seeing it right now.
The above if passed head returns an empty list, and if the suggested changes are made, simply doesn't finish running, but I don't get any sort of error.
(EDITED)
I kind of get your problem now:
Simply speaking, the sentinel head acts simply as a pointer to the first node, instead of being part of the linked list. Therefore it will not be involved in the reverse process, and need to handle separately.
which means, the original list looks like:
HEAD -> a -> b -> c -> null
after reverse, it should look like
HEAD -> c -> b -> a -> null
In brief, it should look like (assume your code already works when passing in head.next)
public Node<T> reverse(Node<T> current)
{
if (current == head) {
return reverse(current.next);
}
// rest of your original code.
}
Just a further suggestion:
Your reverse() method, as an public instance method of your list class, shouldn't accept the current node, as it is conceptually meaningless for caller.
I believe you should make this method protected, which means something like:
public void reverse() {
this.head = reverseInternal(head);
}
private Node<T> reverseInternal(Node<T> node) {
// your original reverse logic
}
With such encapsulation, you don't even need to struggle before how to make your reverse works when you pass in the sentinel head: you can simply call reverseInternal(head.next) in your public reverse() method.
First: if it returns an empty list it doesn't "work".
There is no need for head to be an empty node. You should normally just keep the first node (in your case list.head.next) as your list.head. head should be a reference to where the list starts, not a separate node.
The reason your code empties the list when you pass it list.head is it sets list.head.next to null. This is because you assume the node you pass to the list is a regular one, while your head node is special.
Here's a solution for your assumptions (I'll assume someone insisted on this bizarre detached head thing. Just don't do it if you're designing the list yourself. Please...)
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
Node<T> temp = current.next;
current.next = null;
head.next = temp;
reverse(temp).next = current;
return current;
}
Explanation: This still sets the last node's next to null, but it pushes the list's head one spot down as it runs through the list, eventually pointing it to the last (now first) member.
This reeks of homework.
But still.
In general:
f(Node<T> current, ...) {
f(current.next, ...);
}
For a list a > b > c > d > e sitting in the midle at d, one
probably has built c > b > a already, so guess what is needed as additional parameter to f?
Good luck.
After comments:
public Node<T> reverse(Node<T> current)
{
return reverseRec(current, null);
}
/**
* #param current to-do (sub-)list.
* #param resultDone done reversed list sofar.
* #return reversed result.
*/
public Node<T> reverseRecursively(Node<T> current, Node<T> resultDone)
{
if (current == null) {
return resultDone;
}
Node<T> next = current.next;
current.next = resultDone;
return reverseRecursively(next, current);
}
I have developed a code to merge two already sorted linked lists in java.
I need help with the following:
How do I retain the value of head node of merged list without using tempNode?
Can this code be better optimized?
public static ListNode mergeSortedListIteration(ListNode nodeA, ListNode nodeB) {
ListNode mergedNode ;
ListNode tempNode ;
if (nodeA == null) {
return nodeB;
}
if (nodeB == null) {
return nodeA;
}
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode = nodeA;
nodeA = nodeA.getNext();
}
else
{
mergedNode = nodeB;
nodeB = nodeB.getNext();
}
tempNode = mergedNode;
while (nodeA != null && nodeB != null)
{
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode.setNext(nodeA);
nodeA = nodeA.getNext();
}
else
{
mergedNode.setNext(nodeB);
nodeB = nodeB.getNext();
}
mergedNode = mergedNode.getNext();
}
if (nodeA != null)
{
mergedNode.setNext(nodeA);
}
if (nodeB != null)
{
mergedNode.setNext(nodeB);
}
return tempNode;
}
1: You have to keep a record of the first node, which means you will have to store it in a variable such as tempNode.
2: No. There's not much to optimize here. The process is quite trivial.
There are a few possibilities:
1) Instead of using mergedNode to keep track of the previous node, use nodeA.getNext().getValue() and nodeB.getNext().getValue(). Your algorithm will become more complex and you will have to deal with a few edge cases, but it is possible to eliminate one of your variables.
2) Use a doubly linked-list, and then use either nodeA.getPrev().getValue() and nodeB.getPrev().getValue() instead of mergedNode. You will also have to deal with edge cases here too.
In order to deal with edge cases, you will have to guarantee that your references can not possibly be null before calling getPrev(), getNext() or getValue(), or else you will throw an exception.
Note that the above modifications sacrifice execution time slightly and (more importantly) simplicity in order to eliminate a variable. Any gains would be marginal, and developer time is far more important than shaving a microsecond or two off of your operation.