【问题标题】:Java Linked List unable to add item to endJava Linked List 无法将项目添加到末尾
【发布时间】:2019-09-17 18:15:53
【问题描述】:

似乎无法正确添加最后一个元素。我将最后一项保存在临时节点中,然后创建一个新节点。然后我为每个节点链接上一个和下一个,然后将最后一个节点指向一个新的空节点。但是当我转到我的 print() 方法时,那个空节点似乎不是列表的一部分。

似乎它应该像我的推送方法一样简单,但我似乎无法让它像它一样工作。

public class LinkedListDeque {

public DoubleNode first = new DoubleNode(null);
public DoubleNode last = new DoubleNode(null);
public DoubleNode temp;
public int N;

LinkedListDeque() {
    first.next = last;
    last.prev = first;

}

public static void main(String[] args) {

    LinkedListDeque link = new LinkedListDeque();

    link.push("banana");
    link.printList();

    link.enqueue("gorilla");
    link.printList();


    link.enqueue("spam");

}


//nested class

private class DoubleNode {

    String item;
    int counter = 0;
    DoubleNode next;
    DoubleNode prev;

    DoubleNode(String i) {
        this.item = i;
    }

}

public void push(String item) {

    System.out.println("\npush()\n******");
    if (first.item == null) {
        first.item = item;
        first.counter++;
    } else {

        System.out.println("last.item = " + last.item);
        DoubleNode node = new DoubleNode(item);
        first.prev = node;
        node.next = first;
        first = node;

    }

}



