我正在使用Visual Studio 2010中的C ++。我有一个STL集,我在程序关闭时保存到文件。下次程序启动时,我将(已排序)数据加载回一个集合中。我正在尝试优化加载过程,我遇到了麻烦。我怀疑问题是经常重新平衡,我正在寻找一种方法来避免这种情况。
首先,我没有进行优化,使用“set-> insert(const value_type& x)”
时间: ~5.5分钟
然后我尝试使用insert()的版本,在其中传递insert()的位置提示:
iterator insert ( iterator position, const value_type& x );
粗略地说,我这样做了:
set<int> My_Set;
set<int>::iterator It;
It = My_Set.insert (0);
for (int I=1; I<1000; I++) {
It = My_Set.insert (It, I); //Remember the previous insertion's iterator
}
时间: ~5.4分钟
几乎没有任何进步!我不认为问题是从文件读取开销 - 注释掉insert()会将时间减少到2秒。我认为问题不在于复制对象的开销 - 它是一个带有int和char的Plain Old Data对象。
我能想到的唯一一点就是这套装置不断重新平衡。
1。)你同意我的猜测吗?
2。)有没有办法在我加载集合时“暂停”重新平衡,然后在结束时重新平衡一次? (或者......这会有帮助吗?)
3.。)是否有更智能的方法来加载已排序的数据,即不是简单地从最低到最高?也许交替我的插入,以便它不必经常平衡? (例如:插入1,1000,2,999,3,998 ......)
答案 0 :(得分:6)
关于我们谈论的元素数量?
我用10.000.000整数(用向量准备)做了一个简短的测试,并以三种不同的方式将它们插入到集合中。
准备输入:
std::vector<int> input;
for(int i = 0; i < 10*1000*1000; ++i) {
input.push_back(i);
}
<小时/> 逐项插入设置项:
发布:2,4秒/调试:110,8秒
std::set<int> mySet;
std::for_each(input.cbegin(), input.cend(), [&mySet] (int value) {
mySet.insert(value);
});
<小时/> 使用
insert(itBegin, itEnd)
插入到集合中:
发布:0,9秒/调试:47,5秒
std::set<int> mySet;
mySet.insert(input.cbegin(), input.cend());
// this is also possible - same execution time:
std::set<int> mySet(input.cbegin(), input.cend());
因此插入可能会大幅加速,但即使是缓慢的方式也应该远离几分钟。
<小时/> 修改强>
我同时使用调试模式进行了测试 - 哇 - 我知道调试成本的性能,但它比我想象的要多。使用50.000.000元素在调试模式下有一个错误的alloc,所以我将我的帖子更新为10.000.000元素,并显示了发布和调试版本的时间。
你可以在这里看到巨大的差异 - 使用更快的解决方案50次。
此外,快速解决方案(insert(itBegin, itEnd)
)似乎与元素数量呈线性关系(使用预先排序的数据!)。普通测试的元素数量增加了五倍,插入时间从4,6减少到0.9,大约是5倍。
答案 1 :(得分:2)
您是否尝试过范围构造函数?
#include <set>
#include <fstream>
#include <algorithm>
#include <iterator>
int main()
{
std::ifstream file("Plop");
std::set<int> myset;
std::copy(std::istream_iterator<int>(file),
std::istream_iterator<int>(),
std::inserter(myset, myset.end()));
}
用[0 - &gt;尝试了4种技术。 10,000,000个项目(按文件排序):
void t1(std::set<int>& data, std::istream& file)
{
int x;
while(file >> x) {data.insert(x); }
}
void t2(std::set<int>& data, std::istream& file)
{
int x;
while(file >> x) {data.insert(data.end(), x);}
}
void t3(std::set<int>& data, std::istream& file)
{
std::set<int>::iterator it = data.begin();
int x;
while(file >> x) {it = data.insert(it, x);}
}
void t4(std::set<int>& data, std::istream& file)
{
std::copy(std::istream_iterator<int>(file),
std::istream_iterator<int>(),
std::inserter(data, data.end()));
}
clock()中的时间平均超过3次运行(正常)和3次运行(-O4)
Plain Data
Normal -O4
========= =========
t1 Result: 21057300 6748061
t2 Result: 6580081 4752549
t3 Result: 6675929 4786003
t4 Result: 8452749 6460603
结论1:对于排序数据:
Best: data.insert(data.end(), <item>) // Hint end()
Worst: data.insert(<item>); // No Hint
结论2:优化计数。
答案 2 :(得分:1)
该集可能是重新平衡的。你真的有多少项需要5.6分钟?如果您的项目集足够大,则可能会遇到物理RAM限制和颠簸,或者只是存在非常糟糕的缓存未命中。
绝对没有办法禁用重新平衡。如果可以,那么该集合将能够打破其不变量,这将是不好的。
end
而不是之前的迭代器作为另一个数据点来使用两个参数插入?vector
而不是比较时间?random_shuffle
,然后再次尝试插入集合中,看看会发生什么。