Search code examples
javadata-structureslinked-listdoubly-linked-list

Implement doubly linked list


I've looked around on this forum regarding the implementation of doubly linked lists and I can't a grasp of the below code.

// instance variables of the DoublyLinkedList
    private final Node<E> header;     // header sentinel
    private final Node<E> trailer;    // trailer sentinel
    private int size = 0;       // number of elements in the list
    private int modCount = 0;   // number of modifications to the list (adds or removes)

    /**
     * Creates both elements which act as sentinels
     */
    public DoublyLinkedList() {

        header = new Node<>(null, null, null);      // create header
        trailer = new Node<>(null, header, null);   // trailer is preceded by header
        header.setNext(trailer);                    // header is followed by trailer
    }

I've seen videos about linked lists and doubly ones, but I haven't seen this kind of implementation. What's the logic behind, for example: trailer = new Node<>(null, header, null)?


Solution

  • You have Probably some DoubleLinkedList like:

         /**
         * A double linked list.
         *
         */
        public class DoubleLinkedList<E> {
        
            private final Node<E> header;     // header sentinel
            private final Node<E> trailer;    // trailer sentinel
            private int size = 0;       // number of elements in the list
            private int modCount = 0;   // number of modifications to the list (adds or removes)
        
            public DoubleLinkedList() {
                this.header = new Node<>(
                            // The successor of the header is the trailer.
                            // It will be set with: header.setNext(trailer);
                        null,
                            // The predecessor of the header is always null,
                            // because there there is no node before the first
                        null,
                            // The payload of the node is null.
                            // I guess it is just a part of the example.
                        null
                );
        
                this.trailer = new Node<>(
                        // The successor of the trailer is always null,
                        // because there there is no node after the last
                        null,
                        // The predecessor of the trailer is the header
                        // at construction of this object
                        header,
                        // The payload of the node is null.
                        // I guess it is just a part of the example.
                        null
                );
                // Now is the successor of the header set to the trailer.
                header.setNext(trailer);
            }
        
            // Some list methods like add, remove, get, ...
        
        
            /**
             * The nodes of the List
             *
             * @param <T> The type of the stored objects in the list.
             */
            static class Node<T> {
        
                /**
                 * The predecessor of this node.
                 */
                private Node<T> predecessor;
        
                /**
                 * The successor of this node.
                 */
                private Node<T> successor;
        
                /**
                 * The payload
                 */
                private final T payload;
        
                public Node(final Node<T> successor, final Node<T> predecessor, final T payload) {
                    this.predecessor = successor;
                    this.successor = successor;
                    this.payload = payload;
                }
        
                // Getter and Setter:
        
                private Node<T> getPredecessor() {
                    return this.predecessor;
                }
        
                private void setNext(final Node<T> next) {
                    this.predecessor = next;
                }
        
                private Node<T> getSuccessor() {
                    return this.successor;
                }
        
                private void setPrevious(final Node<T> previous) {
                    this.successor = previous;
                }
        
                private T getPayload() {
                    return this.payload;
                }
            }
        }
    

    This is architectural not very beautiful, but I think this explanation matches your case.