具有最快“存在”搜索的 C++ 容器(向量/数组/等)

Posted

技术标签:

【中文标题】具有最快“存在”搜索的 C++ 容器(向量/数组/等)【英文标题】:C++ Container with Fastest "Exists" Seeking (Vector/Array/etc) 【发布时间】:2014-03-20 14:50:18 【问题描述】:

我不确定在这里使用的最佳 C++ 数据容器......我正在构建一个对延迟非常敏感的应用程序(因此我需要绝对最快的实现)。

我需要一次性存储大约 300,000 个字符串(仅一次写入),然后经常检查该数据存储中是否存在某个元素(多次读取)。除了检查其中是否存在值外,我不需要对这个数据集做任何其他事情,而且我需要每秒检查数百次。如果这很重要,大多数查找将导致找不到密钥。

我考虑过使用向量或数组,但它们似乎都只是简单地扫描整个列表并一对一地检查值......这会起作用......但是因为我们正在索引字符串,所以没有任何数据容器为值构建某种树索引,因此在搜索值“apple”时,它会首先查看以“a”开头的键,然后是下一个字符“p”,以及何时它没有找到任何“ap ...”它立即返回未找到。对我来说,这似乎比每次搜索整个庞大的集合要快。我真的希望原生容器具有这种功能。

如果有帮助的话,这个项目确实已经编译了 Boost。

非常感谢!

【问题讨论】:

std::setstd::map 构建红黑树。 std::unordered_setstd::unordered_map 是哈希表。 @MichałGóral C++ 没有指定树的具体类型。 【参考方案1】:

有了 Boost,答案显然是 boost::unordered_set

它也可以作为 C++11 中标准的一部分作为 std::unordered_set<unordered_set> 中使用。

它们都建立在哈希表上,因此计算哈希后查找本身的 O(1)。

【讨论】:

请原谅我的无知,但假设unordered_set 哈希表比普通set 中的红黑树更快,以进行简单的“如果存在”查找? 这是平均 O(1) 查找,在最坏的情况下是线性的,而 std::set 总是 O(log(N)) 完美,因为我不相信有比 O(1) 更好的方法,unordered_set 是。谢谢! @Harry,并不是保证会更快,但对于大型数据集,可能会更快。如果这很重要,您应该真正为自己进行基准测试。【参考方案2】:

那个树容器叫做Trie

Here你可以找到Boost.Trie,我没用过,不知道有没有完成。

【讨论】:

这听起来很有趣,这就是我所描述的,但对于我的速度要求来说可能有点过多的开销。 Trie 应该会表现得更好,尤其是在有很多未命中的情况下。【参考方案3】:

这取决于您是否可以将数据保存在内存中,而不是用于该目的的最佳容器是 unordered_set。如果您需要检查集合中是否存在某个键,它具有 O(1) 访问时间。 Boost 提供了很好的实现,你可以在这里找到http://www.boost.org/doc/libs/1_55_0/doc/html/unordered.html。

如果由于数据太大而无法将数据保存在内存中,则可以使用不同的技巧。您可以计算每个字符串的一些小哈希(您可以找到不同的哈希函数),因此它基本上就像从 string -> int 转换一样。然后,每当您需要测试数据库中是否存在字符串时,您只需将其转换为 int (使用相同的哈希函数)并检查哈希表是否存在。如果您需要检索数据,您可以将哈希值与文件中字符串的偏移量相关联,但在您的情况下,您可以考虑仅在需要节省空间时才保留哈希值。

PS。 unordered_set 也使用了哈希函数,只是被隐藏了。

【讨论】:

以上是关于具有最快“存在”搜索的 C++ 容器(向量/数组/等)的主要内容,如果未能解决你的问题,请参考以下文章

带有浮点索引的 C++ 数组/向量

C++ 将对象向量中的元素复制到具有此元素的向量中

C++中的稀疏数组

C++容器

用 SSE 在 C++ 中将两个 32 位整数向量相乘的最快方法

C++ 字符串向量和数组的一些术语