std::map 插入还是 std::map 查找?

发布于 2024-07-05 04:03:17 字数 136 浏览 12 评论 0原文

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

Assuming a map where you want to preserve existing entries. 20% of the time, the entry you are inserting is new data. Is there an advantage to doing std::map::find then std::map::insert using that returned iterator? Or is it quicker to attempt the insert and then act based on whether or not the iterator indicates the record was or was not inserted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

我只土不豪 2024-07-12 04:03:18

关于效率的任何答案都取决于 STL 的具体实现。 唯一确定的方法是对这两种方式进行基准测试。 我猜差异不太可能很大,所以根据您喜欢的风格来决定。

Any answers about efficiency will depend on the exact implementation of your STL. The only way to know for sure is to benchmark it both ways. I'd guess that the difference is unlikely to be significant, so decide based on the style you prefer.

萌梦深 2024-07-12 04:03:18

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

是的,很公平。

如果你先查找然后插入,那么当你错过时,你将执行 2 x O(log N),因为查找只会让你知道是否需要插入,而不是插入应该去的地方(lower_bound 可能会帮助你) 。 我的做法就是直接插入然后检查结果。

map[ key ] - let stl sort it out. That's communicating your intention most effectively.

Yeah, fair enough.

If you do a find and then an insert you're performing 2 x O(log N) when you get a miss as the find only lets you know if you need to insert not where the insert should go (lower_bound might help you there). Just a straight insert and then examining the result is the way that I'd go.

爱格式化 2024-07-12 04:03:18

我似乎没有足够的点来发表评论,但勾选的答案对我来说似乎很冗长 - 当你认为 insert 无论如何都会返回迭代器时,为什么要搜索 lower_bound ,当你可以只使用返回的迭代器时。 奇怪的。

I don't seem to have enough points to leave a comment, but the ticked answer seems to be long winded to me - when you consider that insert returns the iterator anyway, why go searching lower_bound, when you can just use the iterator returned. Strange.

路还长,别太狂 2024-07-12 04:03:17

我认为如果您先查找然后插入,额外的成本将是当您找不到密钥并在之后执行插入时。 这有点像按字母顺序翻阅书籍,但找不到该书,然后再次翻阅书籍以了解将其插入的位置。 这归结为您将如何处理按键以及它们是否不断变化。 现在有一些灵活性,如果你没有找到它,你可以记录,异常,做任何你想做的事......

I would think if you do a find then insert, the extra cost would be when you don't find the key and performing the insert after. It's sort of like looking through books in alphabetical order and not finding the book, then looking through the books again to see where to insert it. It boils down to how you will be handling the keys and if they are constantly changing. Now there is some flexibility in that if you don't find it, you can log, exception, do whatever you want...

自控 2024-07-12 04:03:17

如果您关心效率,您可能需要查看 hash_map

通常,地图<> 被实现为二叉树。 根据您的需要,hash_map 可能更有效。

If you are concerned about efficiency, you may want to check out hash_map<>.

Typically map<> is implemented as a binary tree. Depending on your needs, a hash_map may be more efficient.

最偏执的依靠 2024-07-12 04:03:17

两者之间的速度几乎没有任何差异,find 将返回一个迭代器,insert 执行相同的操作,并且无论如何都会搜索映射以确定条目是否已存在。

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

There will be barely any difference in speed between the 2, find will return an iterator, insert does the same and will search the map anyway to determine if the entry already exists.

So.. its down to personal preference. I always try insert and then update if necessary, but some people don't like handling the pair that is returned.

三生池水覆流年 2024-07-12 04:03:17

答案是你两者都不做。 相反,您想要执行 Effective STL 的第 24 项建议的操作 斯科特·迈耶斯

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
}

The answer is you do neither. Instead you want to do something suggested by Item 24 of Effective STL by Scott Meyers:

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
}
自找没趣 2024-07-12 04:03:17

这个问题的答案还取决于创建要存储在映射中的值类型的成本有多大:

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;
  }
}

对于诸如 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;
  }
}

为了调用“插入”,我们正在为构造我们的值类型的昂贵调用付费 - 从您在问题中所说的来看,您不会20% 的时间使用这个新值。 在上述情况下,如果无法更改映射值类型,那么首先执行“查找”来检查是否需要构造元素会更有效。

或者,可以更改映射的值类型,以使用您最喜欢的智能指针类型存储数据的句柄。 对 insert 的调用使用空指针(构造起来非常便宜),并且仅在必要时才构造新的数据类型。

The answer to this question also depends on how expensive it is to create the value type you're storing in the map:

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;
  }
}

For a value type such as an int, the above will more efficient than a find followed by an insert (in the absence of compiler optimizations). As stated above, this is because the search through the map only takes place once.

However, the call to insert requires that you already have the new "value" constructed:

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;
  }
}

In order to call 'insert' we are paying for the expensive call to construct our value type - and from what you said in the question you won't use this new value 20% of the time. In the above case, if changing the map value type is not an option then it is more efficient to first perform the 'find' to check if we need to construct the element.

Alternatively, the value type of the map can be changed to store handles to the data using your favourite smart pointer type. The call to insert uses a null pointer (very cheap to construct) and only if necessary is the new data type constructed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文