陷入困境

时间:2009-07-11 13:59:18

标签: java list loops infinite

我正在尝试用Java实现我自己的List系统。

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();
    }
}

现在,当我添加前两个节点时,一切都很好。但是,在我删除节点之后调用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;
}

但是对于大型列表而言,这对内存不友好。如果你能发现问题,请告诉我!

5 个答案:

答案 0 :(得分:3)

问题是您的列表最终损坏了。在列表中有2个项目的位置,它看起来像这样:

  
      
  1. 列出{info = Node(5,6),prev = null,next = 2}
  2.   
  3. 列出{info = Node(1,3),prev = 2,next = null}
  4.   

Woops,请注意列表 prev 字段中的第二项是指向自身?你的问题在于这个方法:

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

在该行上, ref.last()是一个循环查找列表中最后一项的方法,参考。但是,最后一项不是您所期望的,因为上一行看起来像这样:

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

您想要查找的是最后一项,因为它之前您通过在末尾添加新列表来设置 next 字段。但是,通过再次调用 last 方法,您可以在添加新列表后找到 new 最后一项。这就是为什么它的最后一个节点最终指向自己。

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;
}

......它会起作用。通过在修改之前将引用缓存到列表末尾,您现在可以获得正确的引用。

即便如此,您的代码也比以前复杂得多。您应该查看如何实现双链表的示例,您将找到示例,向您展示如何更简单地执行此操作。特别是 delete 方法过于复杂。

我还认为将空列表表示为包含 null 的节点时遇到问题。这似乎导致你需要检查各种令人讨厌的边缘情况。

答案 1 :(得分:1)

可能是你在对象上使用==。

if(ref.info() == o)

即使这不是您的无限循环的确切问题,也是您需要解决的问题。

答案 2 :(得分: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的第一个元素,或者您将在确实很长一段时间。

答案 3 :(得分: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;
    }

您总是将第二项添加到列表中并使其成为最后一项。这样,当您删除它时,它只会对自身执行killNext操作,并且您的第一个节点将不受影响。 然后,您会将自引用节点返回到您的调用示例,而不是您认为应该是剩余列表的引用。当你在那个节点上调用count()时,它会调用first()并且会被卡在循环中,因为!isFirst()总是为真,并且它总是将其自身引用为它的前一个,所以它会不断在ref = ref.prev();行重新安排自己。

答案 4 :(得分:0)

  

我正在尝试用Java实现我自己的List系统。

我的建议,不要。您应该重用标准的内置List并且可以工作。如果您想知道它是如何工作的,您可以阅读源代码。

知道如何编写自己的List实现可能在访谈中很有用,但我强烈建议你永远不要在实际工作中这样做!