Using doubly linked nodes can solve the problem of removing the last element efficiently.
Using doubly linked nodes does a bit more code to update both next and prev members instead of just next.
But both doubly linked lists as well as singly linked lists have to be careful to handle boundary cases:
- adding an item to an empty list
- removing an item from a list with only one item
One addition to the structure will allow these boundary cases to be handled with the same code as non boundary cases.
The change is to add two guard nodes: one at the beginning before the first data node and the other after the last data node.
This has the benefit that every data node will have a node before it and one after. In particular this is true even for the first data node and for the last data node.