每个人都知道(或必须知道),设计一个支持中间O(1)插入和O(1)查找的列表数据结构是不可能的。
例如,链表支持O(1)插入,但O(N)用于查找,而数组支持O(1)用于查找,但O(N)用于插入(可能是分摊的O(1)用于插入开始,结束或两者兼而有之。)
但是,假设您愿意用以下方式进行O(1)插入交易:
那么在每种情况下查找的理论界限是什么?你知道现有的数据结构吗?内存复杂性怎么样?
答案 0 :(得分:3)
基于树的数据结构,如rope或finger tree,通常可以在任意位置提供对数插入时间。权衡取决于访问时间,除了在特殊情况下,例如手指树的末端,它往往也是对数的。
Dynamic arrays可以在末尾提供分摊的常量插入,但是插入中间需要复制数组的一部分,并且正如你所提到的那样及时为O(N)。
可能实现支持分摊的常量中间插入的数据结构。如果添加到任一端,则视为动态数组。如果插入中间,请保留旧数组并在其上方添加一个新数组,其中包含列表的新“中间”,使用旧数组作为中间左侧或右侧的数据。在您第一次插入中间后,访问时间将是对数,并跟踪哪个数据层将很快变得复杂。
这可能是维基百科文章中提到的“分层”动态数组,我还没有进一步研究过。
我怀疑没有人真正使用这样的数据结构的原因是在中间插入很少是你最需要的情况,并且对数插入(使用树)对于大多数现实世界的情况来说已经足够了。 / p>
答案 1 :(得分:2)
这些仍然是未解决的问题,但我所知道的最佳界限来自Arne Andersson的Sublogarithmic searching without multiplications,它有O(sqrt(lg(n))的插入,删除和查找。然而,这需要2 ^ k额外空间,其中k是存储在数据结构中的整数中的位数,因此我们仍然使用平衡二叉树而不是Andersson的数据结构。数据结构的变体允许O(1)查找,但随后附加空间增加到n2 ^ k,其中n是数据结构中的元素的数量。随机变体不使用任何额外空间,但是sqrt(lg(n))插入/删除/查找时间变为平均空间时间而不是最差情况时间。