I am creating a double-linked list (has a previous and next pointer) from scratch using nodes. I'm trying to write the methods to implement a ListIterator and I'm having trouble figuring out how to write the remove method. I know it is probably something really simple but I don't have a lot of experience with iterators and I can't find a tutorial or post on this anywhere.
private Node<E> cur;
private Node<E> head;
public E next() {
if(size == 0) throw new NoSuchElementException();
if(cur.next == null) throw new NoSuchElementException();
return cur.next.value;
}
public boolean hasNext() {
boolean flag = cur != null;
return flag;
}
public void remove() {
//??????????????????
}
To delete a node, the prev node needs to point to next node, and vice versa (respective to current) . That's it. Pretty simple.
Edge cases to consider:
Deleting head node
Deleting tail node
Deleting last remaining node
I hope this is enough for you to code it yourself.
Related
I am trying to write an algorithm that checks if an input LinkedList is a palindrome or not. My algorithm is as follows:
Set a dummy node to point to the head of the input linkedList
Use a handler to store the reversed linkedlist
Run a loop to compare the values from front and back
My error: I know that the algorithm is wrong, because the output that I get seems to say that my original head is pointing in the wrong direction. I cannot figure out why, since I have used handler nodes while reversing as well.
The code is as follows:
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null) return true;
ListNode dummy = head;
ListNode MatchList = null;
MatchList=reverseList(head);
while(dummy!=null)
{
if(dummy.val!=MatchList.val)
{return false;}
MatchList=MatchList.next;
dummy=dummy.next;
}
return true;
}
public ListNode reverseList(ListNode head) {
ListNode dummy, newHead;
newHead=head;
ListNode another=newHead;
ListNode prev=null;
while(another!=null)
{
dummy=another.next;
another.next=prev;
prev=another;
another=dummy;
}
return prev;
}
}
The problem in your attempt is that when you reverse the list, it happens to that list. Yet your code deals with it as if it is a second list, independent from the first list. But because it is not, the head node has become the tail, and so after reverseList has been called, head.next (i.e. dummy.next) is going to be null.
A simple idea would be to change reverseList so that it creates a new list, calling the ListNode constructor for each node it encounters, but then linking them in the opposite direction.
This is however not an ideal solution, as it needs O(n) auxiliary space.
There is the following "trick" you can apply:
Find the middle node of the list (or if the size is even, the first one of the second half).
Reverse the list that starts at that node, i.e. reverse the second half of the list
Now you can walk in both halves and compare the values in tandem.
To make that work, here is a function you could use:
public ListNode middleNode(ListNode head) {
ListNode fast = head;
while (fast != null && fast.next != null) {
head = head.next;
fast = fast.next.next;
}
return head;
}
And now you can do:
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
ListNode mid = middleNode(head);
ListNode tail = reverseList(mid);
while (tail != null) {
if (head.val != tail.val) return false;
tail = tail.next;
head = head.next;
}
return true;
}
I've recently encountered a problem of iterating through the node from head to tail.
I usually used this method to iterate:
Node<E> walk = head;
while (walk != null) {
//do the job
walk = walk.getNext();
}
but when I tried to use for-loop instead, I got a null pointer error
for (Node<E> walk = head; walk.next != null; walk = walk.next) {
//do the job
}
Do I only have to use while-loop to iterate through the node? Or is it just my code making a bug because of my mistake?
Also, what makes a difference between walk.next and walk.getNext? I thought they are the same things
here is a getNext method
public Node<E> getNext() { return next; }
Below code should work because in your code you are iterating till walk==null
that is the reason you are getting null when accessing walk.next means null.next so Please follow below code.Hope it helps.
for (Node<E> walk = head; walk != null; walk = walk.next) {
//do the job
}
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);
}
Hi I am making a linked list data structure and within the list I define an iterator inner class. I am currently having trouble with the remove method. The functionality that I want is that it cannot be called on the if the next has not been called or the current element in the list has been removed already. Here's what I have.
private class ListItr implements java.util.Iterator<E>{
private Node<E> currentNode;
private Node<E> nextNode;
private Node<E> previousNode;
public ListItr(List<E> theList){
previousNode = new Node<E>(null);
currentNode = new Node<E>(null);
nextNode = theList.head;
currentNode.setSuccessor(nextNode);
}
public boolean hasNext(){
return nextNode != null;
}
public E next(){
if(nextNode == null)
throw new NoSuchElementException();
previousNode = currentNode;
currentNode = nextNode;
nextNode = nextNode.getSuccessor();
return currentNode.getElement();
}
public void remove(){
if(currentNode == null)
throw new IllegalStateException();
nextNode = currentNode.getSuccessor();
previousNode.setSuccessor(nextNode);
currentNode = null;
size--;
}
}
As you can see this will successfully remove the node in the list by splicing around it, setting the current node to null. However if it is called on the first without calling next, it will still run when I do not want it to. I can hack around it by adding a flag nextNotCalled, setting it to true in the constructor, then setting it false when next is called however I feel that that is not the way to go about it...
If the question is in general how to do it, I'd look at how Josh Bloch and Neil Gafter did it. Look at the class definition for Itr (line 330).
What is a doubly linked list's remove method?
The same algorithm that Bill the Lizard said, but in a graphical way :-)
(source: jaffasoft.co.uk)
The general algorithm is as follows:
Find the node to remove.
node.previous.next = node.next
node.next.previous = node.previous
node.previous = null
node.next = null
Dispose of node if you're in a non-GC environment
You have to check the previous and next nodes for null to see if you're removing the head or the tail, but those are the easy cases.
public void remove ()
{
if (getPreviousNode () != null)
getPreviousNode ().setNextNode (getNextNode ());
if (getNextNode () != null)
getNextNode ().setPreviousNode (getPreviousNode ());
}
Doubly Linked List Implementation Remove Methods (from my second programming assignment):
public void remove(int index) {
if(index<0 || index>size())
throw new IndexOutOfBoundsException("Index out of bounds. Can't remove a node. No node exists at the specified index");
if(size()==0) {
throw new NullPointerException("Empty list");
}
if(!isEmpty()) {
Node current;
//starting next one to our head
current = head.next;
for(int i=0;i<index;i++) {
current = current.next;
}
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
}
}
public boolean remove(T o) {
Node current = head;
for(int i=0;i<size();i++) {
current=current.next;
if(current.data.equals(o)) {
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
return true;
}
}
return false;
}
Are you asking for the name of a method in the api? That answer would simply be remove, assuming you are asking about java.util.LinkedList which is in fact a double linked list.
...or are you asking about what the name of the algorithm to remove an element from that type of data structure is called? Well.. the answer for that would also be to remove an element. Now for the actual algorithm to do it... it's really just a matter of changing the next pointer in the previous node and the last pointer in the next node. However, if you are using your data structure from multiple threads, you will need to either synchronize the remove method, or do the removal steps in an order that will make sense for your usage pattern for the data structure.
What about the current pointer pointer? You have to move crnt to the next node.
http://pastebin.ca/1249635