Using Sentinel Nodes
A common practice when implementing a link list is to use sentinel nodes.
- Sentinel nodes are dummy nodes that you add to both ends of your linked list.
- You will have the
head
and thetail
pointer to always point to sentinel nodes. The constructor will construct the sentinel nodes; they will never be removed nor updated. - You should not count the sentinel nodes as elements of the data structure.
- The sentinel nodes should not be considered when iterating over the elements of the data structure.
Here is the constructor of LinkedList
building the sentinel nodes:
public LinkedList() {
head = new Node<>(null, this);
tail = new Node<>(null, this);
head.next = tail;
tail.prev = head;
numElements = 0;
}
Using sentinel nodes eliminates many of the edge cases that arise in implementing linked list operations.
Exercise Update the implementation of insertFront
. Considering head
and tail
point to sentinel nodes.
public Position<T> insertFront(T data) {
if (head == null) {
head = new Node<T>(data, this);
tail = head;
numElements += 1;
return head;
}
Node<T> newFront = new Node<T>(data, this);
Node<T> currFront = head;
newFront.next = currFront;
currFront.prev = newFront;
head = newFront;
numElements += 1;
return newFront;
}
Solution
We don't need to treat the case where head == null
differently as that never happens with a sentinel node implementation.
@Override
public Position<T> insertFront(T data) {
Node<T> newFront = new Node<T>(data, this);
Node<T> currFront = head.next;
newFront.next = currFront;
currFront.prev = newFront;
head.next = newFront;
newFront.prev = head;
numElements += 1;
return newFront;
}
Resources
- Wikipedia's entry on Sentinel Node.