以下代码来自cplusplus.com。它有两个插入标记为高效且低效。我认为有效的提示应该提示为mymap.begin() + 1
,因为*(mymap.begin() + 1)
为'z'
而z
将跟随b
。
如果位置指向的话,该函数会优化其插入时间 将跟随插入元素的元素(如果是,则为结尾) 将是最后一次)。
插入'c'
的最佳提示是*(mymap.begin() + 2)
,因为它必须通过'a'
和'b'
。
对还是错?我尝试对我提出的代码进行计时,并将其与“高效”代码进行比较。一个在这里,但我认为没有区别。可能是因为我打开了一百万个标签并播放音乐,因为这是一个简单的例子。
std::map<char,int> mymap;
// first insert function version (single parameter):
mymap.insert ( std::pair<char,int>('a',100) );
mymap.insert ( std::pair<char,int>('z',200) );
// second insert function version (with hint position):
std::map<char,int>::iterator it = mymap.begin();
mymap.insert (it, std::pair<char,int>('b',300)); // max efficiency inserting
mymap.insert (it, std::pair<char,int>('c',400)); // no max efficiency inserting
答案 0 :(得分:0)
&#34;高效&#34;版本只有在你提供一个好的提示时才有效。你的提示(.begin
)是错误的。现在,在只有两个元素的容器中,你不能非常错误,因此损坏是有限的。
答案 1 :(得分:0)
使用C ++ 11更改了提示插入语义的规范(如this answer中所示)。有关决议,请参见DR 233;有关导致该决议的部分讨论,请参见N1780。
缺陷报告和讨论文件主要是关于std::multimap
和std::multiset
,其中允许使用重复的密钥。在这种情况下,如果“提示”指的是一个键与插入的键相等的元素,则可以在提示之前或之后插入新元素,并且前C ++ 11标准不明确。 DR233使决策具有确定性,但也可以将其视为影响std::map
和std::set
的行为规范。
在原始规范中(在C + 11之前),标准简单地说“迭代器p
是指向插入应该开始搜索的位置的提示”,这对于提示是否应该是否应该是非常具体的插入点之前或之后的点。 (也没有说明在提示错误的情况下如何进行搜索,因为无论提示如何,都必须将新元素插入到正确的位置。)然而,操作的复杂性被记录为“对数一般” ,但如果在t
之后插入p
,则摊销常数。
这个复杂性规范在两个方面显然是错误的:首先,如果t
未插入,它不会坚持恒定时间插入(因为提示指向其键比较的元素)等等),但在这种情况下,任何合理的实施都难以成为恒定时间。其次,如果要在容器的开头插入新元素,则无法在插入点之前指定提示。
事实上,标准库的主要实现实际上期望提示指向插入点之后,尽管大多数也检查它是否就在之前。因此,现有的做法是在标准不需要的情况下提供摊销的恒定时间复杂度(当然,这是允许的),至少有一个广泛使用的实施无法提供所需的复杂性。
因此cplusplus.com中的代码充其量是不精确的,并且肯定无法描述提示插入的正常用例。
假设为给定键构造映射值是昂贵的。 (也许地图会记住一个昂贵的函数,并且映射值没有廉价的默认构造函数。)在这种情况下,你可能想要检查地图是否已经包含了密钥,然后才开始计算相应的值需要插入。一个天真的实现将是这样的:
if (mymap.find(key) == mymap.end())
mymap[key] = expensive_function(key);
// See Note 1 for another slightly more efficient variant
结果是,如果密钥不存在,则进行两次相同的对数搜索。当然,与expensive_function
的成本相比,不必要的搜索的额外成本可能微不足道,但是,似乎还有更好的解决方案。其中有:我们使用std::map::lower_bound
进行第一次搜索,导致唯一稍微复杂的代码:
auto where = mymap.lower_bound(key);
if (where == mymap.end() || where->first != key)
where = mymap.emplace_hint(where, key, expensive_function(key));
/* Here, 'where' points to the element with the specified key */
(我使用std::map::emplace_hint
- 自C ++ 11以来可用 - 而不是insert
部分尝试避免不必要的副本,以及避免使用{{1来混淆代码}}。)
该代码的实例很容易找到。许多人继续引用std::make_pair
以使用存储的值,添加另一个不必要的对数搜索;更好的代码是:
mymap[key]