C++ 从矢量中删除重复项的最快方法<&燃气轮机;

C++ 从矢量中删除重复项的最快方法<&燃气轮机;,c++,vector,stl,duplicates,C++,Vector,Stl,Duplicates,正如标题所说,我有一些方法可以做到这一点,但我不知道哪种最快 假设我们有一个:向量VAL,有一些值 1 在添加我的VAL之后 sort(vals.begin(), vals.end()); auto last = unique(vals.begin(), vals.end()); vals.erase(last, vals.end()); 2 添加myVAL后转换为set: set<int> s( vals.begin(), vals.end() ); vals.assign( s

正如标题所说,我有一些方法可以做到这一点,但我不知道哪种最快

假设我们有一个:
向量VAL
,有一些值

1

在添加我的
VAL
之后

sort(vals.begin(), vals.end());
auto last = unique(vals.begin(), vals.end());
vals.erase(last, vals.end());
2

添加my
VAL
后转换为set:

set<int> s( vals.begin(), vals.end() );
vals.assign( s.begin(), s.end() );
4

从一开始就使用一套

好的,我有这4种方法,我的问题是:

1从1开始,2从3从2开始,哪一个最快
24比前3个快吗

3在2将向量转换为set后,使用set做我需要做的事情或我应该做
VAL更方便。分配(…)
并继续我的向量?

这些方法都有它们的缺点,尽管(1)值得一看

但是,看看第五个选项:请记住,您可以使用
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;
            }
        }
    }
}
unduplicate(vals.data(),vals.size());
void unduplicate(int*arr,std::size\u t length)/*参考:我想是四人帮*/
{
int*it,*end=arr+length-1;
对于(it=arr+1;arr问题1:1和2都是O(n logn),3是O(n^2)。在1和2之间,这取决于数据

问题2:4也是O(n log n),如果有很多重复项,它可能比1和2好,因为它只存储每个副本的一个副本。想象一百万个值都相等

问题3:这取决于你需要做什么

唯一可以说的是,你的备选方案3比其他方案更差


如果您使用的是C++11并且不需要排序,那么您可以使用
std::unordered_set
,这是一个哈希表,可以大大快于
std::set
,选项1将击败所有其他选项。复杂性仅为O(N log N),并且向量的连续内存保持恒定因子较低


std::set通常会受到非连续分配的影响。访问这些分配不仅速度慢,而且创建它们也需要花费大量时间。

最近我遇到了类似的问题,并尝试了124,以及
无序的4版本。结果表明,最好的性能是后者,4,用
无序集
代替


顺便说一句,如果人们认为
set
sort
都有点过分:它们保证了不相等元素的相对顺序。例如,输入
4,3,5,2,4,3
将导致排序的输出唯一值
2,3,4,5
,这是不必要的可以使用任意顺序的唯一值,即
3,4,2,5
。当使用
unordered\u set
时,它不能保证顺序,只能保证唯一性,因此它不必执行额外的工作来确保不同元素的顺序。

好的,你测量了吗?不,我想有人可能知道。好的@deepmax,您回答了第二个问题,那么1和3呢?如果值足够小,位图是一个非常快速的解决方案。我相信OP有标志
c++
vector
stl
,因此访问内部缓冲区可能不合适。但是如果您访问内部缓冲区,我个人不会使用
c++
,这会更好
vector
stl
我会吗?因为C++03标准保证了
vector
数据是连续的,只要您知道自己在做什么,访问内部缓冲区没有问题。我已经断言不会发生重新分配。如果性能很重要(如本例所示),访问数据缓冲区是允许的。我同意KiaMorot的观点,这里似乎没有理由使用指针。事实上,
it
这个名称已经暗示了迭代器。事实上,该算法只使用双向访问。顺便说一句,这也解释了为什么它如此低效。
std::sort
后跟
std::unique
O(N logn)不是O(N*N)。当然,我采取相反的立场。也许这是因为我在日常工作中使用了C风格的算法,所以我习惯了“连接”用C++标准库容器。我总是回避从头开始重新编写一个算法。这一切都是用“<代码> STD::设置< /代码>如果可能的话,是在这个例子中的方式。”Bathsheba:有点讽刺,“避免从头开始重新编码算法”。然后再回顾一个比现有C++标准库算法差的算法。在复习时,我喜欢这个答案,加上一个。虽然我需要学习<代码> STD::唯一的< /代码>如果你不同意我的话,我不会亲自去做。另外,当您的元素是
int
:)时,这些节点在内存方面也相对昂贵
无序集
是一个非常好的建议,C++11之前的版本可以在
boost
库中找到,并且通常作为编译器扩展。输入中相同值的重复次数越多,您从中得到的好处就越多你现在有足够的业力;-)。这是一个很好的答案,尤其是最后一点。加上一点。
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;
            }
        }
    }
}