陷入循环

发布于 2024-07-26 16:33:47 字数 7584 浏览 10 评论 0原文

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

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

但这对于大型列表来说不利于内存。 如果您能发现问题,请告诉我!

I'm trying to implement my own List system in Java.

the List class file :

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

And I was testing it out like this:

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

Now, everything is fine when I add the first two nodes. However, I go into an infinite loop when I call the count() after I delete a node.

And after going through a lot of breakpoints, I've marked the place in the code where I get stuck. Apparently something is wrong in the delete() function, I cannot figure out what I'm doing wrong.

For the time being, I've replaced my delete() code with this :

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

But this wouldnt be memory-friendly for huge lists. Let me know if you can spot the problem!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

遗忘曾经 2024-08-02 16:33:47

问题是你的列表最终被损坏了。 当列表中有 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());

您想要查找的是最后一个项目,因为它在您设置它之前 em>next 字段,将新列表附加到末尾。 但是,通过再次调用 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 的节点时遇到问题。 这似乎导致您需要检查各种令人讨厌的边缘情况。

The problem is that your list ends up corrupted. At the point where you have 2 items in the list, it looks something like this:

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

Woops, notice the second item in the list's prev field is pointing at itself? Your problem is in this method:

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

On that line, ref.last() is a method that loops through looking for the last item in the list, ref. However, the last item isn't what you expect it to be, because the previous line looks like this:

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

What you want to look for is the last item as it would have been before you set it's next field by appending the new list on the end. However, by calling the last method again, you're finding the new last item, after the new list has been appended. That's why its last node ends up pointing to itself.

Change your addList method to look like this:

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

...and it will work. By caching the reference to the end of the list before modifying it, you have the correct reference now.

Even so, your code is quite a bit more complicated than it has to be. You should look up an example of how to implement a double linked list and you will find examples that show you how to do it far simpler. Your delete method in particular is far too over-complicated.

I also think you have problems with representing the empty list as a node containing a null. That seems to be causing you to have all kinds of nasty edge cases you need to check for.

那支青花 2024-08-02 16:33:47

这可能是因为您在对象上使用了 == 。

if(ref.info() == o)

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

It could be the fact that you are using == on Objects.

if(ref.info() == o)

Even if it isn't your exact problem for your infinite loop, it is a problem that you need to address.

水晶透心 2024-08-02 16:33:47

您的代码包含大量无限循环的潜力。 尝试

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

重写看起来像的

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

尽可能

代码。 另外,请确保 List 最后一个元素的 next 永远不会指向 List 的第一个元素,否则您确实会兜圈子很长一段时间。

Your code contains lots of potential for infinite loops. Try to rewrite code that looks like

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

to

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

as much as possible.

Also, make sure that that the next of the last element of your List will never point back to the first element of your List, or you'll be running around in circles for a long time indeed.

灰色世界里的红玫瑰 2024-08-02 16:33:47

您的问题出在 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() 始终为 true,而且它是始终将自身作为其前一个引用,因此它会在 ref = ref.prev(); 行中不断重新定位自身。

your problem is in 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;
    }

do this instead:

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

You were always adding the second item to the list and making it its own last. This way, when you deleted it, it would only perform the killNext operation on itself and your first node would be untouched. You would then return the self-referencing node back to your calling example, not a ref to what you thought should be the remaining list. When you called count() on that node, it would call first() and would get stuck in the loop because !isFirst() would always be true, and it was always referencing itself as its previous, so it would continually reassnging itself in the ref = ref.prev(); line.

季末如歌 2024-08-02 16:33:47

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

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

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

I'm trying to implement my own List system in Java.

My suggestion, don't. You should reuse the built in List which is standard and works. If you want to know how it work you can read the source.

Knowing how to write you own List implementation might be useful in interviews but I would strongly suggest you never do this in a real job!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文