我刚刚发现std :: map.insert可以接受迭代器作为其第一个参数作为插入过程的搜索提示,例如 map.insert(hintIterator, insertElement);
。但是提示元素是否有任何位置要求?是否需要在插入位置之前或之后?顺便说一下,提示迭代器位置对插入效率有多大影响?
我刚刚发现std :: map.insert可以接受迭代器作为其第一个参数作为插入过程的搜索提示,例如 map.insert(hintIterator, insertElement);
。但是提示元素是否有任何位置要求?是否需要在插入位置之前或之后?顺便说一下,提示迭代器位置对插入效率有多大影响?
它可以是任何地方 begin()
至 end()
。如果传入与理想插入位置相对应的迭代器,则可以大大提高插入成本,以便搜索正确的位置。
来自 SGI STL 现场
复杂性保证
带提示的插入是对数的 一般,但它是摊销不变的 如果t立即插入的时间 在p之前。
要理解这是为什么,请考虑正在应用的算法。 std::map
具有按某种顺序排列的项目,并且为了找到正确的插入点,必须遍历项目,直到找到一个项目(“A”)必须在新数据之前且下一个项目(“B”)必须的位置。跟着它。事先给出这个位置,可以消除搜索。
新数据必须介于这两个项目之间,并更新它们之间的链接。至少(对于可向前迭代的容器),必须更新项目A以指向新数据,该数据随后指向B.如果包含的是反向可迭代的,则还必须更新B以指向新数据。
应该如何指定位置?人们必须知道A或B是枯萎的。正如Cubbi指出的那样,并进行了讨论 alt.comp.lang.learn.c-CPP 2003标准在暗示应该是什么上有所不同。 SGI文件表明B是需要的,而标准建议A.可能(鉴于此 std::map
有bidriectional迭代器)没关系。不过,我建议较低的项目(A)的位置是最好的,因为你总能期望能够继续搜索前进。
更新: 由于经过验证的猜测在验证之前是无用的,因此这是一个快速测试:
#include <ctime>
#include <map>
#include <iostream>
int main() {
typedef std::map<unsigned int,unsigned int> map;
const unsigned int k=100000;
const unsigned int reps=10;
// Avoid edge cases by padding either end
map srcMap;
{
for(unsigned int i=0; i!=k;++i) {
srcMap.insert(std::make_pair(i,i));
}
unsigned int l=3*k;
for(unsigned int i=2*k; i!=l;++i) {
srcMap.insert(std::make_pair(i,i));
}
}
std::cout << "Hint is always the position of the preceding value\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
map::iterator p=testMap.lower_bound(k-1);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
p=testMap.insert(p,std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start) ) << " ";
}
std::cout << std::endl;
std::cout << "Hint is always the position of the following value\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
map::iterator p=testMap.lower_bound(2*k);
unsigned int l=k-1;
std::clock_t start = std::clock();
for(unsigned int i=2*k-1; i!=l;--i) {
p=testMap.insert(p,std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start) ) << " ";
}
std::cout << std::endl;
std::cout << "Hint is always the start of the container\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
testMap.insert(testMap.begin(),std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start)) << " ";
}
std::cout << std::endl;
std::cout << "No hint\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
testMap.insert(std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start)) << " ";
}
std::cout << std::endl;
return 0;
}
在我运行MinGW GCC 4.5的小上网本上,我得到了:
提示始终是前一个值的位置
94 109 109 109 109 109 110 110 110 94
提示始终是以下值的位置
109 94 109 94 110 110 109 109 110 110
提示始终是容器的开始
188 172 172 187 172 172 235 187 172 187
没有提示
172 171 172 172 172 172 172 172 171 172
所以我要说任何一方的暗示都给出了相同的结果,并且总是好于没有任何暗示。选择一个糟糕的提示位置(例如开始)比没有提示更糟糕。
它可以是任何地方 begin()
至 end()
。如果传入与理想插入位置相对应的迭代器,则可以大大提高插入成本,以便搜索正确的位置。
来自 SGI STL 现场
复杂性保证
带提示的插入是对数的 一般,但它是摊销不变的 如果t立即插入的时间 在p之前。
要理解这是为什么,请考虑正在应用的算法。 std::map
具有按某种顺序排列的项目,并且为了找到正确的插入点,必须遍历项目,直到找到一个项目(“A”)必须在新数据之前且下一个项目(“B”)必须的位置。跟着它。事先给出这个位置,可以消除搜索。
新数据必须介于这两个项目之间,并更新它们之间的链接。至少(对于可向前迭代的容器),必须更新项目A以指向新数据,该数据随后指向B.如果包含的是反向可迭代的,则还必须更新B以指向新数据。
应该如何指定位置?人们必须知道A或B是枯萎的。正如Cubbi指出的那样,并进行了讨论 alt.comp.lang.learn.c-CPP 2003标准在暗示应该是什么上有所不同。 SGI文件表明B是需要的,而标准建议A.可能(鉴于此 std::map
有bidriectional迭代器)没关系。不过,我建议较低的项目(A)的位置是最好的,因为你总能期望能够继续搜索前进。
更新: 由于经过验证的猜测在验证之前是无用的,因此这是一个快速测试:
#include <ctime>
#include <map>
#include <iostream>
int main() {
typedef std::map<unsigned int,unsigned int> map;
const unsigned int k=100000;
const unsigned int reps=10;
// Avoid edge cases by padding either end
map srcMap;
{
for(unsigned int i=0; i!=k;++i) {
srcMap.insert(std::make_pair(i,i));
}
unsigned int l=3*k;
for(unsigned int i=2*k; i!=l;++i) {
srcMap.insert(std::make_pair(i,i));
}
}
std::cout << "Hint is always the position of the preceding value\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
map::iterator p=testMap.lower_bound(k-1);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
p=testMap.insert(p,std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start) ) << " ";
}
std::cout << std::endl;
std::cout << "Hint is always the position of the following value\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
map::iterator p=testMap.lower_bound(2*k);
unsigned int l=k-1;
std::clock_t start = std::clock();
for(unsigned int i=2*k-1; i!=l;--i) {
p=testMap.insert(p,std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start) ) << " ";
}
std::cout << std::endl;
std::cout << "Hint is always the start of the container\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
testMap.insert(testMap.begin(),std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start)) << " ";
}
std::cout << std::endl;
std::cout << "No hint\n";
for(unsigned int i=0; i!=reps;++i)
{
map testMap(srcMap);
unsigned int l=2*k;
std::clock_t start = std::clock();
for(unsigned int i=k; i!=l;++i) {
testMap.insert(std::make_pair(i,i));
}
std::clock_t end = std::clock();
std::cout << static_cast<double>((end - start)) << " ";
}
std::cout << std::endl;
return 0;
}
在我运行MinGW GCC 4.5的小上网本上,我得到了:
提示始终是前一个值的位置
94 109 109 109 109 109 110 110 110 94
提示始终是以下值的位置
109 94 109 94 110 110 109 109 110 110
提示始终是容器的开始
188 172 172 187 172 172 235 187 172 187
没有提示
172 171 172 172 172 172 172 172 171 172
所以我要说任何一方的暗示都给出了相同的结果,并且总是好于没有任何暗示。选择一个糟糕的提示位置(例如开始)比没有提示更糟糕。