双向链表Java删除方法不适用于除头节点之外的任何节点

时间:2018-02-11 15:19:01

标签: java linked-list nodes doubly-linked-list

除了remove方法之外,我的所有方法都有效。虽然它仅在要删除的节点是头部时才有效,但它不适用于在头部之后删除的任何其他节点。经过几个小时的调试后,我发现除了头部之外的其他东西只有在“头部”之后才会起作用。本身被引用(不是通过将头值存储在变量中),例如head.next,head.next.next等。但是诸如curNode.next.prev = curNode.prev之类的语句似乎不会改变列表的顺序一点都不下面是我的整个双向链接类以及节点类,以及我用来检查代码的主要方法。

双重链接节点类

public class DLNode {
    Object data;
    DLNode next;
    DLNode prev;

    DLNode(Object o) {
        data = o;
        next = null;
        prev = null;
    }
    public String toString() {
        return "[" + data + "]";
    }

}

双重链接列表类

public class DLList {
    DLNode head;
    DLList(){
        head = null;
    }
    public void append(DLNode newNode) {
        if (head == null ) {
            head = newNode;
        }
        else {
            DLNode curNode = head;
            while (curNode.next != null) {
                curNode.prev = curNode;
                curNode = curNode.next;             
            }
            curNode.next = newNode;
            curNode.prev = newNode.prev;
        }

    }
    public void prepend(DLNode newNode) {
        if (head == null) {
            head.prev = newNode;
            head = newNode;
            newNode.prev = null;
        }
        else {
            DLNode n = head;
            head.prev = newNode;
            head = newNode;
            newNode.next = n;
            newNode.prev = null;

        }
    }
    public void insertAfter(DLNode curNode, DLNode newNode) {
        DLNode sucNode = head.next;
        if (head == null) {
            head = newNode;
        }
        else {
            sucNode = curNode.next;
            newNode.next = sucNode;
            newNode.prev = curNode;
            curNode.next = newNode;
            sucNode.prev = newNode;
        }

    }
    public void remove(DLNode curNode) {
        DLNode sucNode = curNode.next; //these variables don't seem to work without
        DLNode predNode = curNode.prev; //the head node directly referenced
        if (head == null) {
            curNode = null;
        }
        else if (curNode == head) { //only block that works
            head = sucNode;
        }
        else if (sucNode != null) {
            sucNode.prev = predNode; //where the problem is apparently
        }
        else if (predNode != null) {
            predNode.next = sucNode;
        }

    }
    public DLNode search(Object key) {
        DLNode curNode = head;
        while (curNode != null) {
            if (curNode.data == key) {
                return curNode;
            }
            curNode = curNode.next;
        }
        return curNode;
    }

    public void insertAfterNew(DLNode curNode, DLNode newNode) {
        DLNode sucNode = head.next;
        if (head == null) {
            head = newNode;
        }
        else if (curNode == null) {
            newNode.next = sucNode;
            head = newNode;
            sucNode.prev = newNode;
        }
        else {
            sucNode = curNode.next;
            newNode.next = sucNode;
            newNode.prev = curNode;
            curNode.next = newNode;
            sucNode.prev = newNode;
        }
    }

    public String toString() {
        String finalString = "X<-";
        DLNode curNode = head;
        if (head == null) {
            return "X";
        }
        while (curNode != null) {
            if (curNode.next == null) {
                finalString += curNode;
                curNode = curNode.next;
            }
            else {  
                finalString += curNode + "<=>";
                curNode = curNode.next;
            }
        }
        return finalString + "->X";
    }
    }

主要

的测试类
public class TestList {
    static final int N = 4;

    public static void main(String[] args) {
        testDLList();
    }

