Joe的回答非常好,并且为您提供了所有重要的关键字。
您应该意识到,简洁的数据结构研究仍处于早期阶段,许多结果在很大程度上是理论上的。许多建议的数据结构实现起来都非常复杂,但是大多数复杂性是由于您需要在Universe大小和存储的元素数量上都保持渐近复杂性这一事实。如果其中任何一个相对恒定,那么许多复杂性就会消失。
如果集合是半静态的(即,插入是很少的,或者至少是低容量的),那么肯定值得考虑将易于实现的静态数据结构(Sadakane的sdarray是一个不错的选择)与更新结合使用缓存。基本上,您将更新记录在传统的数据结构(例如B树,特里,哈希表)中,并定期批量更新“主要”数据结构。这是信息检索中非常流行的技术,因为倒排索引具有许多搜索优势,但难以就地更新。如果是这种情况,请在评论中让我知道,我将修改此答案以为您提供一些建议。
如果插入更为频繁,则建议使用简洁的哈希。基本思想很简单,可以在这里解释,所以我会这样做。
因此,基本信息理论结果是,如果您要存储来自项目的整个宇宙中的元素,并且没有其他信息(例如,元素之间没有相关性),则需要位存储它。(除非另有说明,否则所有对数均以2为底。)您需要这么多的位。没有其他办法了。üñülog(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)<c⋅f(n)
- Ç ñ 0 Ñ > Ñ 0克(Ñ )< Ç ⋅ ˚F (Ñ )g(n)=o(f(n))意味着对于所有常数,存在一个数字,使得对于所有,。cn0n>n0g(n)<c⋅f(n)
非正式地,big-oh和little-oh都是“在一个常数因子内”,但是big-oh会为您选择常数(由算法设计者,CPU制造商,物理定律等),但是很少- 哦,您自己选择常数,它可以随您的喜欢而变小。换句话说,对于简洁的数据结构,随着问题的大小增加,相对开销会任意地变小。
当然,为了实现所需的相对开销,问题的规模可能必须变得很大,但是您不可能拥有所有的一切。
好的,在此基础上,让我们对问题进行一些说明。假设键是位整数(因此Universe的大小是),并且我们想存储个这些整数。假设我们可以神奇地安排一个完全占用且没有浪费的理想化哈希表,因此我们需要哈希槽。2 n 2 m 2 mn2n2m2m
查找操作将对位密钥进行哈希处理,对位进行屏蔽以查找哈希槽,然后检查表中的值是否与密钥匹配。到目前为止,一切都很好。米nm
这样的哈希表使用比特。我们可以做得更好吗?n2m
假设哈希函数是可逆的。然后,我们不必将整个密钥存储在每个哈希槽中。散列槽的位置为您提供了位散列值,因此,如果仅存储了剩余位,则可以从这两条信息(散列槽位置和存储在其中的值)中重建密钥。因此,您只需要位存储。米Ñhm(n - m )2 mn−m(n−m)2m
如果比,则斯特林近似值和一点点算术(证明是练习!)表明:2 n2m2n
(n−m)2m=log(2n2m)+o(log(2n2m))
因此,这种数据结构是简洁的。
但是,有两个陷阱。
第一个陷阱是构造“好的”可逆哈希函数。幸运的是,这比看起来容易得多。密码学家一直在执行可逆函数,只有他们称其为“密码”。例如,您可以基于Feistel网络上的哈希函数,这是从不可逆哈希函数构造可逆哈希函数的直接方法。
第二个发现是,由于生日悖论,真正的哈希表不是理想的。因此,您希望使用更复杂的哈希表类型,以使您更接近全占用而又不会溢出。布谷鸟哈希非常适合此操作,因为它可使您在理论上任意接近理想值,而在实践中则非常接近理想值。
布谷鸟哈希确实需要多个哈希函数,并且要求哈希槽中的值被标记为使用了哈希函数。因此,例如,如果使用四个哈希函数,则需要在每个哈希槽中另外存储两位。随着增长,这仍然很简洁,因此在实践中这不是问题,并且仍然胜过存储整个密钥。m
哦,您可能还想看看van Emde Boas树。
更多思想
如果在周围,则近似为,因此(再次)假设值之间没有进一步的相关性,您基本上将无法执行任何操作比矢量更好。您会注意到,上面的哈希解决方案确实有效地退化了这种情况(您最终在每个哈希槽中存储了一位),但是仅使用密钥作为地址而不是使用哈希函数会更便宜。ünu2 ülog(un)u
如果非常接近,则所有简洁的数据结构文献都建议您反转字典的含义。存储集中未出现的值。但是,现在您实际上必须支持删除操作,并且要保持简洁的行为,还需要能够随着更多元素的“添加”而缩小数据结构。扩展哈希表是一个很好理解的操作,但收缩它不是。ünu