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
}
Related
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.
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 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);
}
When I call this insert before method, it does what it is supposed to do at first, but then it causes the linked list to keep going on and on forever until i click stop (with system out print). I can't find where it goes wrong in this method
private boolean insertBefore(Node aNode, Node beforeNode)
{
Node currentNode;
Node prevNode;
//aNode= new Node();
currentNode = this.getHead();
while(currentNode!=null && currentNode.getNext()!=aNode)
{
if(currentNode == beforeNode)
{
prevNode = this.getPrevious(beforeNode);
prevNode.setNext(aNode);
aNode.setNext(beforeNode);
//aNode.setNext(currentNode);
return true;
}
currentNode = currentNode.getNext();
}
currentNode.setNext(beforeNode);
return false;
}
This is much simpler than the code specified above, given you have a doubly-linked list there is no need to loop over all the elements:
private boolean insertBefore(Node aNode, Node beforeNode) {
if(beforeNode.getPrevious() != null) {
beforeNode.getPrevious().setNext(aNode);
aNode.setPrevious(beforeNode);
} else {
head = aNode;
}
aNode.setNext(beforeNode);
beforeNode.setPrevious(aNode);
}
If the beforeNode is at the head of the list, your new node becomes the head.
Otherwise, there is a node behind your beforeNode. This must now point at your new node.
Either way, your new node's next pointer points at the beforeNode node.
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