正如标题所说,我在脑海中有一些方法可以做到,但我不知道哪个是最快的。
所以我们假设我们有一个vector<int> vals
带有一些值
1
添加vals
后
sort(vals.begin(), vals.end());
auto last = unique(vals.begin(), vals.end());
vals.erase(last, vals.end());
2
添加vals
后转换为设置:
set<int> s( vals.begin(), vals.end() );
vals.assign( s.begin(), s.end() );
第3
当我添加vals
时,我会检查它是否已经在我的向量中:
if( find(vals.begin(), vals.end(), myVal)!=vals.end() )
// add my val
4
从头开始使用一套
好的,我有这四种方法,我的问题是:
1从 1,2 和 3 这是最快的?
2 4 比前3个快吗?
3在将矢量转换为设置后,在 2 时,使用该集合做我需要做的事情或者我应该执行vals.assign( .. )
并继续我的矢量更加方便吗?
答案 0 :(得分:4)
问题1 :1和2都是O(n log n),3是O(n ^ 2)。在1到2之间,它取决于数据。
问题2 :4也是O(n log n),如果你有很多重复项,可以优于1和2,因为它只存储每个副本的一个副本。想象一下百万个值都是平等的。
问题3 :嗯,这实际上取决于你需要做什么。
唯一可以说不知道更多的是你的替代3号渐渐比其他的更差。
如果您使用的是C ++ 11并且不需要订购,则可以使用std::unordered_set
,这是一个哈希表,并且可以明显快于std::set
。
答案 1 :(得分:3)
选项1将击败所有其他人。复杂度只是O(N log N),向量的连续记忆保持低常数因子。
std :: set通常会受到非连续分配的影响。访问它们不仅速度慢,只需创建它们也需要很长时间。
答案 2 :(得分:1)
这些方法都有其缺点,尽管(1)值得一看。
但是,看看第5个选项:请记住,您可以使用data()
函数访问向量的数据缓冲区。然后,请记住,由于向量只会变小,所以不会进行重新分配,应用您在学校学到的算法:
unduplicate(vals.data(), vals.size());
void unduplicate(int* arr, std::size_t length) /*Reference: Gang of Four, I think*/
{
int *it, *end = arr + length - 1;
for (it = arr + 1; arr < end; arr++, it = arr + 1){
while (it <= end){
if (*it == *arr){
*it = *end--;
} else {
++it;
}
}
}
}
如果需要的话,最后调整矢量大小。这永远不会比O(N ^ 2)差,所以优于插入排序或排序然后删除方法。
如果您可以采用它,那么您的第4个选项可能是个主意。描述性能。否则使用我20世纪60年代的算法。
答案 3 :(得分:0)
我最近遇到了类似的问题,并尝试了 1 , 2 和 4 ,以及{ {1}} 4 的版本。事实证明,最好的表现是后者, 4 ,unordered_set
取代unordered_set
。
set
和set
都有点矫枉过正,那么实证结果并不太令人惊讶:它们保证了不相等元素的相对顺序。例如,输入sort
会导致唯一值4,3,5,2,4,3
的排序输出。如果您可以按任意顺序使用唯一值,即2,3,4,5
,则不需要这样做。当您使用3,4,2,5
时,它不保证订单,只保证唯一性,因此它不必执行确保不同元素顺序的额外工作。