2

Java で独自のリスト システムを実装しようとしています。

クラスListファイル:

package RoutingDemo.List;

/**
 * A 2-way Linked-List to store generic elements.
 *
 */
public class List   {

    /*
    Instance Variables
    ---------------------------------------------------------------------------
    */  
    /**
     * Reference to element.
     */
    private Object info;

    /**
     * Reference to previous NodeList instance.
     */
    private List prev;

    /**
     * Reference to next NodeList instance.
     */
    private List next;

    /*
    Constructors
    ---------------------------------------------------------------------------
    */
    /**
     * Creates a new empty list.
     */
    public List()   {
        prev = null;
        next = null;
        info = null;
    }


    /*
    Methods
    ---------------------------------------------------------------------------
    */  
    /**
     * Adds an element to the list.
     *
     * @param o Element to be added
     */
    public List add(Object o)   {
        if(info == null)    {
                info = o;
                prev = null;
                next = null;
                return this;
        }   else    {
                List temp = new List();
                temp.add(o);

                return addList(temp);
        }
    }


    /**
     * Appends an existing list to this list.
     *
     * @param newList List to be appended
     */
    public List addList(List newList)   {
        if(newList.info() == null)
                return this;

        List  ref = this;
        ref.last().setNext(newList.first());
        newList.first().setPrev(ref.last());

        return ref;
    }


    /**
     * Get number of elements in the list.
     *
     * @return number of elements in list
     */
    public int count()  {
        if(info == null)
                return 0;

        List ref = this.first();
        int count = 0;

        while(true) {
            count++;
            if(!ref.isLast())
                    ref = ref.next();  
                else
                    break;
        }           
        return count;
    }


    /**
     * Deletes an element from the list.
     *
     * @param o Element to be deleted
     * @return List which does NOT
     * contain element o
     */
    public List delete(Object o)    {
        if(info == null)
                return this;

        List ref = this.first();        

        while(true) {
            if(ref.info() == o) {
                    if(ref.isFirst() && ref.isLast())   {
                            ref = new List();
                            break;
                    }   else if(ref.isFirst())  {
                            ref = ref.next();
                            ref.killPrev();
                            break;
                    }   else if(ref.isLast())   {
                            /* *** THIS IS THE CASE THAT WILL BE CALLED FOR THIS TEST **** */
                            ref = ref.prev();
                            ref.killNext();
                            break;
                    }   else    {               
                            ref.prev().setNext(ref.next());
                            ref.next().setPrev(ref.prev());
                            ref = ref.prev();
                            break;
                    }
            }   else    {
                    if(!ref.isLast())
                            ref = ref.next();
                        else 
                            break;
            }
        }
        return ref;

    }


    /**
     * Moves to first element in List.
     *
     *
     * @return List pointing to first
     * element in list
     */
    public List first() {
        List ref = this;

        while(!ref.isFirst())   {
            /* *** STUCK HERE *** */
            ref = ref.prev();
        }

        return ref;
    }


    /**
      * Returns current list element.
      *
      * @return current list element
      */
    public Object info()    {
        return info;
    }


    /**
     * Checks whether list is empty.
     *
     * @return true, if list is empty
     * , false otherwise.
     */
    public boolean isEmpty()    {
            if(count() > 0)
                    return false;
                else
                    return true;
    }


    /**
     * Checks whether current element is the first element.
     *
     * @return true, if current element is
     * first element, false otherwise.
     */
    public boolean isFirst()    {
        if(prev == null)
                return true;
            else
                return false;
    }


    /**
     * checks whether current element is the last element.
     *
     * @return true, if current element is
     * last element, false otherwise
     */
    public boolean isLast() {
        if(next == null)
                return true;
            else
                return false;
    }


    /**
     * Cuts the list from next element.
     *
     *
     * @param l new link for current element
     */
    public void killNext()  {
        next = null;
    }


    /**
     * Cuts the list from previous element.
     *
     *
     * @param l new link
     */
    public void killPrev()  {
        prev = null;
    }


    /**
     * Moves to last element in List.
     *
     *
     * @return List pointing to last
     * element in list
     */
    public List last()  {
        List ref = this;

        while(!ref.isLast())    {
            ref = ref.next();
        }

        return ref;
    }


    /**
     * Moves to next element in List
     *
     *
     * @return List pointing to next
     * element in list
     */
    public List next()  {
        if(!isLast())
                return next;
            else
                return this;
    }


    /**
     * Moves to previous element in List
     *
     *
     * @return List pointing to previous
     * element in list
     */
    public List prev()  {
        if(!isFirst())
                return prev;
            else
                return this;
    }


    /**
     * Sets the next link
     *
     *
     * @param l new link for current element
     */
    public void setNext(List l) {
        next = l;
    }


    /**
     * Sets the prev link for current element
     *
     *
     * @param l new link
     */
    public void setPrev(List l) {
        prev = l;
    }
}

