I have a Node class:
public class Node<T> {
private T data; // Entry in bag
private Node<T> next; // Link to next node
public Node(T dataPortion) {
this(dataPortion, null);
}
public Node(T dataPortion, Node<T> nextNode) {
data = dataPortion;
next = nextNode;
}
public T getData() {
return data;
}
public void setData(T newData) {
data = newData;
}
public Node<T> getNextNode() {
return next;
}
public void setNextNode(Node<T> nextNode) {
next = nextNode;
}
}
And a DoublyLinkedNode as a subclass of Node
public class DoublyLinkedNode<T> extends Node<T> {
private DoublyLinkedNode<T> previous; // Link to previous node
public DoublyLinkedNode(T dataPortion) {
super(dataPortion); // sets next to null as well
previous = null;
}
public DoublyLinkedNode(T dataPortion, Node<T> nextNode) {
super(dataPortion, nextNode); // set next
previous = null;
}
public DoublyLinkedNode(DoublyLinkedNode<T> previousNode, T dataPortion, DoublyLinkedNode<T> nextNode) {
super(dataPortion, nextNode); // set next
previous = previousNode;
}
public DoublyLinkedNode<T> getPreviousNode() {
return previous;
}
public void setPreviousNode(DoublyLinkedNode<T> previousNode) {
previous = previousNode;
}
public DoublyLinkedNode<T> getNextNode() {
return (DoublyLinkedNode<T>) super.getNextNode();
}
}
Finally, the LinkedDeque class:
public class LinkedDeque<T> implements DequeInterface<T> {
private DoublyLinkedNode<T> firstNode; // References node at front of deque
private DoublyLinkedNode<T> lastNode; // References node at back of deque
private int size;
public LinkedDeque() {
firstNode = null;
lastNode = null;
size = 0;
}
@Override
public void addToFront(T newEntry) {
size ;
DoublyLinkedNode<T> newNode = new DoublyLinkedNode<T>(null, newEntry, firstNode);
if (isEmpty())
lastNode = newNode;
else
firstNode.setPreviousNode(newNode);
firstNode = newNode;
}
@Override
public void addToBack(T newEntry) {
size ;
DoublyLinkedNode<T> newNode = new DoublyLinkedNode<T>(lastNode, newEntry, null);
if (isEmpty())
firstNode = newNode;
else
lastNode.setNextNode(newNode);
}
@Override
public T removeFront() {
T front = null;
if (isEmpty()) {
throw new EmptyQueueException();
} else {
front = firstNode.getData();
firstNode = firstNode.getNextNode();
if (firstNode == null)
lastNode = null;
else
firstNode.setPreviousNode(null);
size--;
}
return front;
}
@Override
public T removeBack() {
T back = null;
if (!isEmpty()) {
back = lastNode.getData();
lastNode = lastNode.getPreviousNode();
if(lastNode == null)
firstNode = null;
else
lastNode.setNextNode(null);
size--;
} else {
throw new EmptyQueueException();
}
return back;
}
@Override
public T getFront() {
T front = null;
if (!isEmpty())
front = firstNode.getData();
return front;
}
@Override
public T getBack() {
T back = null;
if (!isEmpty())
back = lastNode.getData();
return back;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void clear() {
firstNode = null;
lastNode = null;
}
@Override
public int size() {
return size;
}
@Override
public T[] toArray() {
T[] result = (T[]) new Object[this.size];
int index = 0;
DoublyLinkedNode<T> pointer = firstNode.getNextNode();
while (pointer != lastNode) {
result[index] = (T) pointer;
index ;
pointer = pointer.getNextNode();
}
return result;
}
}
When I tried add an item to front using addToFront() method, there is an error saying that firstNode is null. I used debug to figure out the reason why but I still have no clue. I would like to learn how to fix this.
CodePudding user response:
@Override
public void addToFront(T newEntry) {
size ;
DoublyLinkedNode<T> newNode = new DoublyLinkedNode<T>(null, newEntry, firstNode);
if (isEmpty())
lastNode = newNode;
else
firstNode.setPreviousNode(newNode);
firstNode = newNode;
}
With first time using addToFront, firstNode is null. size == 1, so firstNode.setPreviousNode(newNode); will be called.
That's why you get NullPointerException
CodePudding user response:
A good practice would be to increase/decrease the size
of list after the operation has been performed, if you increase/decrease the size before adding/removing and if it fails in between the size of the list will be in an inconsistent state.
That is one reason you application is performing inconsistently since size is already increased before the node is actually inserted (isEmpty()
is not working as expected) thus giving you an NPE in some cases
In the method addToFront()
the size is being increased before actually inserting node into the list thus isEmpty()
method not working correctly, it should be something like this -
@Override
public void addToFront(T newEntry) {
DoublyLinkedNode<T> newNode = new DoublyLinkedNode<T>(null, newEntry, firstNode);
if (isEmpty())
lastNode = newNode;
else
firstNode.setPreviousNode(newNode);
firstNode = newNode;
size ;
}
Also in the method addToBack()
- if the list is empty firstNode and lastNode should point to the newly created node i.e firstNode = lastNode = newNode
. -
@Override
public void addToBack(T newEntry) {
DoublyLinkedNode<T> newNode = new DoublyLinkedNode<T>(lastNode, newEntry, null);
if (isEmpty())
firstNode = newNode;
else
lastNode.setNextNode(newNode);
lastNode = newNode;
size ;
}
You may also wanna update the removeFront()
and removeBack()
methods to update the size
correctly.