我不确定它是否可能,但对我来说似乎有点合理,我正在寻找一种允许我进行这些操作的数据结构:
当然,编辑不会导致元素顺序的任何变化。什么使它成为可能的是我将按递增的顺序逐个插入元素。因此,例如,如果我尝试第五次插入,我确定在此之前的所有四个元素都比它小,并且在此之后的所有元素将会更大。
答案 0 :(得分:3)
我不知道这样的数据容器是否可以满足所要求的时间复杂性。但这里有几种方法,几乎可以实现这些复杂性。
第一个是tiered vector,其中O(1)插入和索引,但O(sqrt N)删除。由于您希望此容器中只有大约10000个元素,并且sqrt(10000)/ log(10000)= 7,因此您可以获得几乎所需的性能。分层向量是作为一个环形缓冲区数组实现的,因此删除一个元素需要移动所有元素,在环形缓冲区中跟随它,并将一个元素从以下每个环形缓冲区移动到它之前的那个;此容器中的索引意味着在环形缓冲区数组中进行索引,然后在环形缓冲区内进行索引。
可以创建一个与分层向量非常相似的不同容器,具有完全相同的复杂性,但工作速度更快,因为它更易于缓存。分配N元素数组以存储值。并分配一个sqrt(N)元素数组来存储索引更正(用零初始化)。我将展示它如何在100元素容器的示例上工作。要删除索引为56的元素,将元素57..60移动到位置56..59,然后在索引更正数组中将1添加到元素6..9。要查找第84个元素,请在索引更正数组中查找第8个元素(其值为1),然后将其值添加到索引(84 + 1 = 85),然后从主数组中获取第85个元素。在删除主阵列中大约一半的元素之后,必须压缩整个容器以获得连续的存储。这仅获得O(1)累积复杂度。对于实时应用程序,可以通过几个较小的步骤执行此操作。
这种方法可以扩展到深度M的Trie,花费O(M)时间进行索引,O(M * N 1 / M )时间用于删除和O( 1)插入时间。只需分配一个N元素数组来存储值,N (M-1)/ M ,N (M-2)/ M ,...,N < sup> 1 / M - 用于存储索引更正的元素数组。要删除元素2345,在主数组中移动4个元素,在最大的“更正”数组中增加5个元素,在下一个元素中增加6个元素,在最后一个元素中增加7个元素。要从此容器中获取元素5678,请在元素5,56,567中添加5678所有更正,并使用结果索引主数组。为“M”选择不同的值,可以平衡索引和删除操作之间的复杂性。例如,对于N = 65000,您可以选择M = 4;所以索引只需要4次内存访问和删除更新4 * 16 = 64个内存位置。
答案 1 :(得分:1)
我想首先指出,如果 k 实际上是一个随机数,那么可能值得考虑问题可能完全不同:要求第k个最小元素,用k在可用元素的范围内随机均匀地基本上......随机选取元素。而且可以采用不同的方式。
在这里,我假设你实际上需要选择一些特定的,如果是任意的, k 。
鉴于你的强大前提条件是按顺序插入元素,有一个简单的解决方案:
问题当然是,当你删除元素时,你会在表格中创建空白,这样元素 T [k] 可能不是k-因为 j <= k ,所以j最小,但是k之前的一些单元格是空的。
这足以跟踪您已删除的元素,知道 已被删除的小于 k 。你如何及时达到O(log n)?通过使用range tree或类似类型的数据结构。范围树是一种结构,可让您添加整数,然后查询,用于 X 和 Y 之间的所有整数。因此,无论何时删除项目,只需将其添加到范围树中;当您查找第k个最小元素时,查询已删除的 0 和 k 之间的所有整数;说 delta 已被删除,那么第k个元素将在T [k + delta]中。
有两个轻微的捕获,需要一些修复:
范围树返回时间范围O(log n),但要计算范围内元素的数量,您必须遍历范围中的每个元素,这样就会增加时间O(D)其中D是范围内已删除项目的数量;要摆脱这种情况,您必须修改范围树结构,以便在每个节点上跟踪子树中不同元素的数量。保持这个计数只会花费O(log n),这不会影响整体复杂性,而且这是一个相当简单的修改。
事实上,只做一个查询是行不通的。实际上,如果在范围1到k中获得delta删除元素,则需要确保在范围k + 1到k + delta中没有删除元素,依此类推。完整的算法将是下面的内容。
KthSmallest(T,k) := {
a = 1; b = k; delta
do {
delta = deletedInRange(a, b)
a = b + 1
b = b + delta
while( delta > 0 )
return T[b]
}
此操作的确切复杂程度取决于您删除的确切程度,但如果您的元素随机均匀删除,则迭代次数应该相当小。
答案 2 :(得分:0)
查看heaps。插入和删除应为O(log n),并且最小元素的偷看是O(1)。但是,偷看或检索第K个元素将再次为O(log n)。
EDITED:正如amit所说,检索比偷看更贵。
答案 3 :(得分:0)
这可能是不可能的。 但是,您可以在平衡二叉树中进行某些更改,以便在O(log n)中获取第k个元素。
在此处详细了解:Wikipedia.
答案 4 :(得分:0)
可索引的跳过列表可能能够(关闭)您想要的内容: http://en.wikipedia.org/wiki/Skip_lists#Indexable_skiplist
然而,有一些警告:
最有可能的是,为实现目标,你可以做的事情就是“最好的”。
答案 5 :(得分:0)
有一个Treelist(Java实现,包含源代码),对于所有三个操作都是O(lg n)(插入,删除,索引)。
实际上,此数据结构的可接受名称似乎是“order statistic tree”。 (除了索引之外,它还被定义为支持O(lg n)中的 indexof(元素)。)
顺便说一句,O(1)并不比O(lg n)更有优势。这种差异往往被实践中的常数因素所压倒。 (你在数据结构中是否会有1e18个项目?如果我们将其设置为上限,那就等于60左右的常数因子。)