java中的不替换拾取

java中的不替换拾取,java,data-structures,complexity-theory,montecarlo,picking,Java,Data Structures,Complexity Theory,Montecarlo,Picking,我经常*发现自己需要具有以下属性的数据结构: 可以用O(n)中的n个对象数组初始化 可以获得O(1)中的一个随机元素,在该操作之后,拾取 元素从结构中移除。 (无需更换) 可以撤消O(p)中的p“不替换拾取”操作 可以从O(log(n))中的结构中删除特定对象(例如通过id) 可以在中获取结构中当前的对象数组 O(n) 其他操作(如插入)的复杂性(甚至可能性)并不重要。除了复杂度外,它还应适用于少量的n 有谁能给我提供实施这种结构的指导方针吗?我目前实现了一个具有上述所有属性的结构,除了元素

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

  • 可以用O(n)中的n个对象数组初始化
  • 可以获得O(1)中的一个随机元素,在该操作之后,拾取 元素从结构中移除。 (无需更换)
  • 可以撤消O(p)中的p“不替换拾取”操作
  • 可以从O(log(n))中的结构中删除特定对象(例如通过id)
  • 可以在中获取结构中当前的对象数组 O(n)
其他操作(如插入)的复杂性(甚至可能性)并不重要。除了复杂度外,它还应适用于少量的n

有谁能给我提供实施这种结构的指导方针吗?我目前实现了一个具有上述所有属性的结构,除了元素的拾取采用O(d)和d表示过去拾取的数量(因为我显式地检查它是否为“尚未拾取”)。我可以找出允许在O(1)中拾取的结构,但这些结构在至少一个其他操作中具有更高的复杂性

顺便说一句: 注意,上面的O(1)意味着复杂性独立于#早期选取的元素,并且独立于总的#元素

*在monte carlo算法中(从n个元素的“集合”中迭代选取p个随机元素)。

HashMap的插入和删除复杂性均为O(1)。 您指定了很多操作,但所有操作都是插入、删除和遍历操作:

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

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

我们可以得到一个随机元素 O(1),在此操作之后,拾取 元素从结构中移除。 (无需更换)

这是唯一需要O(n)的op

一个人可以取消p'拾取,而无需 O(p)中的“替换”操作

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

可以移除特定对象(例如 通过id)从O(log(n))中的结构

O(1)

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

可以在O(n)中遍历哈希映射

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

一个分为“拾取”和“未拾取”的数组(或
ArrayList
)怎么样?跟踪边界的位置,要拾取边界,需要在边界下方生成一个随机索引,然后(因为不关心顺序),将该索引处的项与最后一个未拾取的项交换,并减小边界。要取消拾取,只需增加边界

更新:忘记了删除O(日志(n))。不过,这并不难,只是内存有点贵,如果您保留索引的ID的
HashMap

若你们在网上浏览,你们会发现各种各样的
IndexedHashSet
实现或多或少都遵循这个原则——一个数组或
ArrayList
加上一个
HashMap

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


更新2:嗯。。。或者,如果必须重新复制阵列或将其四处移动,实际移除是否会再次变为O(n)?

以下是我对在网络上使用的分析:

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

    是的,尽管成本是摊销的,除非事先知道n

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

    是,选择洗牌数组中的最后一个元素;用剩余元素的
    子列表()替换数组

  • ✔ 可以撤消O(p)中的p“不替换拾取”操作

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

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

    不,它看起来像O(n)

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

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

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

创建一个

List<String> array = ArrayList<String>("abc","def","ghi")
List array=ArrayList(“abc”、“def”、“ghi”)
使用以下值创建HashMap映射:

for (int i = 0; i < array.size(); i++) 
{
    map.put(array[i],i);
}
for(int i=0;i
O(1)通过选取数组中的任何索引,可以轻松实现随机查找。唯一出现的复杂情况是删除对象时。为此,请:

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

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

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


  • 我为java和cpp符号的混合表示歉意,希望这有助于

    我确实看到了如何使用hashmap实现除随机选取操作之外的所有操作。换句话说,如何从hashmap中选取随机元素?重新编辑:这不是O(1)选取(
    collection.toArray()
    始终至少是O(n)),而且它也不会从容器中移除选取的值。n、p和d的一些值是什么?一个非常有趣的结构。虽然不能保证移除是O(log(n)),但就我所见,移除是O(n)。它实际上类似于thrashgod的方法,但更有效,因为内存只分配一次。此外,如果索引了未粘贴的元素,则可以在O(1)中删除这些元素。@codelidoo:
    List<String> array = ArrayList<String>("abc","def","ghi")
    
    for (int i = 0; i < array.size(); i++) 
    {
        map.put(array[i],i);
    }