I need to make a method that removes the last element of a LinkedList using recursion.
This is what I have so far but it doesn't seem to be removing the node...when i call list.size() it is still the same size with the same values. What am I doing wrong here?
This is for Java by the way
public void removeLastElement(Node curr){
if (curr == null)
return;
else{
if(curr.next == null)
curr = null;
else
removeLastElement(curr.next);
}
}
In a LinkedList to remove the last element you have to get the penultimate element and set
curr.next = null
You're in the right way to get the recurrent function to remove the last node. The problem is you're identifying the penultimate node with curr.next == null, if you got it, you nullify it, but that's your actual input! So, you must check if the actual node is the antepenultimate node on the list:
if (curr.next.next == null) {
curr.next = null; //Now you're modifying the data in your input.
}
With this change, there are more basic cases to check, but that's up to you, my friend.
Boolean deleteLast(Node n)
{
if(n.next == null)
return true;
if(deleteLast(n.next))
{
n.next = null;
return false;
}
return false;
}
Node deleteLast(Node n) {
if (n.next == null)
return null;
n.next = deleteLast(n.next);
return this;
}
The general idea is you ask the next node "hey, can you tell me where you are, and delete your last node?" The last node can then just say "I'm nowhere" and it'll all fall into place.
This is very similar to Aadi's answer, just using Nodes instead of booleans.
Related
My problem is my delete method isn't deleting the node I want to delete and giving me a infinite loop.
public void delete(String name){
Node current = head;
boolean checker = false;
while(current != null && current.name != name && checker != true){
try{
if(current.name.equals(name)){
Node p = current.previous;
Node q = current.next;
/*The code can somehow get through only above this line, below here its not anymore*/
p.next = q;
q.previous = p;
System.out.println("Item successfully deleted.");
checker = true;
}else if(!current.name.equals(name) && current == tail){
System.out.println("Item not found.");
}
current = current.next;
} catch(NullPointerException e){}
}
}
Im here to asking for a hint or tip about my problem
(Sorry for my bad english)
You are checking if you have reached the end of the list current == tail but not breaking out of it. You can add a break statement inside your else if.
Other than that, you are using == to compare strings. I'm not sure why you added that there and it can be removed. Also, you must (almost always) never catch a NullPointerException.
"infinite loop" means your loop condition is incorrect, you are not making progress in each iteration, or there is a cycle your data. You use both current == null and current == tail to signify that it's the last element. Choice one way. Suggest you rewrite your loop condition to only deal with iteration, and have a conditional with a break if you have a match in the body:
for(current = head; current; current = current.next) {
if(current.name.equals(name)) {
if(current == head)
head = current.next
else
current.previous.next = current.next;
if(current == tail)
tail = current.previous;
else
current.next.previous = current.previous;
break;
}
// if tail.next is not initialized to null
// if(current == tail) break;
}
I see a potential infinite loop with no side effect here. If your list contain a node with node.name set to null then the invocation of current.name.equals(name) results in a NullPointerException. If you are at either end of the list the next or previous pointers will be null which will also result in the same exception. This exception is caught and discarded. Note that this prevents the advance of the current pointer which causes the same iteration to occur. At the very least make sure to print out the exception even if you're not taking any other action. It'll help with debugging.
Your while loop condition is overly complicated. while(current != null) should suffice given that:
Using if(current.name.equals(name)) removes the need for current.name != name. Also, don't use == or != for string comparison. It is a pointer comparison. Most equals methods take care of pointer comparisons.
Use a break or return for flow control here and remove checker boolean. The tail.next should always point to null to signify the end of the list. The only reason I see to have the checker boolean is if delete should remove all matching nodes and you want to know if it happened at least once. From what I see in the code that is not the case.
I would rewrite this as:
public void delete(String name){
Node current = head;
while(current != null){
try{
if(current.name.equals(name)){
...
return;
// Do not advance current here. Refer to finally block below.
}
} catch(NullPointerException e){
e.printStackTrace();
return; // If function should stop on error.
} finally {current = current.next;} // This prevents the repeat as it always happens.
}
System.out.println("Item not found.");
}
Note if you use "break" instead of "return" then the "Item not found." line will always print. You'd have to guard it with an if statement and a flag.
public void delete(String name){
Node current = head;
while(current != null){
if(current.name.equals(name)){
if(current.prev != null){
current.prev.next = current.next
}
if(current.next != null){
current.next.prev = current.prev
}
System.out.println("Removed node")
break;
}
current = current.next;
}
}
You could use this logic to delete the node that matches the name(given name is always present) if node is non null.
I am using a linked list without using collections class for data structure practice.
I wanted to remove an element from the linked list after passing the element value to function
This is the function that i've written.
public boolean remove(String s)
{
if(head.getName().equalsIgnoreCase(s))
{
head = head.getNext();
return true;
}
else
{
Node p =head;
Node current=p.getNext();
while(true) {
if(current == null || current.getName().equals(s)) {
break;
}
p = current;
current = current.getNext();
}
if (current == null)
{
p.setNext(current.getNext());
return true;
}
}
return false;
}
i'm using Node p to store the previous node and current node.
The code falls in the return false section and there is no change in the list.Also i'm getting a null pointer exception warning in the p.setNext(current.getNext()) here.
Please let me know where i'm making mistake.
Regarding the Null Pointer Exception this should ring a bell
if (current == null)
{
p.setNext(current.getNext());
return true;
}
current is null and you are trying to invoke a method from it.
Also it doesn't seem you handle the corner cases like the list is empty or having one element.
current == null
is the not found case. When current == null we should return false, and calling current.getNext() will give the null pointer error. Similarly, the found case is not getting into the block you want. It should suffice, I think, to say if (current != null) where you have if (current == null)
I found https://www.geeksforgeeks.org/linked-list-set-3-deleting-node/ helpful.
Instead of checking true condition based on current value which possibly may or may not be null, you should be having one boolean flag.
This flag value can be made true if you find the passed element.
while(true) {
if(current == null || current.getName().equals(s)) {
flag = true;
break;
}
p = current;
current = current.getNext();
}
if (flag)
{
if(current!=null)
p.setNext(current.getNext());
return true;
}
I am trying to write a "contains" method for a splay tree to figure out if a node is already in the tree. I give this method a node to start searching and a string key to use find the corresponding node. I think I have a pretty good handle on recursion, but I am stumped by this. I've bolded the two lines that are causing the infinite recursion, but I'm stuck because, unless you somehow have a tree with an infinite number of elements, wouldn't the left and/or right elements have to be null at some point? They cannot be != to null forever! I might be losing my mind but I would very much appreciate any clarification on how to create a stronger base case.
tldr: how is it possible for this function to recurse infinitely when we have to run into null at some point?!
public BST_Node containsNode(BST_Node node, String s) {
BST_Node result = null;
if (node == null) {
return null;
}
if (node.data.compareTo(s) == 0) {
splay(node);
return node;
}
if (node.left != null) {
result = containsNode(node.left, s); //recursion here
}
if (result == null && node.right != null) {
result = right.containsNode(node.right, s); //recursion here
}
return result;
}
}
I'm writing a LinkedList class for an assignment and I'm writing my insert method and was wondering if I could get it looked at.
private Node first; // start of the list
private class Node {
private Item item;
private Node next;
}
public boolean insert(Item item) {
// add item to list if it doesn't already exist
// return true if a new Node is created, otherwise false
if ( first.next == null && first.item == item) {
return false;
}
Node ptr = first;
while (ptr.next != null) {
if (ptr.item == item) {
return false;
}
ptr = ptr.next;
}
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
return true;
}
For the most part I think it's okay, but everytime I try to trace the insert method I end up confusing myself and messing up all the reference changes. Can someone tell me if I'm doing it right? Any other improvements would be appreciated too.
I would consider writing an extra function for checking if the Item is already in the list. This would make the insert function more clear and the whole reference changing would only be there. Also your first test:
if ( first.next == null && first.item == item) {
return false;
}
does nothing else then the first iteration of the while loop.
You should definitely initialize first so that you don't throw a NullPointerExcpetion as #threenplusone said or check if:first == null. (the first ptr.next in your while-loop throws a NPE if first is null)
Also you should compare your items by equals as #Thilo said.
The rest is correct I think.
Your insert method is not OO - you're using a while loop to traverse the list, so this method could be a static method (if you also passed in the first node).
A more elegant way would be:
In pseudo-code:
insert(item) {
if (next == null)
add item to "this" // we are at end of list
else
next.insert(item) // hand item to the next node
}
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.