我正在尝试确定是否应使用emplace_hint
将密钥插入multimap
(与常规emplace
相对)。我已经在之前的操作中(在同一个键上)计算了键的范围:
range = multimap.equal_range(key);
我应该使用range.first
,range.second
,还是没有任何内容作为插入键值对的提示?如果范围是空的怎么办?
答案 0 :(得分:10)
我应该使用range.first,range.second或者什么都不作为提示来插入键值对吗?
正如std::multimap::emplace_hint()
所述:
在容器中插入一个新元素,尽可能靠近之前的位置提示。
(重点是我的)你应该使用范围内的second
迭代器,它应该使插入更有效:
复杂性
一般来说,容器的大小是对数的,但如果在提示之前插入新元素,则摊销常数。
对于空范围,使用second
迭代器仍然可以,因为它应该总是指向大于元素或者在最后一个后面,如果不存在这样的话。
答案 1 :(得分:1)
首先,表现明智,如果您使用range.first
或range.second
,则不会有任何区别。让我们看一下equal_range
的返回值:
std::equal_range
- 返回值
std::pair
包含一对定义所需范围的迭代器, 第一个指向第一个不小于value的元素 第二个指向第一个元素大于值。如果 没有不小于value的元素,last返回为 第一要素。同样,如果没有大于值的元素, last作为第二个元素返回
这意味着 - 当获得值key
时,range.first
和range.secod
都是represent positions where
键may be correctly inserted right before. So performance wise it should not matter if you use
range.first or
range.last`。复杂性应该是"摊销常数",因为新元素是在提示之前插入的。
其次,当范围是"空"时,range.first
和range.second
都是一个接一个的,因此性能和结果是相同的,实际上就像你在没有任何提示的情况下使用emplace
一样。
请参阅以下程序演示:
int main()
{
std::multimap<std::string, std::string> m;
// some clutter:
m.emplace(std::make_pair(std::string("k"), std::string("1")));
m.emplace(std::make_pair(std::string("k"), std::string("2")));
m.emplace(std::make_pair(std::string("z"), std::string("1")));
m.emplace(std::make_pair(std::string("z"), std::string("2")));
// relevant portion of demo data: order a-c-b may be preserved
m.emplace(std::make_pair(std::string("x"), std::string("a")));
m.emplace(std::make_pair(std::string("x"), std::string("c")));
m.emplace(std::make_pair(std::string("x"), std::string("b")));
auto r = m.equal_range("x");
// will insert "x.zzzz" before "x.a":
m.emplace_hint(r.first, std::make_pair(std::string("x"), std::string("zzzz")));
// will insert "x.0" right after "x.b":
m.emplace_hint(r.second, std::make_pair(std::string("x"), std::string("0")));
auto rEmpty = m.equal_range("e");
// "empty" range, normal lookup:
m.emplace_hint(rEmpty.first, std::make_pair(std::string("e"), std::string("b")));
m.emplace_hint(rEmpty.second, std::make_pair(std::string("e"), std::string("a")));
auto rWrong = m.equal_range("k");
m.emplace_hint(rWrong.first, std::make_pair(std::string("z"), std::string("a")));
for (const auto &p : m) {
std::cout << p.first << " => " << p.second << '\n';
}
}
输出:
e => b
e => a
k => 1
k => 2
x => zzzz
x => a
x => c
x => b
x => 0
z => a
z => 1
z => 2
简而言之:如果预先计算出range
有效key
,则在插入key
时使用它。无论如何它会有所帮助。
编辑:
关于是否&#34;无效&#34;提示可能会导致插入一个不会反映插入顺序的位置&#34;对于具有相同键的值。这可以从一般的多图表语句得出结论&#34;其键比较等效的键值对的顺序是插入的顺序,并且不会改变。 (自C ++ 11起)&#34;。
我没有在任何规范性文件中找到对一种或另一种观点的支持。我刚刚在cplusplus multimap / emplace_hint文档中找到以下语句:
emplate <class... Args> iterator emplace_hint (const_iterator position, Args&&... args);
位置提示可以插入元素的位置。如果位置指向,则该函数优化其插入时间 将跟随插入元素的元素(如果是,则为结尾) 将是最后一次)。请注意,这不会强制新元素 位于multimap容器中的那个位置(a。中的元素) multimap始终遵循特定的顺序)。 const_iterator是一个成员 type,定义为指向的双向迭代器类型 元件。
我知道这不是一个规范性参考,但至少我的Apple LLVM 8.0编译器遵循这个定义(参见上面的演示):
如果一个元素插入一个&#34;错误的&#34;提示,即一个指向甚至在插入一对的位置之前,算法识别并选择一个有效位置(参见插入&#34; z&#34; =&gt;&#34; a&#34;其中一个提示指向&#34; x&#34; -element)。
如果我们使用键的范围&#34; x&#34;并使用range.first
,将第一个x
之前的位置解释为有效位置。
所以:我认为m.emplace_hint(r.first,...
的行为方式是算法立即选择一个有效的位置,to a position close to hint
否决了一般语句&#34;键值对的顺序密钥比较等效是插入的顺序,不会改变。 (自C ++ 11起)&#34;。