【问题标题】:Data structure with quick insert and search具有快速插入和搜索功能的数据结构
【发布时间】:2013-11-05 16:51:44
【问题描述】:

我有一个问题想要编写代码。我有一个生成数字 0 到 n-1 的过程,我想在它生成第一个重复元素时停止它。*我正在寻找一种可以快速实现这一点的数据结构。特别是,添加一个新元素并测试一个元素是否在结构中需要很快。预期的插入数量在 sqrt(n) 左右(生日问题),或者实际上更糟一些(比如 sqrt(2n)),因为该过程略微偏向于唯一值。换句话说,它相当稀疏——处理多达 10 亿个数字时,只会使用大约 30 或 50,000 个值。

哈希集或某种自平衡二叉树似乎是正确的方法,但也许有更好的方法?对于小的 n,我认为位数组会更好,但我认为 n 大约为 10^9,这对于我来说太大了,不实用。

* 实际上,它不需要立即停止——如果效率更高,您可以在块中生成元素并不时检查。


注意:这最初是在 math.se 上发布的,但他们建议我在此处重新发布。它不是研究级别的,因此不适合 cstheory.se。

【问题讨论】:

  • 哈希集是要走的路,只需使用模运算符并将它们放在一组合理的大小中。

标签: data-structures computer-science computer-science-theory


【解决方案1】:

哈希表确实是要走的路。一个经过适当优化的整数哈希集几乎可以(不能完全忽略负载因子)与普通数组一样节省空间,同时保持您期望的高性能。将键用作哈希值,不要将哈希值存储两次,保持表大小为 2 的幂(因此使用位掩码而不是模数)。如果你使用开放寻址,需要删除,可以从key中借一点来标记tombstones。

对于 50k 项,这些优化可能不值得编写自己的哈希表(尽管它本身就是一个有趣的练习!)。如果您可以使用您选择的语言中的现有哈希集,请使用它。否则,请参阅Fast and Compact Hash Tables for Integer Keys 以了解各种方法的调查和基准,并考虑 Robin Hood Hashing,它非常容易实现,具有不错的最坏情况保证,虽然在上述论文中没有提到,但根据我的经验,它的速度相当快(主要是因为它是对线性探测的简单修改并继承了它的优点)。我的 C 实现——不幸的是还没有公开——甚至还没有 250 行代码,包括空白和 cmets,这些都不是棘手的(与其他哈希表相比)。这是没有任何微优化的。

【讨论】:

  • 谢谢。你能推荐一个用 C 语言实现的哈希表,还是建议我自己动手? (顺便说一句,我喜欢这篇文章,但是 Robin Hood 散列在这里非常不合适 - 查找缺失元素的所有操作都发生在最后一次插入之外。)
  • @Charles 我不推荐 C 哈希表:我听说过一些,但从未认真使用过其中任何一个。我认为自己滚动是一个合理的选择,但不是第一选择。我不知道你为什么认为罗宾汉散列是不合适的?正如文章所说,查找缺失元素的速度很快——与其他开放寻址方案相比。一旦探测计数大于当前正在探测的元素的探测计数,搜索就会终止 - 由于平均和最大探测计数较低,这种情况发生在几个元素之后。
  • ~6 次探测以确定元素是否存在过高。就我的目的而言,线性探测会更快(也许其他更复杂的版本会更快)。
  • @Charles ~6 是最坏情况下的数字(在良好哈希函数的假设下得出)。如果线性探测可以因为空槽而提前终止,那么罗宾汉哈希也可以——这两种方案需要相同数量的探测,或者罗宾汉哈希需要更少。通过建设,它永远不需要更多。这并不一定意味着它总体上更快,因为它需要在其他地方进行更多的簿记,但声称它需要更多的探测是错误的。
【解决方案2】:

我认为最好的数据结构是hashTable。最重要的部分是哈希函数,您可以创建自己的,也可以使用MurmurHash/CityHash 进行均匀分布。

【讨论】:

  • 他的键已经是整数了。没有理由对它们进行散列,或者如果有,任何合适的算法都将与处理可变长度字节字符串的散列非常不同。
猜你喜欢
  • 2015-11-10
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 2021-09-22
  • 1970-01-01
  • 2014-01-16
相关资源
最近更新 更多