std :: map插入或std :: map查找?

假设您想要保存现有条目的地图。 20%的时间,你插入的条目是新的数据。 是否有利用做std :: map :: find然后std :: map :: insert使用返回的迭代器? 还是更快尝试插入,然后根据迭代器是否指示logging是否插入?

答案是你既没有。 相反,你想要做一些斯科特·迈耶斯 ( Scott Meyers)提出的Effective STL第24条提出的build议:

typedef map<int, int> MapType; // Your map type may vary, just change the typedef MapType mymap; // Add elements to map here int k = 4; // assume we're searching for keys equal to 4 int v = 0; // assume we want the value 0 associated with the key of 4 MapType::iterator lb = mymap.lower_bound(k); if(lb != mymap.end() && !(mymap.key_comp()(k, lb->first))) { // key already exists // update lb->second if you care to } else { // the key does not exist in the map // add it to the map mymap.insert(lb, MapType::value_type(k, v)); // Use lb as a hint to insert, // so it can avoid another lookup } 

这个问题的答案还取决于在地图上创build存储的值的types是多么昂贵:

 typedef std::map <int, int> MapOfInts; typedef std::pair <MapOfInts::iterator, bool> IResult; void foo (MapOfInts & m, int k, int v) { IResult ir = m.insert (std::make_pair (k, v)); if (ir.second) { // insertion took place (ie. new entry) } else if ( replaceEntry ( ir.first->first ) ) { ir.second->second = v; } } 

对于像int这样的值types,上述方法比查找后跟插入方法(在没有编译器优化的情况下)效率更高。 如上所述,这是因为通过地图的search只发生一次。

但是,插入调用要求您已经创build了新的“值”:

 class LargeDataType { /* ... */ }; typedef std::map <int, LargeDataType> MapOfLargeDataType; typedef std::pair <MapOfLargeDataType::iterator, bool> IResult; void foo (MapOfLargeDataType & m, int k) { // This call is more expensive than a find through the map: LargeDataType const & v = VeryExpensiveCall ( /* ... */ ); IResult ir = m.insert (std::make_pair (k, v)); if (ir.second) { // insertion took place (ie. new entry) } else if ( replaceEntry ( ir.first->first ) ) { ir.second->second = v; } } 

为了打电话给'插入',我们正在花费昂贵的电话来构build我们的价值types – 从你所说的问题中你不会在20%的时间内使用这个新的价值。 在上述情况下,如果更改映射值types不是一个选项,那么首先执行“查找”以检查是否需要构造该元素会更有效。

或者,可以更改地图的值types,以使用您最喜爱的智能指针types将句柄存储到数据中。 插入的调用使用一个空指针(非常便宜地构造),并且只有在必要时才是构造的新数据types。

2之间速度几乎没有什么区别,find会返回一个迭代器,insert会做同样的事情,并且会search映射来确定这个条目是否已经存在。

所以..它归结为个人喜好。 我总是尝试插入,然后根据需要更新,但有些人不喜欢处理返回的对。

我想如果你做了一个查找然后插入,额外的成本将是当你没有find钥匙和执行后插入。 这就像是按照字母顺序浏览书籍,而不是find书本,然后再次浏览书籍,看看在哪里插入它。 这归结于你将如何处理钥匙,如果他们不断变化。 现在有一些灵活性,如果你没有find它,你可以login,例外,做任何你想要的…

我迷失在最上面的答案。

查找返回map.end(),如果它没有find任何意思,如果你是添加新的东西

 iter = map.find(); if (iter == map.end()) { map.insert(..) or map[key] = value } else { // do nothing. You said you did not want to effect existing stuff. } 

是一倍慢

 map.insert 

对于任何尚未在地图中的元素,因为它将不得不search两次。 有一次,看看它是否在那里,再次find放置新事物的地方。

如果您担心效率问题,您可能需要查看hash_map <> 。

通常map <>是作为一个二叉树实现的。 根据你的需要,一个hash_map可能更有效率。

我似乎没有足够的观点留下评论,但是打勾的答案似乎很长时间对我来说太慢了 – 当你认为插入返回迭代器时,为什么要searchlower_bound,何时可以使用迭代器返回。 奇怪。

任何有关效率的答案将取决于您的STL的确切实施。 唯一可以肯定的方法就是通过两种方式进行基准testing。 我猜测这个差别不大,所以根据你喜欢的风格来决定。

map [key] – 让stl把它整理出来。 这是最有效地传达你的意图。

是的,够公平的。

如果你做了一个查找,然后插入,那么当你发现一个错误的时候,你会执行2 x O(log N),因为查找只会让你知道是否需要插入而不是插入的位置(lower_bound可能会帮助你) 。 只是一个简单的插入,然后检查结果是我会去的方式。