2

我正在尝试用 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;
}

但这对于巨大的列表来说是不友好的。如果您能发现问题,请告诉我!

4

5 回答 5

3

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

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

糟糕,请注意列表prev字段中的第二项指向自身?您的问题出在这种方法中:

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

在那一行中,ref.last()是一种循环查找列表中最后一项的方法,即 ref。但是,最后一项并不是您所期望的,因为前一行如下所示:

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

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

将您的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;
    }

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

于 2009-07-11T14:32:25.240 回答
0

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

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

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

于 2009-07-11T15:15:19.023 回答