そして、私はそれを次のようにテストしていました:

    class Example   {
    Example()   {
        List nl = new List();
        nl = nl.add(new Node(5,6));
        System.out.println("" + nl.count());
        Node x = new Node(1,3);
        nl = nl.add(x);
        System.out.println("" + nl.count());
        nl = nl.delete(x);
        System.out.println("as" + nl.count());

    }
}

public class ListTest   {
    public static void main(String args[])  {
        new Example();
    }
}

最初の 2 つのノードを追加すると、すべて問題ありません。ただし、ノードを削除したcount() にを呼び出すと、無限ループに陥ります。

そして、多くのブレークポイントを通過した後、コード内でスタックしている場所をマークしました。どうやらdelete()関数に何か問題があるようです。何が間違っているのかわかりません。

とりあえず、delete()コードを次のように置き換えました。

    public List delete(Object o)    {
    if(info == null)
            return this;

    List ref = this.first();        
    List temp = new List();

    while(true) {
        if(ref.info() != o)
                temp.add(ref.info());
        if(!ref.isLast())
                ref = ref.next();
            else
                break;
    }

    return temp;
}

しかし、これは巨大なリストのメモリに優しくありません。問題を見つけることができたら教えてください!

4

5 に答える 5

3

問題は、リストが破損してしまうことです。リストに 2 つの項目がある時点で、次のようになります。

  1. リスト { 情報 = ノード (5,6)、前 = null、次 = 2 }
  2. リスト { 情報 = ノード (1,3)、前 = 2、次 = null }

おっと、リストのprevフィールドの 2 番目の項目がそれ自体を指していることに気付きましたか? あなたの問題はこの方法にあります:

public List addList(List newList) {
    // ...
    newList.first().setPrev(ref.last()); // <-- here
}

その行のref.last()は、リスト内の最後の項目 ref を探してループするメソッドです。ただし、前の行は次のようになっているため、最後の項目は期待どおりではありません。

ref.last().setNext(newList.first());

探したいのは、最後に新しいリストを追加して次のフィールドを設定する前の最後の項目です。ただし、最後のメソッドを再度呼び出すと、新しいリストが追加された後に、新しい最後のアイテムが見つかります。そのため、最後のノードが自分自身を指すことになります。

addListメソッドを次のように変更します。

public List addList(List newList)   {
    if(newList.info() == null)
                    return this;

    List ref = this;
    List last = ref.last();
    last.setNext(newList.first());
    newList.first().setPrev(last);

    return ref;
}

...そしてそれはうまくいきます。変更する前にリストの最後への参照をキャッシュすることで、正しい参照が得られます。

それでも、コードは必要以上に複雑です。二重リンク リストを実装する方法の例を調べると、はるかに簡単な方法を示す例が見つかります。特にあなたの削除方法は複雑すぎます。

また、空のリストをnullを含むノードとして表すことに問題があると思います。そのため、チェックが必要なあらゆる種類の厄介なエッジ ケースが発生しているようです。

于 2009-07-11T14:39:35.977 に答える
1

オブジェクトで == を使用している可能性があります。

if(ref.info() == o)

無限ループの正確な問題ではない場合でも、対処する必要がある問題です。

于 2009-07-11T14:10:50.220 に答える
1

あなたのコードには、無限ループの可能性がたくさん含まれています。次のようなコードを書き直してみてください

while (true) {
    // do something interesting
    if (someCondition)
        // go forward in the loop
    else
        break;
}

while (someCondition) {
    // do something interesting
    // go forward in the loop
}

できるだけ。

また、nextあなたの最後の要素のListが決してあなたの最初の要素を指していないことを確認してくださいList

于 2009-07-11T14:23:24.413 に答える
0

あなたの問題はaddListにあります:

    public List addList(List newList)   {
        if(newList.info() == null)
                        return this;

        List  ref = this;
        //you should get a reference to the original "last"
        ref.last().setNext(newList.first());
        newList.first().setPrev(ref.last());

        return ref;
    }

代わりにこれを行います:

    public List addList(List newList)   {
        if(newList.info() == null)
                        return this;

        List  ref = this;
        List last = ref.last();
        last.setNext(newList.first());
        newList.first().setPrev(last);

        return ref;
    }

あなたはいつもリストに2番目のアイテムを追加し、それをそれ自身の最後のものにしていました。このように、削除すると、それkillNext自体でのみ操作が実行され、最初のノードは変更されません。 次に、自己参照ノードを呼び出し元の例に戻します。残りのリストであると考えたものへの参照ではありません。count()そのノードを呼び出すとfirst()、!isFirst()が常にtrueであり、常にそれ自体を前のノードとして参照していたため、呼び出してループにスタックし、行内で継続的に自分自身を再参照していましたref = ref.prev();

于 2009-07-11T14:32:25.240 に答える