C++ std::map insert还是std::map find?

C++ std::map insert还是std::map find?,c++,optimization,stl,stdmap,C++,Optimization,Stl,Stdmap,假设要在其中保留现有条目的映射。20%的情况下,您插入的条目是新数据。使用返回的迭代器进行std::map::find然后std::map::insert是否有优势?或者尝试插入,然后根据迭代器是否指示记录已插入或未插入而采取行动会更快吗?2之间的速度几乎没有差别,find将返回迭代器,insert也会执行同样的操作,并搜索映射以确定条目是否已存在 所以。。这取决于个人喜好。我总是尝试插入,然后在必要时进行更新,但有些人不喜欢处理返回的数据对。map[key]-让stl来解决它。这是最有效地传达

假设要在其中保留现有条目的映射。20%的情况下,您插入的条目是新数据。使用返回的迭代器进行std::map::find然后std::map::insert是否有优势?或者尝试插入,然后根据迭代器是否指示记录已插入或未插入而采取行动会更快吗?

2之间的速度几乎没有差别,find将返回迭代器,insert也会执行同样的操作,并搜索映射以确定条目是否已存在


所以。。这取决于个人喜好。我总是尝试插入,然后在必要时进行更新,但有些人不喜欢处理返回的数据对。

map[key]-让stl来解决它。这是最有效地传达你的意图

是的,很公平


如果您先查找,然后再插入,则当您未命中时,您正在执行2 x O(logn),因为查找只会让您知道是否需要插入,而不是插入的位置(下限可能会帮助您)。我会直接插入并检查结果。

任何关于效率的答案都取决于STL的确切实现。唯一可以确定的方法是从两个方面对其进行基准测试。我想差异不大,所以根据您喜欢的样式来决定。

我认为如果您先查找然后插入,额外的成本将是您找不到键,然后再执行插入。这有点像按字母顺序翻阅书籍,却找不到那本书,然后再翻阅一遍,看看要把它放在哪里。它归结为你将如何处理钥匙以及钥匙是否在不断变化。现在有了一些灵活性,如果你找不到它,你可以记录,异常,做任何你想做的事…

如果你关心效率,你可能想检查一下


通常,映射实现为二叉树。根据您的需要,哈希映射可能更有效。

此问题的答案还取决于创建存储在映射中的值类型的成本:

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.first->second = v;
  }
}
typedef-std::map-MapOfInts;
typedef std::pair-IResult;
void foo(映射到its&m、int k、int v){
IResult ir=m.insert(std::make_pair(k,v));
中频(红外秒){
//插入发生(即新条目)
}
否则如果(替换条目(ir.first->first)){
红外第一->第二=v;
}
}
对于像int这样的值类型,上面的方法比先查找然后插入(在没有编译器优化的情况下)更有效。如上所述,这是因为在地图上搜索只发生一次

但是,调用insert要求您已经构造了新的“值”:

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.first->second = v;
  }
}
类大数据类型{/*…*/};
typedef std::大数据类型的映射;
typedef std::pair-IResult;
void foo(MapOfLargeDataType&m,int k){
//此呼叫比通过地图查找更昂贵:
LargeDataType const&v=VeryExpensiveCall(/*…*/);
IResult ir=m.insert(std::make_pair(k,v));
中频(红外秒){
//插入发生(即新条目)
}
否则如果(替换条目(ir.first->first)){
红外第一->第二=v;
}
}
为了调用“insert”,我们为构建我们的值类型支付了昂贵的调用费用——根据您在问题中所说的,您在20%的时间内不会使用这个新值。在上述情况下,如果更改映射值类型不是一个选项,那么首先执行“查找”检查是否需要构造元素会更有效


或者,可以更改地图的值类型,以使用您喜爱的智能指针类型存储数据句柄。对insert的调用使用空指针(构造起来非常便宜),只有在必要时才构造新的数据类型。

答案是两者都不做。相反,您希望执行以下内容的第24项所建议的操作:

typedef映射映射类型;//您的地图类型可能会有所不同,只需更改typedef即可
地图类型mymap;
//在此处添加要映射的元素
int k=4;//假设我们正在搜索等于4的键
int v=0;//假设我们希望值0与键4关联
迭代器lb=mymap.lower_-bound(k);
如果(lb!=mymap.end()&&!(mymap.key_comp()(k,lb->first)))
{
//密钥已存在
//如果愿意,请更新lb->second
}
其他的
{
//该键在地图中不存在
//把它添加到地图上
插入(lb,MapType::value_type(k,v));//使用lb作为插入的提示,
//因此,它可以避免另一次查找
}

我似乎没有足够的分数来留下评论,但是滴答的答案似乎对我来说是冗长的。当你认为INSERT无论如何都会返回迭代器时,当你可以使用返回的迭代器时,为什么要去搜索低级绑定。奇怪。

否,如果条目存在,则返回对现有条目的引用。此答案为-1。正如krisk所说,使用map[key]=value将覆盖现有条目,而不是按照问题中的要求“保留”它。您不能使用map[key]测试是否存在,因为如果key不存在,它将返回一个默认构造的对象,并将其创建为key的条目。重点是测试map是否已填充,如果不存在,则仅添加/覆盖。使用map[key]时,假设该值已经存在,并且总是存在。如果愿意的话。但是在C++标准库中没有HASHYMAP,PHB不允许代码在该外部。是建议添加到下一个标准中的哈希映射,应该在大多数STL的当前实现中可用。这确实是find的工作原理,诀窍在于它将find和insert所需的搜索结合起来。当然,使用insert然后查看第二个返回值也是如此。两个问题:1)对于ma,使用下界和使用find有什么不同
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
}