LinkedList remove conditions (last iterated item) - java

I am attempting to remove the last iterated element, with a custom iterator/linked list class. It for some reason only does this for the first item in the list (the head condition). Is there anything wrong with the conditions?
Should I, instead of the Else after If (prev=head), write If (next != null) to find middle nodes, and If (next = null) to find the last node?
Second question: to remove the items, should I also write prev.element = null (now I only have prev = null, and I suppose that erases the node but not its content.
Quite simply, what is wrong with my remove method, as I cannot figure it out myself. Thank you guys so much in advance. I have been working many hours with this but I still haven't got it working.
public E next() {
if (!hasNext())
throw new NoSuchElementException ();
prev = next;
E element = next.element;
next = next.next;
return element;
}
public void remove() {
if(prev == null) {
throw new IllegalStateException();
}
else {
if(prev == head){
head = head.next;
next = head;
}
else {
next = prev.next;
}
sizeOfList--;
prev = null;
}
}

You would need a while loop to be able to go through every node in the list until you hit the last one. As it is now, your code simply goes past the head, and then gets into the code that says sizeOfList-- and then prev = null;
You need something like this:
while (prev.next.next != null) {
prev = prev.next;
}
prev.next = null;
I do prev.next.next so that you can set the 2nd to last node in your linked list to point to a null value (which is done by prev.next = null;). Think of it this way: prev is the 2nd to last element in the list, prev.next is the last element, and obviously prev.next.next HAS to be null (because prev.next is LAST.) So once this is the case, delete the last element by setting the 2nd to last element to point to a null value.
And then decrement your list count.

This is my best guess with the given code
if(prev == head){ should change to if(prev.equals(head)){ Use equals method.
And I think you have to override equals method in the corresponding element class might definitely help.
== only checks for whether both variables refer to same object in memory, where as equals check Object state.
I hope it helps :).

Related

Recursively delete the last occurrence in a linked list, Java

class Link{
private int value;
private Link next;
}
I am asked to write a recursive method to delete last occurrence of a certain value, say 4.
before 2->3->4->5->4->2
after 2->3->4->5->2
The last occurrence only. I know how to delete all occurrence but I can't tell if its the last occurrence. No helper method is allowed.
The one to delete all occurrence
public Link deleteAll(){
if (next == null){
return value==4ļ¼Ÿ null:this;
}else{
if (value == 4){
return next.deleteAll();
}
next = next.deleteAll();
return this;
}
}
You can declare a pointer to the last occurred node and delete that node when reached the last element in list. Following steps explains that -
Declare two pointers one is next as in your above code another can be temp.
Iterate through list using next like you doing in deleteAll method above.
If you find the node you looking for assign that node to temp.In your case 4.
When next is null you reached the end of list now delete, whatever node is in temp delete that node. If temp is still null than no node found in given key.
EDIT:
Possible pseudo Code in case of recursion:
public void deleteLast(Node node,Node temp,Node prev, int data)
{
if(node==null)
{
if(temp!=null && temp.next.next!=null){
temp.next = temp.next.next;}
if(temp.next.next==null)
temp.next = null;
return;
}
if(node.data==data)
{
temp = prev;
}
prev = node;
deleteLast(node.next, temp, prev, int data);
}
Above code should be able to solve your problem. I made some edit in my approach which should be obvious from the code but let me describe it below
I added a prev pointer. Because if we want to delete a particular node we need to assign its next to prev node's next.So, we need the prev node not the node that we want to delete.
I think this change will follow in iterative approach too.
Not really answering your exact question, but as an alternative option, you might consider the following.
Write a recursive method to delete the first occurrence of a specified value, something like this:
public Link deleteFirst(int target) {
if (value == target) {
return next;
}
next = (next == null) ? null : next.deleteFirst(target);
return this;
}
Then you could write a reverse() method as either an iterative or recursive method as you see fit. I haven't included this, but googling should show some useful ideas.
Finally the method to remove the last occurrence of a value from the linked list could then be written like this:
public Link deleteLast(int target) {
return reverse().deleteFirst(target).reverse();
}
Note that as long as your reverse() method is linear complexity, this operation will be linear complexity as well, although constants will be higher than necessary.
The trick is to do the work on the way back -- there is no need for additional parameters, helpers or assumptions at all:
Link deleteLast(int target) {
if (next == null) {
return null;
}
Link deleted = next.deleteLast(target);
if (deleted == null) {
return value == target ? this : null;
}
if (deleted == next) {
next = deleted.next;
}
return deleted;
}

Descending ListNode Iterator Implementation

My goal in this method is to write the implementation for an iterator that iterates through elements of a listNode in descending order. (From the back to the front) I have attached my implementation of the ascending iterator. Any help in the right direction would be appreciated.
public MyDescendingDequeIterator(ListNode<E> back, ListNode<E> front) {
frontOfList = front;
nextToReturn = back;
while (nextToReturn.next != null) {
nextToReturn = nextToReturn.next;
}
}
public boolean hasNext() {
if (nextToReturn == null){
return false;
} else {
ListNode<E> current = frontOfList;
return true;
}
}
public E next() {
ListNode<E> current = frontOfList;
while ( current.next != nextToReturn ) {
current = current.next;
}
nextToReturn = current;
return nextToReturn.data;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Provided it's a regular ListNode implementation that has only next() method, you'll need to implement the prev() method - the hasNext in that case is quite similar to the one you've implemented already.
The other approach is to hold the start of the list and to iterate each time until next element will be nextToReturn (and then update nextToReturn). This is less desired approach since you'll need to iterate O(m^2) from end to start of list of length m;
UPDATE:
OK, first of all you don't need number of elements, since it's quite opposite to the Iterator idea.
So let's say we have
public MyDescendingDequeIterator(ListNode<E> back, ListNode<E> front) {
frontOfList = front;
nextToReturn = frontOfList;
current = frontOfList;
}
Next thing is than you want to set the nextToReturn = back (now you don't use back at all). And you don't really need two variables, since nextToReturn is the current iterator.
So it transforms to:
public MyDescendingDequeIterator(ListNode<E> back, ListNode<E> front) {
frontOfList = front;
nextToReturn = back;
}
Now let's look on the next() method
As I said you don't need an indexed for here, since you've got frontOfList that has a next attribute.
So it could be:
public E next() {
ListNode<E> current = frontOfList;
while ( current.next != nextToReturn ) {
current = current.next;
}
nextToReturn = current;
return nextToReturn.data;
}
hasNext implementation should be straightforward from here. Just pay attention that according to the good coding standards the method that starts with is or has rarely changes the state of the object.
Note, that I also omit possible null checks here and other possible specific checks as is just an example of direction.
UPDATE 2:
As I think of it now, you don't need the second parameter in the constructor either, just this:
public MyDescendingDequeIterator(ListNode<E> front) {
frontOfList = front;
nextToReturn = front;
// calculate back here instead of get it as param
while ( nextToReturn.next != null) {
nextToReturn = nextToReturn.next;
}
}
UPDATE 3:
Look, it won't help to just start writing some code and expect it to work, you should sit down first and start drawing the boxes with the arrows on the piece of paper and then try to understand what each function should do.
As I said before, your hasNext() method has a bug and incorrect in general. Why do you check the null? You move from back to front, do you have a null at some place at the front? What do you need the current object for. What does it do?
The next() method should check also if you're already at the first element. Otherwise it will (and it does ) cause NullPointerException at the last element.
Try to debug first, or at least add some printouts, it helps to understand where the bug is. But first you should build the algorythm, only then start coding it, not vice versa.

Circular Linked List Node Insertion Java

I tried implementing the insert method for circular linked list. I think I had some success.
Problem:
When I display the list. The display method will loop because every next variable of the link is linked to a non-null node object. So head will never be a null object. From what I recall about singly linked list, head always point to the first node in the list or the first node with data inside of it.
My conceptual understanding of circular linked list:
From what I can understand circular linked is somewhat like a singly linked list but with a slight twist: the next variable of the tail object points to the head.
I'm coding it like the diagram has presented provided by the source link.
Source: http://sourcecodemania.com/circular-linked-lists/
public void insert(String data)
{
Link link = new Link(data);
if(head == null)
{
head = link;
tail= link;
}
else
{
tail.next = link;
tail = link;
tail.next = head;
}
}
public void display()
{
// good implementation for display #2
while(head != null)
{
// System.out.println (head.data);
head = head.next;
}
}
Once you insert at least one element, you would never come across null. It will keep on going till infinity.
Also, it might not be a good idea to modify head just for displaying the list. Operation like display should not have any side effects.
In stead, keep a member field size in your list class and update it in each insert and delete method.
Now you would know how many times you should iterate the loop.
ListClassName current = head; // Head is not modified.
for (int i = 0; i < this.size; i++) {
// System.out.println (current.data);
current = current.next;
}
Good luck.
You can keep a reference to the first Link object and check to make sure head is not equal to this object while looping:
public void display()
{
boolean first=true;
Link firstItem=null;
// good implementation for display #2
while(head != null && head!= firstItem)
{
if(first){
firstItem=head;
first=false;
}
// System.out.println (head.data);
head = head.next;
}
}

Implement an algorithm to delete a node in the middle of a single linked list, given only access to that node

Example input: the node ā€˜cā€™ from the linked list a->b->c->d->e Result: nothing is returned, but the new linked list looks like a->b->d->e
I do understand that ppl have already asked this question before, but since my reputation is not high enough yet, I couldn't ask my question in that thread. so here goes my quesetion:
So in the solution, when deleting the middle node we do:
public static boolean deleteNode(LinkedListNode n) {
if (n == null || n.next == null) {
return false; // Failure
}
LinkedListNode next = n.next;
n.data = next.data;
n.next = next.next;
return true;
}
But what I don't understand is that why can't I just do n = next?
It is probably a trivial question, but I didn't seem to find a good explanation for this question
If you just do n = next then you have only changed what object your local reference variable n refers to; you haven't modified any part of the list.
The trick to "deleting" the current node is to overwrite it with the next one:
n.data = next.data;
n.next = next.next;
Now you are modifying fields of the object that is referred to by n, which is a part of the actual list.
In C++, the code you wrote would look like this:
bool deleteNode(LinkedListNode* n) {
if (n == null || (*n).next == null) {
return false; // Failure
}
LinkedListNode* next = (*n).next;
(*n).data = (*next).data;
(*n).next = (*next).next;
return true;
}
So what does that mean? When you call this method, in C++ it would look like this:
LinkedListNode* listNode = new LinkedListNode();
deleteNode(&listNode);
This is important, because that means you're just sending an address over, and not the entire object. This means that you don't actually have access to the node you gave as a parameter to the method, you only have a reference to its address.
Basically, in Java, you can't do the following C++ code:
*n = *next;
You can't modify the listNode object that's outside of the method. You only get its address. And you are only modifying the copy of its address, not the address itself.
Basically, it's because in Java, the pointer of the class is passed by value (as a copy), and primitives are also passed by value (as a copy).
somehow, it overwrites the current node which is supposed to be deleted with the
data of next node to it,and delete the next node.
LinkedListNode next = n.next;
n.data = next.data;
n.next = next.next;
That is how the code comes.

LinkedList remove(), next, prev and head

I need to remove() from a (custom) LinkedList, setting last iterated item to null. There are two cases, one where prev is head, one where it is not. The nodes are next, prev and head. I was wondering if you spot any problems in the following code? Do I need to set the iterator variables in between? (or will emptying prev do the trick?) Thanks guys!
public void remove() {
if(prev == null) {
throw new IllegalStateException();
}
else {
if(prev == head){
head = head.next;
prev = null;
sizeOfList--;
}
else {
prev = null;
sizeOfList--;
}
}
}
In case your previous is not the head(second case in your code) you should fix the next link of the previous node before prev. Otherwise it will be left pointing to prev.

Categories

Resources