std :: map要超过排序的std :: vector>集合必须有多大?
我有一个系统,我需要几千个关联容器,std::map
似乎在CPU缓存方面带来了很多开销。我听说过某些地方对于小型集合std :: vector可以更快 - 但我想知道那条线在哪里....
Billy3
答案 0 :(得分:9)
这不是一个大小问题,而是用法问题。
当使用模式是您读取数据时,排序后的矢量效果很好,然后您在数据中进行查找。
当使用模式涉及或多或少任意混合修改数据(添加或删除项目)和对数据进行查询时,地图效果很好。
原因很简单:地图在单个查找上的开销较高(感谢使用链接节点而不是单片存储块)。然而,维持顺序的插入或删除具有仅O(lg N)的复杂度。保持向量中的顺序的插入或删除具有O(N)的复杂度。
当然,各种混合结构也有助于考虑。例如,即使数据是动态更新的,您通常也会从大量数据开始,并且一次只进行相对较少的更改。在这种情况下,您可以将数据加载到内存中,形成一个已排序的向量,并将(少量)添加的对象保存在单独的向量中。由于第二个向量通常非常小,所以您根本不需要对它进行排序。当/如果它变得太大,你将它排序并将其与主数据集合并。
Edit2 :(响应有问题的编辑)。如果你说的是5件或更少,你可能最好忽略上述所有。只需保留未排序的数据,然后进行线性搜索。对于这个小的集合,线性搜索和二分搜索之间实际上几乎没有区别。对于线性搜索,您希望平均扫描一半项目,进行~2.5次比较。对于二进制搜索,你说的是log 2 N,(如果我的数学在早上的这个时间工作)可以达到~2.3 - 关注或注意的差异太小(实际上,二进制搜索有足够的开销,它可能非常很容易变慢。)
答案 1 :(得分:1)
如果你说“outspace”意味着消耗更多的空间(也就是内存),那么矢量总是更有效率(底层实现是一个没有其他数据的连续内存数组,其中map是树,所以每个数据意味着使用更多空间)。然而,这取决于向量为未来插入预留了多少空间。
当它是关于时间(而不是空间)时,矢量也将始终更有效(进行二分法搜索)。但是对于添加新元素(或删除它们)来说,极其不好。
所以:没有简单的答案!查看复杂性,考虑一下你将要做的用途。 http://www.cplusplus.com/reference/stl/
答案 2 :(得分:1)
std::map
的主要问题是缓存问题,正如您所指出的那样。
已排序的向量是一种众所周知的方法:Loki::AssocVector
。
对于非常小的数据集,AssocVector
应该粉碎地图,尽管插入过程中涉及的副本仅仅是因为缓存局部性。 AssocVector
也将优于地图以实现只读使用。二进制搜索在那里更有效(更少的指针)。
对于所有其他用途,您需要进行个人资料...
然而,您可能希望考虑使用混合替代方法:使用映射的Allocator
参数来限制分配项目的内存区域,从而最大限度地减少位置引用问题(缓存未命中的根源) )。
您可能还会考虑范式转换:您需要分类项目还是快速查找?
在C ++中,用于快速查找的唯一符合STL的容器已经使用Sorted Associative Containers多年来实现。然而,即将推出的C ++ 0x具有期待已久的unordered_map
功能,可以执行上述所有解决方案!
答案 3 :(得分:0)
编辑:看到你在谈论5件或更少的东西:
排序涉及交换项目。插入std :: map时,只涉及指针交换。矢量或地图是否更快取决于交换两个元素的速度。
我建议你介绍一下你的申请表。
如果你想要一个简单而通用的规则,那么你运气不好 - 你至少需要考虑以下因素:
<强>时间强>
<强>内存强>
过去一定大小的容器和元素,分配和树指针的开销将超过向量末尾未使用内存的成本 - 但到目前为止最简单的方法是通过测量来确定是否以及何时发生这种情况。
答案 4 :(得分:0)
它必须是百万项。甚至那里......
我更想到内存使用和内存访问。在数十万之下,随心所欲,没有明显的区别。这些天CPU非常快,瓶颈就是内存延迟。
但即使有数百万件物品,如果你的地图&lt;&gt;已经通过以随机顺序插入元素来构建。当您想要遍历地图时(按排序顺序),您最终会在内存中随机跳转,从而停止CPU以使内存可用,从而导致性能不佳。
另一方面,如果你的数百万项都在一个向量中,那么利用CPU内存访问预测来遍历它真的很快。
正如其他人所写,这取决于您的使用情况。
编辑:如果它们只包含5个项目,我会更多地质疑组织数千个关联容器的方式而不是容器本身。