2011-05-27 77 views
1

列表中的问题如下:迭代在Java中

编写一个使用递归回溯找到一个给定列表的每一个可能的子列表中的静态方法的子集。列表L的子列表包含0个或更多的元素。您的方法应该接受一个字符串列表作为其参数,并打印每个可以从该列表的元素创建的子列表,每行一个。例如,假设名为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行(字)的ConcurrentModificationException的。为什么?我认为ListIterator的整个目的是为了避免这个问题?

编辑:我也想解决这样的:

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

我仍然得到一个ConcurrentModificationException的....:?( 怎么会出现这种情况有没有原始列表的修改的所有.. 。

+1

这个功课? – Casey 2011-05-27 00:54:16

回答

2

不完全是,这个问题是(最有可能)您创建ListIterator()每次去递归。每个列表迭代器试图修改单词相同的底层列表,从而引发异常的时间。这是不允许的。

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

+0

所以我应该使用迭代器? – user658168 2011-05-27 01:33:11

+0

你可以,但你没有义务。问题是你不应该使用两个列表迭代器,并在同一个列表上同时执行修改。 – JVerstry 2011-05-27 01:36:46

0

编辑:我错过了OP是使用ListIterator

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

从上面的链接:

如果一个线程修改集合 直接而它遍历 具有快速失败 迭代器收集,迭代器将抛出此 例外

Here是另一篇快速文章。

+1

这是不正确的,'Iterator.add()'和'Iterator.remove()'是显式提供的,以允许在迭代过程中进行修改。除非同时在同一个集合上有多个活动迭代器,否则这些方法不会引发此异常。 – verdesmarald 2011-05-27 01:03:46

+0

啊,你是对的。出于某种原因,我完全读了ListIterator。 – Casey 2011-05-27 01:11:15

+0

所以我应该使用迭代器? – user658168 2011-05-27 01:32:50

0

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

您应该重新考虑这段代码。

0

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

List<String> choicesCopy = choices; 

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

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