迭代Java中的列表

时间:2011-05-27 00:51:28

标签: java listiterator

问题如下:

编写一个静态方法子集,该子集使用递归回溯来查找给定列表的每个可能的子列表。列表L的子列表包含0个或更多个L's元素。您的方法应接受字符串列表作为其参数,并打印可从该列表的元素创建的每个子列表,每行一个。例如,假设名为list的变量存储以下元素:

[Janet, Robert, Morgan, Char]

子集的调用(列表);会产生如下输出:

[Janet, Robert, Morgan, Char]
[Janet, Robert, Morgan]
[Janet, Robert, Char]
[Janet, Robert]
[Janet, Morgan, Char]
[Janet, Morgan]
[Janet, Char]
[Janet]
[Robert, Morgan, Char]
[Robert, Morgan]
[Robert, Char]
[Robert]
[Morgan, Char]
[Morgan]
[Char]
[]

我的部分解决方案要求使用递归回溯:

ListIterator<String> itr = choices.listIterator();
      while (itr.hasNext()) {
         String word = itr.next();
         chosen.add(word);
         itr.remove();
         subsets(choices, chosen, alreadyPrinted);
         chosen.remove(word);
         itr.add(word);
      }

但是我在包含itr.add(word)的行上得到了ConcurrentModificationException。为什么?我认为ListIterator的重点是避免这个问题吗?

编辑:我也试过像这样解决它:

for (String word : choices) {
         List<String> choicesCopy = choices;
         chosen.add(word);
         choicesCopy.remove(word);
         subsets(choicesCopy, chosen, alreadyPrinted);
      } 

我仍然得到并发修改例外.... :( 这是怎么回事?根本没有对原始列表进行修改......

4 个答案:

答案 0 :(得分:2)

不完全是,问题是(很可能)每次递归时都会创建ListIterator()。每个List Iterator都试图修改相同的基础单词列表,从而触发异常。这是不允许的。

解决方案是每次递归时提供单词列表的副本。像这样,每个列表迭代器都可以在自己的个人列表中工作。

答案 1 :(得分:0)

编辑:我错过了OP正在使用ListIterator

ConcurrentModificationException的原因是您在迭代它时通过添加和删除元素来修改基础列表。我相信你将不得不使用更原始的迭代技术,比如传统的for循环,并自己跟踪迭代值。

从以上链接:

  

如果线程修改了集合   直接迭代   快速失败的集合   迭代器,迭代器会抛出这个   例外

Here是另一篇关于它的快速文章。

答案 2 :(得分:0)

在每次递归调用时创建新的迭代器,然后使用它删除/添加。 当你向上移动堆栈时,旧的迭代器会检测到变化并产生异常。

您应该重新考虑此代码。

答案 3 :(得分:0)

你的第二个解决方案有一个简单的错误。

List<String> choicesCopy = choices;

这不会创建列表的副本。您可以使用ArrayList.clone()或LinkedList.clone()或创建一个这样的新列表

List<String> choicesCopy = new LinkedList<String>(choices);