在 c++ 中加快 map<string,int> .find() 的最快方法。键按字母顺序排列的位置

Posted

技术标签:

【中文标题】在 c++ 中加快 map<string,int> .find() 的最快方法。键按字母顺序排列的位置【英文标题】:Fastest way to speed up map<string,int> .find() in c++ . Where the keys are in alphabetical order 【发布时间】:2012-02-16 17:40:10 【问题描述】:

我有一张大约有 100,000 对的地图。考虑到键是按字母顺序排列的,有什么方法可以在使用 find() 时加快搜索速度。另外我应该怎么做。我知道您可以在创建地图时指定一个新的比较器。但这会加速 find() 函数吗?

提前致谢。

[已解决] 感谢一群人,我决定使用矢量并使用下限和上限来“剪断”一些搜索。

我也是新手,有什么方法可以将此问题标记为已回答,或选择最佳答案?

【问题讨论】:

如果您的编译器支持它,请尝试使用std::unordered_map P.S.按字母顺序排列键无关紧要,map 无论如何都会将它们重新排列为字母顺序。 @MarkRansom:只是因为我不喜欢:这取决于比较者:D 要将问题标记为已回答,您可以选择一个最佳答案,并在答案左侧的投票按钮下方打勾。 【参考方案1】:

一个不同的比较器只有在它设法更快地进行比较时才会加快查找速度(这对于字符串来说通常是相当困难的)。

如果您基本上是按顺序插入所有数据,然后进行搜索,那么使用std::vectorstd::lower_boundstd::upper_bound 可能会更快。

如果您并不真正关心排序,只想尽快找到数据,您可能会发现std::unordered_map 更适合您。

编辑:仅作记录:您“可能找到”或“可能找到”这些东西的方式通常是通过分析。根据情况,即使在简单的测试中也很明显,它可能会足够快,所以分析并不是真正必要的,但如果有(很多)疑问,或者你想量化效果,分析器可能是正确的方法去做。

【讨论】:

关于已排序的std::vector&lt;&gt;,另请参阅Boost.Container 的boost::container::flat_map&lt;&gt;,了解预先编写、预先测试的实现。 @JerryCoffin:我删除了反对票。我确实有不讨人喜欢的倾向。【参考方案2】:

std::map 已经在利用键按字母顺序排列的事实——它保证了这一点。您将无法通过更改比较器来改进它(假设它已经是一个相当有效的字符串比较)。

您是否考虑过在 C++11 之前的各种实现中使用 unordered_map(又名 hash_map?它应该能够在 O(1) 而不是 O(log(n)) 中搜索 std::map

你也可以研究一些更奇特的东西,比如 trie,但这不是标准库的一部分,所以你要么必须在其他地方找到一个,要么自己动手,所以我建议 unordered_map 是一个开始的好地方。

【讨论】:

【参考方案3】:

如果您使用std::find 来查找元素,您应该切换到使用map::find(您的问题中并没有真正说出来。)map::find 使用了这样一个事实,即地图的搜索速度要快得多.

如果这还不够好,您可以查看一个哈希容器,例如 unordered_map 而不是 map

【讨论】:

这是一个很好的观点。这个问题真的没有说清楚。使用std::find 基本上是搜索的最坏情况,无论是算法还是内存访问模式。 其实,如果你用于std::find的比较器与你用于地图排序的比较器相同,那么std::find不能专门使用成员find吗? @bames53 不,因为std::find 没有通过或不知道容器是什么。它只是进行线性搜索。 @bames53:它可能是,但不是必须的,而且我从未见过实现它,因为它是 far比听起来更难。 @MarkB 这是有道理的。虽然我认为如果迭代器提供对容器的访问(如调试迭代器用于有效性检查),则可以做到这一点。显然,依赖实现这样做是不好的,因此一开始就不值得实现,除非出于好奇。【参考方案4】:

我已经为unordered_map 投了票,但我还想提出另一点。

影响现代机器性能的因素之一是缓存使用不当。地图将在整个地方分配节点,并且不会有太多的参考位置。此外,由于它必须在节点之间存储一堆指针,因此会占用更多内存。

在最近的Going Native 2012 会议上,Bjarne Stroustroup 提供了一个interesting talk,涉及到这个话题。他比较了vectorlist 在涉及大量随机插入和删除的任务中的性能,看起来list 应该占主导地位,但由于内存大小和布局问题vector 实际上是迄今为止最快的。看看his slides,从幻灯片 43 开始。

unordered_map 让您可以直接访问元素,因此与尝试将数据粘贴到vector 中相比,这可能意味着在内存中的跳跃更少(因此性能比vector 更好)所以我的评论很简单始终牢记内存访问模式以提高性能的告诫

【讨论】:

我喜欢他在那次谈话中比较速度的图表。 局部性很好,但只适用于线性的东西。向量上的二分搜索可能比地图 我想知道 binary tree 是否会比排序数组更快? @MooingDuck 幻灯片确实有图表 :) @MooingDuck 为什么对vector 的二分搜索会比搜索map?在这两种情况下,您都会在内存中跳来跳去,直到在vector 情况下,范围已缩小到适合缓存行的位置。除非将所有map 节点分配在一起,否则map 将永远不会获得这种好处,那么只有在地图很小的情况下您才有可能受益。 vector 元素会更小,因此适合缓存的范围将包含比 map 可以容纳的更多元素。

以上是关于在 c++ 中加快 map<string,int> .find() 的最快方法。键按字母顺序排列的位置的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中使用 map 时输出顺序错误

C++中map用法详解《转》

C# 等效于 C++ map<string,double>

这是 C++ 中的有效数据结构 Map<string, string, string> 吗?

C++里怎样用map将枚举类转换到string类

如何从 C++ 到 C# 获取 map<string, int>