【问题标题】:java infinite loop while using collections [closed]使用集合时的java无限循环[关闭]
【发布时间】:2012-11-03 02:53:00
【问题描述】:

请建议我解决下面的无限循环。类对象包含相同类型对象的集合。在转换为 String 时,该对象调用集合中每个对象的 toString。因此它导致无限循环。 请不要使用任何静态变量。

import java.util.LinkedList;

/**
 *
 * @author ranga
 */
public class MyList  {
    LinkedList<Object> l1,l2;

    MyList() {
        l1 = new LinkedList<Object>();
        l2 = new LinkedList<Object>();
        l2.add(l1);
        l1.add(l2);
    }

    @Override
    public String toString() {
        return l1.toString();
    }

    public static void main(String ...args) {
        MyList m = new MyList();
        System.out.println(m);
    }
}

【问题讨论】:

标签: java collections linked-list stack-overflow infinite-loop


【解决方案1】:

不要将链表添加到自身。

【讨论】:

    【解决方案2】:

    我将假设您有意创建了一个循环数据结构作为示例,并且您确实确实希望能够生成一个字符串渲染循环图。

    答案并不简单。

    首先,您需要在不进入循环的情况下执行(可能)循环图的遍历。基本算法是这样的:

    public void traverse(List<?> graph) {
        doTraverse(graph, new IdentityHashMap<?, ?>());
    }
    
    private void doTraverse(List<?> graph, IdentityHashMap<?, ?> visited) {
        if (visited.get(graph) == null) {
            visited.put(graph, graph);
            for (Object element : graph) {
                if (element instanceof List<?>) {
                    doTraverse((List<?>) element, visited);
                }
            }
        }
    }
    

    visited 映射允许遍历不访问它已经访问过的节点。


    问题的第二部分是修改代码来进行渲染。在这一点上,您必须决定如何在输出为字符序列的上下文中呈现图中的循环。

    显而易见的方法是给事物贴上标签。例如我们可以将l1 的渲染写成

    1: [2: [1] ]
    

    (每个列表表示为[ ... ]n:表示后面的东西有一个“标签”n。当我们遇到一个我们已经看到的“节点”时,我们使用一个标签;例如上面的第二个1 指的是我们标记为1 的列表。)

    给定这样的表示形式,我们可以修改doTravers 方法以采用额外的StringBuilder 参数,并更改IdentityHashMap 以将标签字符串作为值保存。其余的都很简单。

    这种方法的问题是:

    • 渲染的可读性不是很好...尤其是对于更大和/或更复杂的图形结构。
    • 算法需要知道如何遍历和渲染所涉及的特定类型。很难以通用的、独立于数据结构的方式实现这一点。

    【讨论】:

      【解决方案3】:

      是我还是递归调用 ToString() 方法总是递归调用自身 并且没有一个递归调用可以停止的情况? 如果是这样,您需要一些条件来退出递归调用自身。

      【讨论】:

        【解决方案4】:

        toString() 方法没有任何问题。默认情况下,它通过迭代来打印集合中的所有元素(查看AbstractCollection.toString() 的实现)。您遇到的问题是通过将列表作为元素添加到另一个(反之亦然)。打印l1时,调用l2toString()方法(因为它是第一个元素),依次打印一个元素,由于l2的第一个元素是l1它调用它的toString() 方法,依此类推……

        简而言之,不要通过将列表作为元素相互添加来短路列表。

        【讨论】:

          猜你喜欢
          • 2017-05-19
          • 2015-03-02
          • 2014-01-28
          • 2015-10-01
          • 2021-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多