Java 实现双链表

Java 实现双链表,java,data-structures,linked-list,doubly-linked-list,Java,Data Structures,Linked List,Doubly Linked List,我在这个论坛上浏览了有关双链表实现的内容,但我无法掌握下面的代码 // 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

我在这个论坛上浏览了有关双链表实现的内容,但我无法掌握下面的代码

// 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
    }
//双链接列表的实例变量
私有最终节点头;//头球哨兵
私有最终节点尾部;//拖车哨兵
私有整数大小=0;//列表中的元素数
私有int modCount=0;//对列表的修改次数(添加或删除)
/**
*创建两个充当哨兵的元素
*/
公共双链接列表(){
header=新节点(null,null,null);//创建头
拖车=新节点(null,header,null);//拖车前面有header
header.setNext(拖车);//头后面跟着拖车
}
我看过关于链表和双链表的视频,但我还没有见过这种实现。例如:
trailer=newnode(null,header,null)

给定一个列表(任何类型),您至少需要知道如何到达第一个元素,以及如何告知何时看到最后一个元素

有几种方法可以安排满足这些要求

对于链表,要知道列表从何处开始,可以对第一个节点进行简单的引用,也可以使用始终存在的完整“虚拟”节点

要知道列表的结束位置,您可能有一个空的“next”引用,或者您可能有一个始终存在的完整的“dummy”节点

虚拟节点方法通常会产生更清晰的代码,因为这样所有实际节点将始终具有“上一个”节点,而所有实际节点将始终具有“下一个”节点


这似乎是代码提取中采用的方法。

您可能有一些双链接列表,如:

     /**
     * 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;
            }
        }
    }
/**
*双链接列表。
*
*/
公共类双链接列表{
私有最终节点头;//头哨兵
私有最终节点拖车;//拖车哨兵
private int size=0;//列表中的元素数
private int modCount=0;//对列表的修改次数(添加或删除)
公共双链接列表(){
this.header=新节点(
//标题的后续部分是尾部。
//它将设置为:header.setNext(拖车);
无效的
//标头的前置项始终为空,
//因为在第一个节点之前没有节点
无效的
//节点的有效负载为空。
//我想这只是例子的一部分。
无效的
);
this.traile=新节点(
//预告片的后续项始终为空,
//因为在最后一个节点之后没有节点
无效的
//拖车的前身是收割台
//在建造这个物体时
标题,
//节点的有效负载为空。
//我想这只是例子的一部分。
无效的
);
//现在是标题集到拖车的后续项。
标题。设置下一步(拖车);
}
//一些列表方法,如添加、删除、获取。。。
/**
*列表的节点
*
*@param列表中存储对象的类型。
*/
静态类节点{
/**
*此节点的前置节点。
*/
专用节点前置器;
/**
*此节点的后续节点。
*/
私有节点继承者;
/**
*有效载荷
*/
专用最终T载荷;
公共节点(最终节点后续节点、最终节点前置节点、最终T有效负载){
这个。前任=继任者;
这个后继者=后继者;
这个有效载荷=有效载荷;
}
//接受者和接受者:
私有节点getPreference(){
把这封信还给我;
}
私有void setNext(最终节点next){
this.preference=next;
}
私有节点getSuccessor(){
把这个交给继任者;
}
私有void setPrevious(最终节点previous){
这个后继者=先前的;
}
私有T getPayload(){
返回此有效载荷;
}
}
}

这在架构上不是很漂亮,但我认为这个解释符合您的情况。

您看过节点构造函数吗?你们到底不确定什么?拖车只是指向第一个节点的指针。标头是当前的最后一个节点。如果添加下一个节点,则它将更改。。。是常见的解决方案。
java.util.LinkedList
已经包含对上一个和下一个的引用elements@tgdaviesheader=新节点(null,null,null);trailer=新节点(null,header,null);我的疑问主要在于此。节点构造函数的每个参数代表什么?