我听过很多人说如果容器中预期的元素数量相对较少,最好使用std::vector
代替std::map
,尽管我只使用容器进行查找而不是用于迭代。
这背后的真正原因是什么?
显然,map的查找性能不能比矢量的查找性能差(尽管它可能是纳秒/微秒),那么它是否与内存使用有关呢?
在虚拟地址空间的分段中,向量是否比映射更好/更差?
我正在使用随Visual Studio一起提供的STL库(即微软实现)与其他实现有什么不同?
答案 0 :(得分:61)
我认为您正在将map<A, B>
与vector<pair<A, B> >
进行比较。
首先,在一个非常小的向量中找到一个项目可能比在地图中的同一个东西更快,因为向量中的所有内存总是连续的(因此与计算机的缓存和此类事物一起玩得更好),在向量中找到某些东西所需的比较次数可能与地图大致相同。在非常大的容器的限制中,在地图中查找元素需要的操作更少。
地图变得比矢量快的点取决于实现,处理器,地图中的数据以及处理器缓存中的内存等细微之处。通常,地图变得更快的点将是大约5-30个元素。
另一种方法是使用哈希容器。它们通常被命名为hash_map
或unordered_map
。名为hash_map
的类不是官方标准的一部分(并且有一些变体); std::tr1::unordered_map
是。哈希映射通常比普通的查找映射更快,无论其中包含多少元素,但它是否实际更快取决于键是什么,如何散列,需要处理的值以及如何处理密钥在std :: map中进行比较。它不会像std :: map那样保持特定的顺序,但是你已经说过你并不关心它。我建议使用哈希映射,特别是如果键是整数或指针,因为这些哈希非常快。
答案 1 :(得分:27)
地图通常被实现为二叉搜索树,并且在二叉树中行走总是带来一点开销(执行比较,步行链接等)。矢量基本上只是数组。对于非常少量的数据,可能是8或12个元素,有时在数组上进行线性搜索比在二进制搜索树中进行线性搜索更快。
你可以自己运行一些时间来查看盈亏平衡点的位置 - 搜索四个元素,然后是八个,然后十六个,依此类推,找到特定STL实现的最佳位置。 / p>
映射确实往往在堆上有一堆小的分配,而向量是连续的,因此在你从前面迭代所有元素的情况下,向量的缓存命中率有时会更好一点背部。
答案 2 :(得分:22)
“默认情况下,在需要容器时使用矢量” - Bjarne Stroustrup。
否则,我发现这个小流程图非常有用:
答案 3 :(得分:4)
如果您正在进行所有插入,然后进行大量查找,则可以使用向量并在插入时对其进行排序;然后使用lower_bound进行快速查找。它可能比使用地图更快,即使是大量的项目。
答案 4 :(得分:3)
我认为你应该首先使用适合数据的容器。 std :: vector用于你在C或pre-STL C ++中使用数组的情况:你想要一个连续的内存块来存储具有快速恒定时间查找的值。 std :: map应该用于将键映射到值。这里的主要重叠是矢量与地图,其中size_t为关键。在这种情况下,有两个问题:指数是否连续?如果没有,你可能会浪费内存和矢量。第二,你想要什么样的查找时间?向量具有恒定时间查找,而std :: map通常实现为RB树,其具有O(log n)查找时间,甚至哈希映射(例如TR1 unordered_map)通常具有更差的复杂性,因为索引(或其散列)将映射到可以包含多个值的存储桶。
如果瞄准具有对的向量:您可以使用向量的元素并使用find来查找元素。但这是一个二分搜索,实际上和std :: map一样快。
无论如何,尝试以明显的方式对数据建模。过早优化通常没有多大帮助。
答案 5 :(得分:3)
另一种看待这个问题的方法是,如果我们谈论的是小容器,那么任何人都不会花很长时间来查找。除非您在非常紧密的循环中搜索此容器,否则时间上的差异可能会微不足道。
在这种情况下,我会寻找哪个容器更符合您的要求。如果您正在寻找特定值,那么map的内置find()方法将比创建for循环和迭代向量更容易(并且使用起来更简单)。
你的时间可能比这里和那里几纳秒还要多。
答案 6 :(得分:0)
基本上,地图用于查找。
但是,即使是查询,有时也可以使用std::vector
代替std::map
。
如果键值对中的元素非常少,那么即使在std::vector<std::pair<x,y>>
中也可以使用键进行迭代搜索。
这是因为散列需要时间,特别是散列字符串和映射中的其他操作,如在堆中存储数据。
如果您有更多需要查找的元素,并且想要在您拥有的元素列表中进行频繁查找,那么您只会在std :: map中看到更好的区别。