Java 双链表删除第一次出现的方法

Java 双链表删除第一次出现的方法,java,linked-list,Java,Linked List,有人能帮我为这个双链接列表写一个removeFirstOccurrence方法吗 它删除第一次出现目标数据的节点。搜索从头部开始。如果目标数据不在列表中,则列表保持不变。最后一个节点的下一个字段的值为null。没有尾部引用 public class DoublyLinkedList { protected Node head; // Note there is no tail reference. public void addToFront(String data) {

有人能帮我为这个双链接列表写一个removeFirstOccurrence方法吗

它删除第一次出现目标数据的节点。搜索从头部开始。如果目标数据不在列表中,则列表保持不变。最后一个节点的下一个字段的值为null。没有尾部引用

public class DoublyLinkedList {

    protected Node head; // Note there is no tail reference.
    public void addToFront(String data) {
        head = new Node(data, head, null);
        if(head.next != null) {
            head.next.previous = head;
        }

    public void removeFirstOccurrence(String data) { 
    }

    protected class Node {
        protected String data;
        protected Node next;
        protected Node previous;
        private Node(String data, Node next, Node previous) {
            this.data = data;
            this.next = next;
            this.previous = previous;
        }
        private Node(String data) {
            this(data, null, null);
        }
    } // end of Node class 
} // end of DoublyLinkedList class
到目前为止,我写了类似这样的东西,但是当删除列表中不存在的字符串时,我得到了一个空指针异常。我已经标记了NPE发生的位置。如果你能帮我找出原因,或者你有一个完全不同的方法也可以,请告诉我,谢谢

public void removeFirstOccurance(String data) {
    if (data.equals(null)) {
        throw new java.lang.IllegalArgumentException("Data is null");
    }
    if (head == null) {
        throw new java.util.NoSuchElementException("List is empty");
    }

    Node current = head;
    if (current.data.equals(data)) {
        head = current.next;
    } else {
        boolean found = false; //keeps track if we found the element
        while (current != null && !found) {
            if (current.next.previous == null) { //NPE here
                current.next.previous = current;
            }
            current = current.next;
            if (current.data.equals(data)) {
                found = true;
                if (current.next == null) {
                    current.previous.next = null;
                } else {
                    current.previous.next = current.next;
                }
            }
        }
    }
}

在访问其值之前,您没有测试循环中的
当前.next
。 因此,当到达列表的末尾时,会发生异常

while (current != null && !found) { // testing current
    if (current.next.previous == null) { // accessing current.next + testing current.next.previous
        current.next.previous = current;
    }
    // your loop
}

注意:它看起来像是工作分配,所以我不会发布代码。

这将是我帮助您找到bug的理由。计算
current.next.previous
时发生空指针异常。上一行确保
当前!=空
。因此,
current.next
很可能是空值。一个简单的测试方法是添加
assert current.next!=在使用该值之前,为空。如果这一理论是正确的,那么此时将抛出断言异常。然后,您可以开始检查其他代码,找出
当前的原因。下一个
此时可能为空


作为编程技巧,我建议您使用大量的
assert
语句。从长远来看,它们会帮你省去很多痛苦。对于阅读代码的其他人来说,它们也是一个很好的提示,告诉他们您假设的条件在每一点上都是正确的。

只是一些提示,因为我甚至没有在这台机器上安装Java来检查代码

我建议你把注意力集中在你必须做的事情上:找到第一件事。然后,一旦找到它:更新前面和后面节点的指针

例如,在我看来,当您检查数据是否位于第一个节点时,您似乎忘记了更新
current.previous
指针
current.next
。这样,您就不会实际删除节点

所以,我的方法是

while(!current.data.equals(data) && current.next != null){
    current = current.next; // looking through the list
}
然后,仔细检查是否尚未到达列表的末尾,更新指针,以便

current.previous.next = current.next;
current.next.previous = current.previous;
还请注意,如果只是为了复制值,那么不需要将null视为特殊的东西。 我的意思是,在你的最后一次演讲中,如果:

if (current.data.equals(data)) {
                found = true;
                if (current.next == null) {
                    current.previous.next = null;
                } else {
                    current.previous.next = current.next;
                }
            }
您可以简单地分配
current.previous.next=current.next


希望这有帮助。

如果我添加了一个while循环,上面写着while(current.next!=null),那么它会在结束时停止吗?我已经在检查电流了!=上面为空,我认为这就是我所需要的,但也许它应该是最新的。下一步?更新我的答案。你可以做一些测试,很快就会知道它是否有效。@Hartok我不同意。断言并不打算影响功能(它们在功能上不做任何事情)。它们旨在确保代码的正确性和可维护性。在我看来,它们几乎(但不是完全)和全面的单元测试一样重要。我明白你的意思,我们在测试类中使用Assert是为了测试以确保一切正常,但就向我正在编辑的类添加Assert而言,它在我不允许使用的代码列表中,以及诸如不能使用的东西-继续;等