在没有循环的情况下随机获取HashMap或HashSet中的元素

时间:2011-10-31 21:31:10

标签: java collections hashmap hashset

我需要将大约420,000个元素轻松存储在某种Set或List中。但是限制是我需要能够选择一个随机元素并且需要快速。

最初我使用了ArrayList和LinkedList,但是使用那么多元素它非常慢。当我对它进行分析时,我发现我存储的对象中的equals()方法在很短的时间内被称为大约2100万次。

接下来我尝试了一个HashSet。我在性能方面获得的东西我在功能上松了一口气:我不能选择随机元素。 HashSet由HashMap支持,HashMap由HashMap.Entry个对象的数组支持。然而,当我试图暴露它们时,我被整个Java Collections Framework的疯狂私有和包私有的可见性所阻碍(即使复制和粘贴类也没有用,JCF非常“使用我们拥有的东西或滚动你自己的东西“)。

随机选择存储在HashSet或HashMap中的元素的最佳方法是什么?由于集合的大小,我宁愿不使用循环。

重要编辑:我忘记了一个非常重要的细节:我究竟是如何使用该系列的。我在桌子的乞讨处填充整个收藏品。在程序中,我选择并删除随机元素,然后选择并删除一些更多已知元素,然后重复。不断查找和更改是导致缓慢的原因

4 个答案:

答案 0 :(得分:4)

ArrayListLinkedList没有理由需要致电equals() ...虽然想要LinkedList这里你想要通过索引快速随机访问。

ArrayList应该是理想的 - 使用适当的容量创建它,将所有项添加到其中,然后您可以重复选择适当范围内的随机数,并调用get(index)得到相关价值。

HashMapHashSet根本不适用于此。

答案 1 :(得分:1)

如果 ALL 你需要做的是获取大量的值并随机选择一个值,那么ArrayList(字面上)完全符合您的需求。你不会明显加快速度(除非你直接进入原始数组,否则你会失去抽象的好处。)

如果这对你来说太慢了,那是因为你也在使用其他操作。如果您使用集合必须服务的所有操作更新您的问题,您将得到更好的答案。

答案 2 :(得分:1)

如果您不致电contains()(会多次拨打equals()),您可以使用ArrayList.get(randomNumber),那将是O(1)

你不能用HashMap来做 - 它将对象内部存储在一个数组中,其中index =对象的hashcode。即使您拥有该表,也需要猜测哪些存储桶包含对象。因此,HashMap不是随机访问的选项。

答案 3 :(得分:0)

假设equals()调用是因为您使用contains()对重复进行排序,您可能希望同时保留HashSet(对于快速if-already-present查找)和ArrayList {用于快速随机访问)。或者,如果操作不交错,则首先构建HashSet,然后使用toArray()提取其数据,或者使用后者的构造函数将其转换为ArrayList

如果您的问题是remove() ArrayList set()的问题,请不要使用它而是:

  1. 如果你不删除最后一个元素,只需用最后一个元素替换(用{{1}})删除的元素;
  2. 将列表大小缩小1.
  3. 这当然会搞砸元素顺序,但显然你不需要它,从描述来判断。或者你省略了另一个重要的细节?