除了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();
}
答案 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 = predNode
和predNode.next = sucNode
predNode <-> curNode
,即predNode != null && sucNode == null
,则需要设置predNode.next = null
curNode <-> sucNode
,即predNode == null && sucNode != null
,则需要设置sucNode.prev = null
和head = 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 = null
,newNode.next = null
和head = newNode
newNode
应插入列表的首部,即curNode == null && head != null
,则需要设置newNode.prev = null
,newNode.next = head
和head = newNode
newNode
附加到列表的尾部,即curNode != null && curNode.next == null
,则需要设置newNode.prev = curNode
,newNode.next = null
和curNode.next = newNode
newNode
,即curNode != null && curNode.next != null
,则需要设置newNode.prev = curNode
,newNode.next = curNode.next
和curNode.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;
}
}