Может кто-нибудь сказать мне, почему это возвращает пустой список (NPE)? - PullRequest
1 голос
/ 25 октября 2011

У меня есть этот код, который должен объединить два экземпляра 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 голосов
/ 25 октября 2011

Отлично! Ваша правка в значительной степени выявляет вашу проблему: вы неправильно расширяете 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 - вы не добавляете в SortedLinkedList (this), который добавляете в список внутри этого (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 () в первой строке вашего конструктора, чтобы вызывался код в конструкторе суперкласса). Удачи в выполнении домашней работы - я рекомендую проверить работоспособность объекта перед добавлением новых методов.

0 голосов
/ 25 октября 2011

просто любопытно, посмотрев на реализацию, но разве вы не могли просто сделать .addAll (...) с последующим Collections.sort (...)?Это то, что я бы предпочел лично.

...