 public void enqueue(String item) {
    System.out.println("\nenqueue()\n***********");
    System.out.println("adding \"" + item + "\" to the end");

    if (last.item == null) {
        DoubleNode node = new DoubleNode(null);                     //holds null node to end list
        last.item = item;
        last.next = node;
    } else {
        DoubleNode node = new DoubleNode(null);
        System.out.println("node = " + node.item);                  //= correct item

        temp = last;
        last = new DoubleNode(item);                                //creating a new last node

        System.out.println("temp = " + temp.item);                  //corect
        //reconnect the links
        temp.next.item = last.item;

        System.out.println("temp.prev = " + temp.prev.item);        //correct
        System.out.println("temp.next = " + temp.next.item);        //correct
        System.out.println("last = " + last.item);                  //correct
        System.out.println("last.prev = " + last.prev);             //correct

        last.prev = temp;

        System.out.println("last.prev = " + last.prev.item);        //correct

        last.next = node;
        System.out.println("last.next = " + last.next.item);        //= null to end list

        System.out.println("\n\nfirst = " + first.item);                                //correct
        System.out.println("first.next = " + first.next.item);                          //correct
        System.out.println("first.next.next = " + first.next.next.item);                //correct
        System.out.println("first.next.next.next = " + first.next.next.next.item);      //"null pointer exception"
}

public void printList() {
    System.out.println("\nprintList():\n********");
    temp = first;

    int i = 0;
    if (first.item == null) {
        temp = first.next;
    }
    System.out.println("temp = " + temp.item);
    while (temp.item != null) {
        i++;
        System.out.println(i + " " + temp.item);
        temp = temp.next;
    }
    System.out.println();
}

【问题讨论】:

  • 为什么enqueue方法中包含打印语句?
  • 您的first 节点和last 节点被视为两个单独的列表,其中last 是其自身列表的第一个节点。当您将第一个节点添加到列表中时,您需要链接 lastfirst 节点。
  • 在循环双向链表末尾添加一个新节点。首先,您需要创建一个新节点。将新节点的上一个设置为最后一个节点和头部旁边。下一步是将最后一个节点的next设置为新节点,并将head的previous设置为新节点。
  • @Travelsbyfire 使用调试器要好得多。适应它。
  • 建议。拿一张纸和笔,一步一步地画出应该发生的事情。这会对你有很大帮助。我有一个任务,我必须在排序的双循环列表中插入节点。绘画对我帮助很大。

标签: java list queue


【解决方案1】:

让我们看看实际发生了什么: 初始状态:

  • first 包含 null,first.next 是 last,last 包含 null
  • push:first 不再包含null,仍然指向last,带有null
  • enque: last.item 为 null,所以第一个 cae 被触发,现在列表是这样的:banana -> gorilla -> null 并且 last 指向 gorilla
  • enque again:现在触发了 else。如果你看一下代码,你 会注意到 temp.next 在任何地方都没有被触及。这意味着作为 enque 之前的最后一个节点并被复制到 temp 的节点仍然指向 null 节点。
  • 这最终导致空指针异常。

缺少什么:在创建最后一个节点之后,类似于 temp.next=last

实际发生的情况如下所示:

---> last ---> closing-null

---> temp ---> closing-null

---> last

看起来你可以更干净地实现这一点,而无需关闭列表的空节点。

然后你可以这样做:

node=new Node(item);
last.next=node;
node.prev=last;
last=node;

【讨论】:

  • 如果它们没有连接,为什么 first.next.next = last?
  • 是的,实际上在其他一些地方缺少链接,比如最后一个空节点 prev 没有添加到 enque 中的任何地方。
  • 我不确定这是否是您的意思,但在最顶部,first.next = last
  • temp.next.item 是 temp.next 指向的节点中包含的字符串。那是先前具有空指针的项目。 temp.next 指针未更新,因此它仍指向先前版本队列中作为关闭空项的项。您更新了它的内容,但它从列表中分离出来,并且指向任何地方。在 else 运行后,您无法再从第一个到达最后一个。这有意义吗?
  • 哦,是的,这只是一小段代码。我只是将其更改为 temp.next = last,现在它可以完美运行。不知道为什么我认为我需要更改值
【解决方案2】:

我不会给你完整的代码,但我会把它可视化。在此之后,您可以轻松地编写代码。

下一个是--->,上一个是<---,最后一个指向最后一个节点,第一个指向第一个节点

假设你有这个列表。

Banana ---> Orange ---> Gorilla ---> null
       <---        <---         
  ^                       ^
  |                       |
first                    last
// First's previous and last's next is null.

您想在最后添加芒果。 你创建一个新节点

DoubleNode node = new DoubleNode("Mango");
<--- Mango --->
// Note: When you create a new node by default both next and previous are null. 
// You don't need to point them to null later

第 1 步:

last.next(newNode);
Banana ---> Orange ---> Gorilla ---> Mango 
       <---        <---    
  ^                       ^
  |                       |
first                    last  

第 2 步:

newNode.previous(last);
Banana ---> Orange ---> Gorilla ---> Mango 
       <---        <---         <---
  ^                       ^
  |                       |
first                    last

现在我们有新的最后一个,所以我们会更新最后一个

last = newNode
Banana ---> Orange ---> Gorilla ---> Mango 
       <---        <---         <---
  ^                                    ^
  |                                    |
first                                last

从构造函数我们知道 Mango 的 next 已经是 null 所以newNode.next(null); 是不必要的。

您可能会收到 nullpointerexception 的原因

添加第一个元素后,您的列表如下所示

null <--- Banana ---> null      null
             ^                   ^
             |                   |
           first                last

从技术上讲,您应该将第一点和最后一点都指向香蕉,因为您不这样做。当您将某些东西排入队列时,我们会说大猩猩。应该是

null.item = "Gorilla"
null.next = null

【讨论】:

  • 那么 (first.next = last) 和 (last.prev = first;) 会确保 first 和 last 都指向香蕉吗?
  • @Travelsbyfire 这取决于你。如果您这样做,您的列表将变为循环。你可以最后指向香蕉,它会解决问题。如果您的最后一个为空,则假设您的列表完全为空。
  • @Travelsbyfire 即使在最后指向香蕉之后,我在回答 enqueue 时给出的算法仍然有效。
  • 是的,这完全有道理。 g_bor 实际上向我指出 temp.next.item = last.item 行实际上并没有更改我的节点,而是指针,并且在将该行更改为 temp.next = last 之后,它停止给我空指针异常。
  • 感谢您的说明,如果没有类似的东西,这些东西很快就会变得混乱,我决定在我的任意变量值中包含芒果
猜你喜欢
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多