    static void testDLList() {

        System.out.println("Doubly-Linked List");

        DLList list2 = new DLList();

        for (int i = 0; i < N; i++) 
            list2.append(new DLNode(i));
        for (double d = N; d < 2 * N; d++)
            list2.append(new DLNode(d));

        System.out.println(list2);

        DLNode temp = list2.search(1); //remove works when the value in search is 0
        System.out.println(temp); // since 0 is head, but not with other values in list

        list2.insertAfter(temp, new DLNode(2000));
        System.out.println(list2);

        list2.remove(temp);
        System.out.println(list2);

        System.out.println();
    }

2 个答案:

答案 0 :(得分:0)

问题出在append。我已经评论了要删除的行和原因,并添加了几行。

public void append(DLNode newNode) {
    if (head == null ) {
        head = newNode;
    }
    else {
        DLNode curNode = head;
        while (curNode.next != null) {
           // curNode.prev = curNode; Shouldn't be updating the prev when traversing
            curNode = curNode.next;     //Traverse         
        }
        curNode.next = newNode;
        newNode.prev = curNode;
        //curNode.prev = newNode.prev; This also must be removed. This cuts off the nodes from the list
    }
 }

答案 1 :(得分:0)

您必须将user7's answer与我在my comment中提出的建议一起使用。

public void append(DLNode newNode) {
    if (head == null ) {
        head = newNode;
    }
    else {
        DLNode curNode = head;
        while (curNode.next != null)
            curNode = curNode.next; 
        curNode.next = newNode;
        newNode.prev = curNode;
    }

}

public void remove(DLNode curNode) {
    DLNode sucNode = curNode.next;
    DLNode predNode = curNode.prev;
    if (sucNode != null)
        sucNode.prev = predNode;
    if (predNode != null)
        predNode.next = sucNode;
    else if (curNode == head)
        head = sucNode;
    else
        throw new IllegalArgumentException();

}

有关append()更改的说明,请参阅user7的答案。至于remove(),有四种情况:

  • 如果列表看起来像predNode <-> curNode <-> sucNode,即predNode != null && sucNode != null,则需要设置sucNode.prev = predNodepredNode.next = sucNode
  • 如果列表看起来像predNode <-> curNode,即predNode != null && sucNode == null,则需要设置predNode.next = null
  • 如果列表看起来像curNode <-> sucNode,即predNode == null && sucNode != null,则需要设置sucNode.prev = nullhead = sucNode
  • 如果列表看起来像curNode,即predNode == null && sucNode == null,则需要设置head = null

固定remove()方法正确处理这四种情况,并在curNode == head时对predNode == null进行完整性检查。

你的insertAfter()也被打破了。首先,head == null检查没用,因为head.next将始终在到达head == null检查之前抛出NullPointerException。我不太确定我是否按照预期的逻辑,但这是一个固定版本和解释:

public void insertAfter(DLNode curNode, DLNode newNode) {
    DLNode sucNode;

    if (curNode == null) {
        sucNode = head;
        head = newNode;
    } else {
        sucNode = curNode.next;
        curNode.next = newNode;
    }
    newNode.prev = curNode;

    newNode.next = sucNode;
    if (sucNode != null)
        sucNode.prev = newNode;
}
  • 如果列表为空,即curNode == null && head == null,则需要设置newNode.prev = nullnewNode.next = nullhead = newNode
  • 如果newNode应插入列表的首部,即curNode == null && head != null,则需要设置newNode.prev = nullnewNode.next = headhead = newNode
  • 如果将newNode附加到列表的尾部,即curNode != null && curNode.next == null,则需要设置newNode.prev = curNodenewNode.next = nullcurNode.next = newNode
  • 如果在两个节点之间插入newNode,即curNode != null && curNode.next != null,则需要设置newNode.prev = curNodenewNode.next = curNode.nextcurNode.next = newNode

您的prepend()也被破坏,因为head.prev将始终在head == null分支中抛出NullPointerException。 head != null分支正常工作但使用不必要的临时变量。这是一个固定版本:

public void prepend(DLNode newNode) {
    if (head == null) {
        newNode.next = null;
        head = newNode;
        newNode.prev = null;
    } else {
        head.prev = newNode;
        newNode.next = head;
        newNode.prev = null;
        head = newNode;
    }
}