带有O(1)随机访问和删除的有序列表

时间:2015-01-14 21:21:30

标签: algorithm data-structures

是否存在具有以下属性的数据结构:

  • 元素按某种顺序存储
  • 访问给定索引处的元素需要O(1)时间(可能已摊销)
  • 删除元素需要分摊O(1)时间,并适当地更改索引(因此,如果删除元素0,则对元素0的下一次访问应该返回旧元素1)

对于上下文,我将算法问题从编程竞赛减少到:

超过m个查询,返回尚未返回的k个最小正数。您可以假设返回的数字小于某个常数n

如果上面的数据结构存在,那么您可以在O(m)时间内执行此操作,方法是创建一个数字1到n的列表。然后,对于每个查询,找到索引k处的元素并将其删除。在比赛期间,我的解决方案最终在某些输入上O(m^2)

我很确定你可以使用二叉搜索树在O(m log m)中执行此操作,但我想知道理想的O(m)是否可以访问。我在网上找到的东西往往很接近,但不是很接近 - 棘手的部分是你删除的元素可以来自列表中的任何地方。

2 个答案:

答案 0 :(得分:4)

  1. O(1)

    可以移除linked list

    每个元素都有指向next和previous元素的指针,因此remove只删除元素并设置其邻居的指针,如:

    element[ix-1].next=element[ix+1].prev
    
  2. 可以使用O(1)

    来访问indexed arrays中索引处的有序元素

    所以你有像dat[]这样的无序数组和像idx[]这样的索引数组,元素ix的访问只是:

    dat[idx[ix]]
    
  3. 现在问题是要立即拥有这些属性

    你可以尝试将链表与索引数组相关联,但删除需要更新索引表,在最坏的情况下为O(N)

    如果您只有索引数组,则删除也是O(N)

    如果索引采用某种形式的树形结构,则删除可能接近O(log(N)),但访问权限也大约为O(log(N))

答案 1 :(得分:2)

我相信有一种结构可以在O(n)时间内完成这两个任务,其中n是已被移除的点数,而不是总大小。因此,如果您要删除的数字与数组的大小相比较小,则它接近于O(1)。

基本上,所有数据都存储在一个数组中。已删除元素还有一个优先级队列。初始化如下:

Data = [0, 1, 2, ..., m]
removed = new list

然后,要删除一个元素,可以将它的原始索引(请参见下面的获取方法)添加到优先级队列(按前面最小的元素大小排序),然后保持数组不变。所以删除第3个元素:

Data = [0, 1, 2, 3,..., m]
removed = 2

那么现在是第4名,是第5名:

Data = [0, 1, 2, 3,..., m]
removed = 2 -> 4

然后现在是第3名并且是第4名:

Data = [0, 1, 2, 3,..., m]
removed = 2 -> 3 -> 4

现在要访问一个元素,你可以从它的索引开始。然后,您沿着删除的列表进行迭代,每次将索引增加1,直到您到达的元素大于索引的增加值。这将为您提供您正在寻找的元素的原始索引(即数据中的位置),并且是您需要删除的索引。

这种沿队列迭代的操作有效地将索引增加了被删除之前的元素数量。

对不起,如果我没有很好地解释,我脑子里很清楚,但很难写下来。

评论:

  • 访问权限是O(n),包含n个已删除的项目
  • 删除大约是访问时间的两倍,但仍然是O(n)
  • 缺点是内存使用不会因删除而缩小。
  • 当删除列表很大时,可能会“重新初始化”以重置内存使用以及访问和删除时间。此操作采用O(N),N总数组大小。

所以这不是OP所期待的,但在适当的情况下可能会很接近。