简体   繁体   中英

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) ?

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.

Given a list (of any kind), you need to know at least how to get to the first element, and how to tell when you've seen the last element.

There are a few ways to arrange for these requirements to be satisfied.

For a linked list, to know where the list starts, you might have a simple references to the first node, or you might have a full 'dummy' node that always exists.

To know where the list ends, you might have a null 'next' reference, or you might have a full 'dummy' node that always exists.

The dummy-node approach can often result in cleaner code, because then all actual nodes will always have a 'previous' node, and all actual nodes will always have a 'next' node.

That seems to be the approach being taken in your code extract.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM