我有一个函数,它有一个无序集作为参数。由于我使用的是openmp,我将这个无序集转换为vector。我使用std :: copy进行此转换。
//pseudo code
func( std::unorderedset s1)
begin
vector v1;
std::copy(s1.begin,s2.end,std::back_inserter(v1.end());
#openmp scope
for( i = 0 ; i < v1.size(); i++ )
{
//accessing v1(i)
}
end
但是我觉得std :: copy是一项代价高昂的操作。所以我认为,如果我创建一个类变量向量并且我继续填充这个向量,当我更新我的集合时,我可以完全避免这个std :: copy操作。由于向量的push_back操作的时间复杂度是分摊的O(1)。你有什么建议?
答案 0 :(得分:6)
std::back_insert_iterator
来电std::vector::push_back
,因此您的提案无法改进。
重要的是,您知道v1
预先具有的尺寸,因此请使用该信息并使std::vector
仅将其存储分配一次以避免在std::push_back
时执行重新分配v1.size() == v1.capacity()
。
这样做:
std::vector<T> v1;
v1.reserve(s1.size());
std::copy(s1.begin(), s2.end(), std::back_inserter(v1));
或者这个:
std::vector<T> v1(s1.size());
std::copy(s1.begin(), s2.end(), v1.begin());
或者,正如@CoryKramer所建议的,从范围中惯用地构建v1
:
std::vector<T> v1(s1.begin(), s1.end());
<强>更新强>
所有三个版本都执行s1.size()
T
份的副本。但是,当使用10^7
T = int
元素在GCC上进行衡量时,它显示std::vector::reserve
是最快的方法(由于std::distance
,速度是范围构造的两倍具有线性复杂度的ForwardIterator与具有常数的std::unordered_set::size
相比。当处理较少和非常大的物体时,这种差异会减小,但它仍然存在。
第二种方式比第一种方式略慢,因为初始化元素的价值。
结论:使用std::vector::reserve
。
答案 1 :(得分:2)
使用此功能可以提高性能:
func( std::unorderedset s1)
begin
vector v1;
v1.reserve(s1.size()); // HERE
std::copy(s1.begin,s2.end,std::back_inserter(v1.end());
#openmp scope
for( i = 0 ; i < v1.size(); i++ )
{
//accessing v1(i)
}
end
但是,复制对象的成本是您必须处理的问题