谁能告诉我为什么这会返回一个空列表(NPE)?

时间:2011-10-25 06:33:24

标签: java exception merge linked-list

我有这个代码,它应该将SortedLinkedList的两个实例合并到一个SLL中(基于mergeSort合并),但是返回一个空列表:

import java.util.LinkedList;

public class SortedLinkedList<T extends Comparable<? super T>>
    extends LinkedList<T> {

private LinkedList<T> list; // the sorted list

// constructor, sorted with insertion sort
public SortedLinkedList(LinkedList<T> in)
{
    if(in.peek() == null || in.size() == 1)
        return;
    else {
        list = new LinkedList<T>();
        for(T e : in)
            list.add(e);
        int i, j;
        T temp;
        for(i = 0; i < list.size(); i++){
            j = i;
            temp = list.get(j);
            while(j > 0 && list.get(j-1).compareTo(temp) > 0){
                list.set(j, list.get(j-1));
                j--;
            }
            list.set(j, temp);
        }
}
}

// return the union of the sorted linked lists this
// and other
public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    list = new LinkedList<T>();
    SortedLinkedList<T> temp = new SortedLinkedList<T>(list);
    int i = 0, j = 0;
    while(i < this.size() && j < other.size()){
        if(this.get(i).compareTo(other.get(j)) <= 0){
            temp.add(this.get(i));
            i++;
        }
        else {
            temp.add(other.get(j));
            j++;
        }
    }
    while(i < this.size()){
            temp.add(this.get(i));
            i++;
    }
    while(j < other.size()){
            temp.add(other.get(j));
            j++;
        }
    return temp;
}

// print the items in list
public void print()
{
    for(T e : list)
        System.out.println(e);
}
}

在SLL构造函数中,我只需返回null列表(并且私有变量list在此方法的第一行中初始化)。但是据我所知,这仍然应该给我一个SLL对象(最初也是null)。我可以在方法本身中添加temp,但在打印列表时得到NullPointerException

我意识到使用get LinkedList效率不高。我解决了这个问题后,我会用迭代器切换它们。

任何提示都会非常感激。

编辑:有趣的是,如果我将两个列表放在一个临时LL中,然后在其上使用构造函数,我会得到相同的结果。由于SLL扩展了LL:

,因此类型是兼容的
public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

EDIT2:似乎@Mead是正确的...虽然size()和get()似乎适用于SLL,但add()却没有。我在想,因为我正在扩展LinkedList,所以它也适用于SLL。它没有,并且压倒它们也没有做任何事情......我对此没有想法。建议?

2 个答案:

答案 0 :(得分:0)

看到实现后只是好奇,但你不能刚刚完成一个.addAll(...)后跟一个Collections.sort(...)?这就是我个人喜欢的。

答案 1 :(得分:0)

大!您的编辑几乎可以揭示您的问题:您没有正确扩展LinkedList。解决这个问题,然后继续工作。

手头的问题:这是一个名为SortedLinkedList的类。我们可以假设它就像LinkedList一样,但它中的值是排序的。所以,鉴于此,这应该有效:

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinkedList<Integer>(unsorted);
System.out.println(sorted.size());
for (Integer i : sorted) {
   System.out.println(i);
}
// Should print out:
// 3
// 100
// 200
// 300

但它不会。运行你的代码,它打印出什么?

返回?为什么打印出来?首先,考虑可以在类的代码中使用的两个变量:this引用SortedLinkedList对象,this.list引用SortedLinkedList对象内的实例变量。然后让我们看一下构造函数:当你添加到列表中时,你正在调用this.list.add()。你所写的内容使得SortedLinkedList成为list实例变量的包装器 - 你不会添加到你要添加到其中的列表(this)的SortedLinkedList(this.list)。 使用this.list实例变量的唯一方法是构造函数,print和makeUnion。所有其他LinkedList方法都不知道list变量,所以当我调用get()时:

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinked<Integer>(unsorted);
System.out.println(sorted.get(0));

它不知道要查看您的this.list变量,因此它不会打印100。实际上,它会崩溃,因为索引0中没有值。您没有添加到get()实际使用的实例变量,因此方法认为SortedLinkedList对象为空。 this.list是继承方法不知道的新变量。

因此,如果我们检查您的最新编辑:

public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

temp.addAll(this)不起作用,因为this的所有方法都认为该列表为空,因为它们没有查看this.list。出于同样的原因,temp.addAll(other)也不起作用。

扩展类时常见的是您希望现有方法继续工作。这意味着您需要将数据存储在get()和其他方法所期望的位置。你是怎样做的?好吧,你已经在做了! 您已经做了正确的事 - 但您是在实例变量this.list而不是this上进行的。开始调用this.add()this.set()this.size()而不是this.list.add()并完全删除实例变量list - 不需要它,您有this。然后数据将是其他方法所期望的数据。

(并在构造函数的第一行调用super(),因此调用超类构造函数中的代码)。祝你的作业好运 - 我建议在添加新方法之前按原样测试对象。<​​/ p>