8

Iteratorインターフェースを実装する内部クラスを実装する必要がある大学の割り当てがあります。イテレータは、単一リンクリストのスーパークラスで機能します。

現在、私の内部クラスは次のようになっています。

private class ListIterator implements Iterator<V>{

    Node temp;
    boolean nextCalled = false;

    ListIterator(Node fo){
        this.temp = fo;
    }

    @Override
    public boolean hasNext() {
        if(temp != null){
            return true;
        }
        return false;
    }

    @Override
    public V next() {
        nextCalled = true;
        return temp.getReprValue();
    }

    @Override
    public void remove() {
        if(nextCalled && hasNext()){
            nextCalled = false;
            removeElement(temp.getReprKey());
            temp = temp.getNext();
        }

    }

}

私の問題は、リストが実際に空の場合でも、hasNext()メソッドがtrueを返すことです。他のすべてはうまくいくようです。私はおそらくどこかで論理的な欠陥を見落としていましたが、私はそれを自分で見つけることができません。

4

4 に答える 4

5

Iterator コントラクトが必要とするものを反映するように実装を変更しました。コレクションのすべての要素を反復処理できる必要があることを覚えておく必要があります。つまり、next()最初の要素から開始し、呼び出しのたびに、現在の次の要素をリスト内の次の要素に変更するか、例外をスローする必要があります。ありません。

Iterator インターフェイスのドキュメントを読んで、必要な実装方法を理解し、そこから始めることをお勧めします。

private class ListIterator implements Iterator<V> {
    private Node next;
    private boolean alreadyDeleted = false;

    ListIterator(Node node){
        this.next = node;
    }

    @Override
    public boolean hasNext() {
        // because next is the current element. We need to iterate over all the elements
        // from the collection.
        return next != null;
    }

    @Override
    public V next() {
        if (next == null) {
           throw new NoSuchElementException();
        }

        Node current = next;

        this.next = current.getNext();
        this.alreadyDeleted = false; // it's better to try to elimate this state variable. You can try to do in another way, if yours removeElement returns something

        return current;
    }

    @Override
    public void remove() {
        if (alreadyDeleted || next == null) {
           throw new IllegalStateException();
        }
        removeElement(next.getReprKey());
        this.alreadyRemoved = true;
    }

}
于 2013-03-12T15:45:23.660 に答える
5

リスト内のどこにいるかを追跡し、 を実装するcursorか、リンクされたリスト内のノードが を認識してnextいる場合は、次の要素があるかどうかを確認する必要があります。カーソルが長さよりも大きい/ノードがないnext場合、hasNext() で false を返します。

これらすべてをhasNext()メソッドで行います。覚えておいてください、next()hasNext()が false であった場合に例外をスローしても問題ありません。そのため、例外がスローされるのはそのときだけであることを確認する必要があります。

リストの基礎となるデータ構造がわからないため、どちらが優れているかはわかりません。

于 2013-03-12T15:24:55.130 に答える
2

一部のコードを減らして、少し読みやすくするため

  • 名前tempnext、に変更します
  • ショートカット表記を使用し、
  • おそらくcurrentノードの概念が必要ですが、

これにより、更新は次のようになります。

private Node next;
private Node current;    //track deletion

@Override
public boolean hasNext() {
    return next != null;
}

public Node getNext() {
  if (hasNext()) {
    current = next;
    next = next.getNextNode();
  }
  return current;
}

削除により、currentがnullに設定される可能性があります。フラグは必要ありません(最初の人に電話する前に人が削除しても何もしなくても大丈夫だと仮定しますgetNext()。本当に金を手に入れたいのなら、ifを投げremove()ました。IllegalStateExceptioncurrent == null

于 2013-03-12T15:59:43.640 に答える
2

hasNext現在のノード ( temp) がそうでない場合は true を返しますnull

リンクされたリストの実装がヘッダー ノードを使用する場合、リストが空であっても、コンストラクターは常に受け取りfo!=nullhasNext戻ります。true実装では、この事実を考慮する必要があります。

あなたのコードに基づいて、それは

ListIterator(Node fo){
    this.temp = fo.getNext();
}

トリックを行うかもしれません(header.getNext()==null空のリストの場合)。

于 2013-03-12T15:25:57.270 に答える