寻找具有较小内存占用的固定实现


9

我正在寻找设置数据类型的实现。也就是说,我们必须

  • 维持一个动态子集(的大小从宇宙)U = \ {0,1,2,3,\点中,u - 1 \}大小的üÑ Ù = { 0 1 2 3 ... ù - 1 } üSnU={0,1,2,3,,u1}u
  • 操作insert(x)(将元素添加xS)和find(x)(检查元素是否xS的成员S)。

我不在乎其他操作。对于定向,在我正在使用的应用程序中,我们有u1010

我知道在O(1)时间内同时提供这两种操作的实现O(1),所以我主要担心数据结构的大小。我希望有数十亿个条目,但希望避免交换。

如果有必要,我愿意牺牲运行时间。我可以接受O(\ log n)的摊销运行时间O(logn);不允许使用预期的运行时或ω(logn)中的运行时。

我的一个想法是,如果S可以表示为范围的并集[xmin, xmax],那么我们将能够以一些性能下降的代价节省存储空间。同样,其他一些数据模式也是可能的,例如[0, 2, 4, 6]

您能否指出我可以执行类似操作的数据结构?



元素个数如何进入图片?即,如果插入一个元素并且已经有什么?ñnn
vonbrand 2014年

@vonbrand- n集S的大小。它可以随着每个增大insert,或者如果元素x已经在集中,则可以保持不变。
HEKTO 2014年

3
您能否接受误报的可能性很小?如果是这样,则布隆过滤器可能是理想的:en.wikipedia.org/wiki/Bloom_filter

1
@AlekseyYakovlev,布隆过滤器的误报率与Universe的大小无关(仅与哈希函数的数量,数据结构的大小和项的数量)有关,但是如果确实为接近(说为小恒),你将很难做得比一个简单的位向量我认为,只有总比特的空间。Ñ Ñ Ù Ù = Ñ Ç Ç Ç Ñkmnnuu=ncccn
2014年

Answers:


8

Joe的回答非常好,并且为您提供了所有重要的关键字。

您应该意识到,简洁的数据结构研究仍处于早期阶段,许多结果在很大程度上是理论上的。许多建议的数据结构实现起来都非常复杂,但是大多数复杂性是由于您需要在Universe大小和存储的元素数量上都保持渐近复杂性这一事实。如果其中任何一个相对恒定,那么许多复杂性就会消失。

如果集合是半静态的(即,插入是很少的,或者至少是低容量的),那么肯定值得考虑将易于实现的静态数据结构(Sadakane的sdarray是一个不错的选择)与更新结合使用缓存。基本上,您将更新记录在传统的数据结构(例如B树,特里,哈希表)中,并定期批量更新“主要”数据结构。这是信息检索中非常流行的技术,因为倒排索引具有许多搜索优势,但难以就地更新。如果是这种情况,请在评论中让我知道,我将修改此答案以为您提供一些建议。

如果插入更为频繁,则建议使用简洁的哈希。基本思想很简单,可以在这里解释,所以我会这样做。

因此,基本信息理论结果是,如果您要存储来自项目的整个宇宙中的元素,并且没有其他信息(例如,元素之间没有相关性),则需要位存储它。(除非另有说明,否则所有对数均以2为底。)您需要这么多的位。没有其他办法了。ünulog(un)+O(1)

现在一些术语:

  • 如果您有一个可以存储数据并支持空间的数据结构的数据结构,则我们将其称为隐式数据结构。log(un)+O(1)
  • 如果您有一个可以存储数据并支持个空间位,我们称之为紧凑数据结构。注意,实际上这意味着相对开销(相对于理论最小值)在一个常数之内。它可能是5%的开销,10%的开销或10倍的开销。log(un)+O(log(un))=(1+O(1))log(un)
  • 如果您有一个可以存储数据并支持个空格,我们称其为简洁的数据结构。log(un)+o(log(un))=(1+o(1))log(un)

简洁和紧凑之间的区别是小哦和大哦之间的区别。暂时忽略绝对值...

  • Ç ñ 0 Ñ > Ñ 0Ñ < Ç ˚F Ñ g(n)=O(f(n))意味着存在一个常数和一个数,使得对于所有,。cn0n>n0g(n)<cf(n)
  • Ç ñ 0 Ñ > Ñ 0Ñ < Ç ˚F Ñ g(n)=o(f(n))意味着对于所有常数,存在一个数字,使得对于所有,。cn0n>n0g(n)<cf(n)

非正式地,big-oh和little-oh都是“在一个常数因子内”,但是big-oh会为您选择常数(由算法设计者,CPU制造商,物理定律等),但是很少- 哦,您自己选择常数,它可以随您的喜欢而变小。换句话说,对于简洁的数据结构,随着问题的大小增加,相对开销会任意地变小。

当然,为了实现所需的相对开销,问题的规模可能必须变得很大,但是您不可能拥有所有的一切。

好的,在此基础上,让我们对问题进行一些说明。假设键是位整数(因此Universe的大小是),并且我们想存储个这些整数。假设我们可以神奇地安排一个完全占用且没有浪费的理想化哈希表,因此我们需要哈希槽。2 n 2 m 2 mn2n2m2m

查找操作将对位密钥进行哈希处理,对位进行屏蔽以查找哈希槽,然后检查表中的值是否与密钥匹配。到目前为止,一切都很好。nm

