2013-02-15 70 views
4
随机顺序

它看起来像我也不能使用ArrayList也没有一套:集合,没有重复,并在Java中

  • Set<> - 我能避免使用一组重复,但没有洗牌的选项//Collections.shuffle(List<?> list)

  • ArrayList<> - 我可以使用shuffle随机化列表,但允许重复。

我可以用一个Set,并转换成ArrayList(或者反过来),这样,避免了重复。或者,循环遍历集合以随机化项目。但我正在寻找更高效的东西。

+0

在添加它之前,您可以检查该项是否已存在于ArrayList中:myList.contains(myItem);这个检查只应该是O(n)。 – HectorLector 2013-02-15 10:56:07

+4

*更有效率的东西*>您是否在说这是因为您已经(a)尝试过,并且(b)通过适当的基准测试得出结论,这是您的应用程序中的一个重大瓶颈?如果不是,请不要过早地优化并写出最清楚的版本(可能转换为数组列表)。 – 2013-02-15 10:57:42

回答

3

您可以维护两个单独的收藏,一个ArrayList和一个HashSet,并拒绝插入任何存在于HashSet中的物品。

如果您关心封装,包住两个集合的元对象实现List,并仔细记录重复的元素的插入会被拒绝,即使List一般合同并没有规定这样。

说到这个解决方案的成本,我相信,在时间上,如果相比于普通ArrayList成本是绝对可以忽略不计:大部分操作上HashSet成本存在摊销O(1),即查找和插入。另一方面,您的内存使用量将是两次(或更多,具体取决于HashSet加载因子)。

+0

根据你对我的回答的评论,你的解决方案可能是最好的。但是我会提到O(1)重复检查。 – 2013-02-15 11:04:15

+0

它有点争议。在某些情况下,HashSet中的插入可能会花费O(n)。但是我添加了它。 – gd1 2013-02-15 11:04:52

+2

你也可以实现Set,并创建一个迭代器,以我想的随机顺序返回元素。 – 2013-02-15 11:07:24

0

随着代码量最少,最优雅的气质,你可以这样做:

public void testFoo() { 
    Set<Integer> s = new TreeSet<Integer>(); 

    s.add(2); 
    s.add(1); 
    s.add(3); 

    Collections.shuffle(Arrays.asList(s.toArray())); 
} 

但是,这不是很有效,你可以使用一个数组和哈希函数把元素所需位置在数组上,并且在放置它们之前检查它们是否已经存在,这将在O(n)时间内工作,所以它非常好,但需要更多的代码和一些关注散列函数。

0
  • 您可以使用地图以避免重复,然后Map.entrySet()和洗牌的ArrayList
0

其实你可以使用一个“有序集”,例如TreeSet中。为了得到一个随机顺序,不要插入实际的项目,而要插入一些随机权重的包装并使用相应的比较器。然而,重新洗牌将需要更新所有包装重量。