从载体中删除重复项的最快方法<>
Fastest way to remove duplicates from a vector<>
正如标题所说,我脑海中有一些方法可以做到这一点,但我不知道哪种方法最快。
假设我们有一个值为的: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
从一开始就使用一套
好的,我有这4种方法,我的问题是:
1从1、2和3哪个最快
24比前3快吗
3在2将向量转换为集合后,使用集合做我需要做的事情更方便,还是应该做vals.assign( .. )
并继续使用我的向量?
问题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将击败所有其他选项。复杂度仅为O(N log N),向量的连续内存使常数因子保持在较低水平。
std::set通常会受到非连续分配的影响。访问它们不仅速度慢,而且创建它们也需要大量时间。
尽管(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;
}
}
}
}
如果需要的话,在最后调整向量的大小。这永远不会比O(N^2)更糟,因此优于插入排序或先排序后删除的方法。
如果你能接受的话,你的第四个选择可能是个主意。否则就用我20世纪60年代的算法。
我最近遇到了类似的问题,并对1、2和4以及4的unordered_set
版本进行了实验。结果表明,性能最好的是后者,4用unordered_set
代替set
。
顺便说一句,如果考虑到set
和sort
都有点过头了,这一经验发现并不太令人惊讶:它们保证了不相等元素的相对顺序。例如,输入4,3,5,2,4,3
将导致排序输出唯一值2,3,4,5
。如果您可以使用任意顺序的唯一值(即3,4,2,5
),则这是不必要的。当您使用unordered_set
时,它不保证顺序,只保证唯一性,因此它不必执行确保不同元素顺序的额外工作。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- C / CUDA中的模板方法是3个角括号(&lt;&lt;&lt;)
- 超载&LT的正确方法;操作员