【问题标题】:Adding to the end of a Doubly-Linked List Data Structure in Java在 Java 中添加到双链表数据结构的末尾
【发布时间】:2016-07-29 01:44:27
【问题描述】:

我正在研究计算机科学,但在将节点添加到双向链表数据结构的末尾时遇到了一些困难。我知道新节点指向尾部,尾部指向它,因此我有这个:

public boolean add(E element) 
    {
        // TODO: Implement this method
        LLNode<E> newNode = new LLNode<E> (element);
        if (element == null) {
            throw new NullPointerException("Element can not store a null reference!");

        } else {
            newNode.next = tail;
            newNode.prev = tail.prev;

            tail.prev = newNode;
            head.next = newNode;

        }
        size++;
        return true;
    }

我遇到的问题是尝试连接头节点(通过 head.next 到正确的节点)。

在我的默认构造函数中,head.next 节点指向 tail.prev。但是在 add 方法中,我无法弄清楚 head.next 会指向哪里,因为每次添加新节点时,head 都必须指向 LinkedList 数据结构中的第一个节点。这是默认构造函数:

public MyLinkedList() {
        // TODO: Implement this method
        size = 0;
        /*create two empty nodes at the head and the tail of the linked list*/
        head = new LLNode<E> (null);
        tail = new LLNode<E> (null);
        head.next = tail;
        tail.prev = head;
        head.prev = null; //Head is a sentinel node with no node prior to it
        tail.next = null; //tail is a sentinel node with no node after it
}

请指出我(不是双关语)正确的方向。谢谢!

【问题讨论】:

  • "在我的默认构造函数中,我有 head.next 节点指向 tail.prev" 你没有?
  • Element can not store a null reference! ... 说谁?列表结束的标记不是要存储的元素为空,而是下一个指针为空。
  • 链表不需要两个虚拟节点。一个虚拟节点就足够了,其中 dummy.prev = 第一个节点或 null,dummy.next = 最后一个节点或 null。第一个节点的 prev 指针和最后一个节点的 next 指针应该为空。您还可以使用对节点的两个引用而不是虚拟节点:头和尾。
  • 这个练习的目的不是关于是否需要两个哨兵节点来形成一个链表。当然不是这样。这里的案例是拥有两个哨兵节点并根据 UCSDs MOOC 实现一个双向链表。
  • @Linuxn00b - 唯一的订购要求是在更新之前使用tail.prev(或它的副本):newNode.prev = tail.prev; tail.prev.next = newNode; tail.prev = 新节点;或 newNode.prev = tail.prev; newNode.prev.next = newNode; tail.prev = 新节点;或 newNode.prev = tail.prev; tail.prev = 新节点; newNode.prev.next = newNode; .

标签: java data-structures linked-list


【解决方案1】:

在纸上画出你必须做的事情。

例如如果你列出 current 有两个元素(A 和 B),你的链将是:

HEAD &lt;-&gt; A &lt;-&gt; B &lt;-&gt; TAIL

要添加一个新元素 (C),您的最终结果应该是:

HEAD &lt;-&gt; A &lt;-&gt; B &lt;-&gt; C &lt;-&gt; TAIL

表示以下更新:

  • C.prev = B 或更准确地说:C.prev = TAIL.prev
  • B.next = C 或更准确地说:TAIL.prev.next = C
  • C.next = TAIL
  • TAIL.prev = C

如您所见,HEAD 没有参与其中,因此您的行 head.next = newNode 是错误的。

【讨论】:

  • 我知道没有涉及到 head,但是如果没有一些 head 的实现,add 方法根本不起作用。
  • @Linuxn00b 你说它不工作是什么意思?如果列表为空并且您要添加 A,则 TAIL.prev HEAD,因此上面的前 2 个项目符号(C.prev = TAIL.prevTAIL.prev.next = C)将具有 A.prev = HEAD 的效果和HEAD.next = A,所以HEAD 更新,即使代码中没有提到名称。这就是使用哨兵节点的重点:第一个/最后一个值节点没有特殊处理。
  • 我的操作顺序不正确。对不起。我在tail.prev.next = newNode之前有tail.prev = newNode。
【解决方案2】:

这应该可行。

public boolean add(E element) 
    {
        LLNode<E> newNode = new LLNode<E> (element);
        if (element == null) {
            throw new NullPointerException("Element can not store a null reference!");
        } else {
            newNode.next = tail;       // set new.next to tail
            newNode.prev = tail.prev;  // set new.prev to prior last
            tail.prev.next = newNode;  // set prior last.next to new last
            tail.prev = newNode;       // set tail.prev to new last
            size++;
        }
        return true;
    }

我不确定在 add 函数中是否需要检查 null 元素,尽管其他地方可能需要检查 null。

【讨论】:

    【解决方案3】:

    我认为您需要重新考虑如何处理链表... 你从一个链表开始像这样:

    head.next = tail
    head.prev = null
    tail.next = null
    tail.prev = head
    

    当你在列表的末尾添加一些东西时,我们称之为 mid,你希望你的列表看起来像这样:

    head.next = mid (set by using tail.prev.next = mid)
    head.prev = null
    mid.next = tail (the new node is the end of the list)
    mid.prev = head (previous tail.prev)
    tail.next = null
    tail.prev = mid (setting the new node to be the new end of the list)
    

    所以你的错误是当你添加一个节点时,你不应该明确地使用头节点,就像你正在做的那样。所有操作都应该按照列表的尾部来完成。我已经把它变成代码了。

    【讨论】:

    • 我可以从反对者那里得到一些关于我的回答的问题吗?有什么问题?
    • 问题代码所做的正是您回答中前 80% 所要求的,尽管我不明白您所说的这一行是什么意思:mid.prev = head (previous tail.prev)。问题是在做newNode.prev = tail.prev,这是正确的,而不是newNode.prev = head,所以“以前的”评论是模糊的。在添加 second 元素之前,您看不到代码中的错误,并且您的回答无论如何都无法帮助识别它。当然,你在最后一段中说对了,但其余的都是毫无意义的,即没有用处。
    • 对我来说非常有道理...不理解某些东西真的是反对的理由吗?
    • 你说“你希望你的列表看起来像这样”,问题代码将使列表看起来像这样,那么这对弄清楚有什么帮助怎么了?你还说“你从一个这样的链表开始”,这正是问题在做什么,那么这样说有什么意义呢?简而言之,前 80% 的答案只是重复了这个问题,但听起来好像这个问题并没有那样做。没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-02
    • 2012-11-02
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    相关资源
    最近更新 更多