这样的哈希表使用比特。我们可以做得更好吗?n2m

假设哈希函数是可逆的。然后,我们不必将整个密钥存储在每个哈希槽中。散列槽的位置为您提供了位散列值,因此,如果仅存储了剩余位,则可以从这两条信息(散列槽位置和存储在其中的值)中重建密钥。因此,您只需要位存储。Ñhmn - m 2 mnm(nm)2m

如果比,则斯特林近似值和一点点算术(证明是练习!)表明:2 n2m2n

(nm)2m=log(2n2m)+o(log(2n2m))

因此,这种数据结构是简洁的。

但是,有两个陷阱。

第一个陷阱是构造“好的”可逆哈希函数。幸运的是,这比看起来容易得多。密码学家一直在执行可逆函数,只有他们称其为“密码”。例如,您可以基于Feistel网络上的哈希函数,这是从不可逆哈希函数构造可逆哈希函数的直接方法。

第二个发现是,由于生日悖论,真正的哈希表不是理想的。因此,您希望使用更复杂的哈希表类型,以使您更接近全占用而又不会溢出。布谷鸟哈希非常适合此操作,因为它可使您在理论上任意接近理想值,而在实践中则非常接近理想值。

布谷鸟哈希确实需要多个哈希函数,并且要求哈希槽中的值被标记为使用了哈希函数。因此,例如,如果使用四个哈希函数,则需要在每个哈希槽中另外存储两位。随着增长,这仍然很简洁,因此在实践中这不是问题,并且仍然胜过存储整个密钥。m

哦,您可能还想看看van Emde Boas树。

更多思想

如果在周围,则近似为,因此(再次)假设值之间没有进一步的相关性,您基本上将无法执行任何操作比矢量更好。您会注意到,上面的哈希解决方案确实有效地退化了这种情况(您最终在每个哈希槽中存储了一位),但是仅使用密钥作为地址而不是使用哈希函数会更便宜。ünu2 ülog(un)u

如果非常接近,则所有简洁的数据结构文献都建议您反转字典的含义。存储集中出现的值。但是,现在您实际上必须支持删除操作,并且要保持简洁的行为,还需要能够随着更多元素的“添加”而缩小数据结构。扩展哈希表是一个很好理解的操作,但收缩它不是。ünu


嗨,至于您回答的第二段-我希望每次对的调用insert都将伴随有find具有相同论点的调用。因此,如果find返回true,那么我们只需跳过insert。因此,find呼叫频率大于呼叫频率insert,当n接近时uinsert呼叫也变得非常罕见。
HEKTO 2014年

但是您希望最终接近?ñun
别名2014年

在现实世界中,n一直增长到到达u,但是我们无法预测它是否会发生。该数据结构应适用于任何情况n <= u
HEKTO 2014年

对。可以公平地说,我们不知道一个简洁的数据结构(在上述意义上),并且无法在的整个范围内实现这一目标。我认为当,您将需要一个稀疏的数据结构,然后当在附近时,切换到一个密集的数据结构(例如,位向量),然后是一个反向的稀疏数据结构。当接近时感觉。nuÑ ùn<un nu2nu
别名2014年

5

听起来好像您想要一个简洁的数据结构来解决动态成员资格问题

回想一下,简洁的数据结构是空间要求“接近”信息理论下限的结构,但与压缩的数据结构不同,它仍然允许有效的查询。

会员的问题到底是什么,你在你的问题描述:

保持一个子集(的大小从宇宙)大小的与操作:Ñ Ù = { 0 1 2 3 ... ù - 1 } üSnU={0,1,2,3,,u1}u

  • find(x)(检查element是否x为的成员)。S
  • insert(x)(将元素添加x到)S
  • delete(x)x从删除一个元素)S

如果仅find支持该操作,则这是静态成员资格问题。如果支持一个insertdelete两个,但不同时支持两个,则将其称为Semi-dynamic,如果同时支持所有三个操作,则将其称为动态成员关系问题。

从技术上讲,我认为您仅要求一个用于半动态成员资格问题的数据结构,但我不知道有任何数据结构可以利用此约束并满足您的其他要求。但是,我有以下参考资料:

恒定时间和几乎最小空间中的成员资格一文的定理5.1中,Brodnik和Munro给出以下结果:

存在一种需要位的数据结构,该数据结构支持在恒定时间内进行搜索以及在恒定预期摊销时间内进行插入和删除。O(B)

其中是信息理论所需的最小位数。B=log(un)

基本思想是将它们递归地将宇宙分成精心选择的大小范围,因此听起来甚至听起来像是这些技术都符合您的想法。

但是,如果您正在寻找可以实际实现的功能,那么我不知道这是否是您的最佳选择。我只是略读了这篇论文,试图解释细节超出了此答案的范围。他们根据和的相对大小使用不同的策略来参数化其解决方案。数据结构的动态版本仅在本文中进行了概述。ñun


1
Brodnik&Munro论文摘要未提及插入物。但是他们的结果是我们可以期待的,对吧?如果为n = u/2,则所需空间为最大。
HEKTO 2014年

@AlekseyYakovlev他们并没有在抽象中真正提到动态案例,但是在我的答案中引用了处理动态案例的定理(来自第5节)。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.