从矢量<>

时间:2015-11-18 07:46:44

标签: c++ vector stl duplicates

正如标题所说,我在脑海中有一些方法可以做到,但我不知道哪个是最快的。

所以我们假设我们有一个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( .. )并继续我的矢量更加方便吗?

4 个答案:

答案 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

BTW,如果人们认为setset都有点矫枉过正,那么实证结果并不太令人惊讶:它们保证了不相等元素的相对顺序。例如,输入sort会导致唯一值4,3,5,2,4,3排序输出。如果您可以按任意顺序使用唯一值,即2,3,4,5,则不需要这样做。当您使用3,4,2,5时,它不保证订单,只保证唯一性,因此它不必执行确保不同元素顺序的额外工作。