在java中选择无需替换

时间:2011-07-01 00:25:26

标签: java data-structures complexity-theory montecarlo picking

我经常发现自己需要一个具有以下属性的数据结构:

  
      
  • 可以使用O(n)中的n个对象数组进行初始化。
  •   
  • 一个人可以在O(1)中获得一个随机元素,在此操作之后拾取   元素从结构中删除。   (无需更换)
  •   
  • 可以在O(p)
  • 中撤消p'选择而无需替换'操作   
  • 可以从O(log(n))
  • 中的结构中删除特定对象(例如,通过id)   
  • 可以获得当前在结构中的对象数组   为O(n)。
  •   

其他行为(例如插入)的复杂性(甚至可能性)无关紧要。除了复杂性之外,它对于少量的n也应该是有效的。

有人能给我指导实施这样的结构吗?我目前实现了一个具有上述所有属性的结构,除了元素的选择需要O(d)和d过去选择的数量(因为我明确检查它是否'尚未被选中')。我可以找出允许在O(1)中进行拣选的结构,但这些结构在至少一个其他操作中具有更高的复杂性。

顺便说一句: 请注意,上面的O(1)意味着复杂性与#earlier拾取的元素无关,并且与总的#elements无关。

*在蒙特卡罗算法中(从n个元素的'集'中迭代选择p个随机元素)。

4 个答案:

答案 0 :(得分:2)

HashMap在插入和删除方面都有复杂度O(1)。 你指定了很多操作,但除了插入,删除和遍历之外,它们都不是其他任何操作:

  

可以使用O(n)中的n个对象数组进行初始化。

n * O(1)插入。 HashMap很好

  

可以获得随机元素   O(1),此操作后挑选   元素从结构中删除。   (无需替换)

这是唯一需要O(n)的操作。

  

可以撤消p'选择而不用   替换'O(p)中的操作

这是一个插入操作:O(1)。

  

可以删除特定对象(例如   通过id)来自O(log(n))

中的结构

O(1)。

  

可以获得对象的数组   目前在O(n)的结构中。

你可以在O(n)中遍历HashMap

编辑: 在O(n)中拾取随机元素的例子:

HashMap map ....
int randomIntFromZeroToYouHashMapSize = ...
Collection collection = map.values();
Object[] values = collection.toArray();
values[randomIntFromZeroToYouHashMapSize];

答案 1 :(得分:1)

如果一个数组(或ArrayList)分为“已挑选”和“未挑出”?你跟踪边界的位置,并选择,你在边界下面生成一个随机索引,然后(因为你不关心顺序),将该索引处的项目与最后一个未被删除的项目交换,并减少边界。要取消选择,只需增加边界。

更新:忘记删除O(log(n))。但是,如果你为索引保留HashMap个ID,那就不那么难了,只需要一点内存。

如果你在线搜索,你会发现各种IndexedHashSet实现都或多或少地遵循这个原则 - 数组或ArrayList加上HashMap

(我希望看到一个更优雅的解决方案,如果存在的话。)

更新2:嗯......或者实际移除是否会再次成为O(n),如果您必须重新复制数组或移动它们?

答案 2 :(得分:1)

以下是我在Collections.shuffle()上使用ArrayList的分析:

  • ✔可以使用O(n)中的n个对象数组进行初始化。

    是的,虽然费用摊销,除非事先知道n。

  • ✔可以在O(1)中获得随机元素,在此操作之后,拾取的元素将从结构中移除,而无需替换。

    是的,选择混洗数组中的最后一个元素;用剩余元素的subList()替换数组。

  • ✔可以在O(p)中撤消p'选择而无需替换'操作。

    是的,通过add()将元素附加到此列表的末尾。

  • ❍可以从O(log(n))中的结构中删除特定对象(例如,通过id)。

    不,看起来像是O(n)。

  • ✔可以在O(n)中获取结构中当前对象的数组。

    是的,使用toArray()看起来很合理。

答案 3 :(得分:1)

好的,与0verbose相同的答案,只需要一个简单的修复就可以获得O(1)随机查找。创建一个存储相同n个对象的数组。现在,在HashMap中,存储对。例如,假设您的对象(简单的字符串)是:

{"abc" , "def", "ghi"}

创建

List<String> array = ArrayList<String>("abc","def","ghi")

使用以下值创建HashMap地图:

for (int i = 0; i < array.size(); i++) 
{
    map.put(array[i],i);
}

通过选择数组中的任何索引,可以轻松实现O(1)随机查找。出现的唯一复杂因素是删除对象时。为此,请执行:

  1. map中查找对象。获取其数组索引。让我们调用这个索引imap.get(i)) - O(1)

  2. 使用array [size of array - 1](数组中的最后一个元素)交换数组[i]。将数组的大小减小1(因为现在减少了一个数字) - O(1)

  3. i中更新数组位置map中新对象的索引(map.put(array [i],i)) - O(1)

  4. 我为java和cpp表示法的混合道歉,希望这有帮助