我正在尝试从双向链接列表中删除节点,但是当我尝试删除第二个项目时,我得到NullPointerException
。我能够删除第一项和最后一项。
以下是我的代码:
@Override
public T removeElement(int index) {
// TODO Auto-generated method stub
T result = null;
if (IsEmpty()) {
throw new NoSuchElementException();
}
if (count == 1 && index == 0) {
result = head.getData();
head = null;
tail = null;
}
if (index == 0) {
result = head.getData();
head = head.getNext();
}
if (count == index) {
result = tail.getData();
tail = tail.getPrev();
tail.setNext(null);
}
int i = 1;
for (Node<T> current = head; current != null; current = current.getNext()) {
if (i == index){
result = current.getData();
Node<T> previous = current.getPrev();
Node<T> next = current.getNext();
previous.setNext(next);
next.setPrev(previous); //getting null pointer exception here
}
i++;
}
count--;
return result;
}
@Override
public void addElement(T data)//add elements in the list
{
Node<T> newNode = new Node<T>(data);
if (IsEmpty()) {
head = newNode;
tail = newNode;
}
else {
newNode.setPrev(tail);
tail.setNext(newNode);
tail = newNode;
}
count++;
}
这是我的测试程序:
public class Test {
public static void main(String[] args) {
DoubleListImpl<Integer> test = new DoubleListImpl<Integer>();
test.addElement(10);
test.addElement(20);
test.addElement(40);
test.addElement(50);
test.display();
System.out.println(test.getCount());
test.removeElement(4);
System.out.println();
//test.removeElement(3);
test.display();
System.out.println(test.getCount());
}
}
更新:
一分钟前我注意到了一些有趣的东西。如果我发出i=0
,当我在removeElement函数中传递index ==3
作为参数时,我得到一个空指针错误。或当我使i = 1时,当我将i==2
作为参数传递时,我得到一个空指针。
答案 0 :(得分:1)
我在评论中写道,我并不认为错误的if(count==index)
是NPE的原因。我现在看到它不是直接问题,但它没有捕获你请求删除实际最后一个节点的情况贡献( index count - 1
)。
当然,添加节点并且addElement()
最初返回count
时,您的IsEmpty()
方法未设置或增加true
,因此计数也将为错。事实上,如果IsEmpty()
依赖于count
来确定列表是否为空,那么addElement()
将永远不会将您的列表扩展到一个元素 - 新元素&#34;添加&#34;将改为替换之前的那个。
同样有一个原因是,即使已经通过早期特殊情况之一完成删除,执行也会在方法结束时进入循环,正如我已经观察到的那样。那么,考虑当index
恰好是循环的正确值以迭代到列表中的最后一个元素但不会超出的情况时会发生什么。控制进入以i == index
为条件的块,并检索当前元素的前一个和下一个元素。但有问题的元素是最后一个,因此其next
为null
。当您尝试在该空引用上调用setPrev()
时,会产生NPE结果。
我在评论中重申了我的建议,即添加内部Node
个对象作为头部和尾部,以便包含实际数据的节点都是内部的,并且您不需要所有特殊情况。例如,
class DoubleListImpl<T> implements DoubleList<T> {
private final Node<T> head = new Node<T>(null);
{ // better to put this in a constructor, but this way I avoid writing any
head.setNext(head);
head.setPrev(head);
}
// ...
@Override
public T removeElement(int index) {
int i = 0;
// negative indexes are always invalid
if (index < 0) {
throw new IndexOutOfBoundsException();
}
for (Node<T> current = head.getNext(); current != head;
current = current.getNext()) {
if (i == index){
Node<T> previous = current.getPrev();
Node<T> next = current.getNext();
previous.setNext(next);
next.setPrev(previous);
// maybe you need count for something else, but not for this
// count -= 1;
return current.getData();
}
i += 1;
}
// If control reaches here then the given index is invalid
throw new IndexOutOfBoundsException();
}
}
答案 1 :(得分:1)
大家好,感谢您的投入。我实际上弄清楚了我的错误,这很有效。以下是我对问题的解决方案。非常感谢你们的帮助:
@Override
public T removeElement(int index) {
// TODO Auto-generated method stub
T result = null;
assert(index>=1&&index<=count);
if(index==1){
if(count==1){
result = head.getData();
head = null;
tail = null;
}
else{
result = head.getData();
head = head.getNext();
head.setPrev(null);
}
}
else if(index==count){
result = tail.getData();
tail = tail.getPrev();
tail.setNext(null);
}
else{
Node<T> current = head;
int i=1;
while(current!=null){
if(i==index){
Node<T> prev = current.getPrev();
Node<T> next = current.getNext();
prev.setNext(next);
next.setPrev(prev);
break;
//current = null;
}
current = current.getNext();
i++;
}
}
count--;
return result;
}