仅使用几乎相等的标准(无排序)从容器中删除重复项的最有效方法是什么
What is the most efficient way of removing duplicates from a container only using almost equality criteria (no sort)
当我无法定义operator<
时,例如当我只能定义模糊比较函数时,我如何从未排序的容器(主要是向量)中删除重复项。
这个使用排序的答案不起作用,因为我无法定义用于排序数据的函数。
template <typename T>
void removeDuplicatesComparable(T& cont){
for(auto iter=cont.begin();iter!=cont.end();++iter){
cont.erase(std::remove(boost::next(iter),cont.end(),*iter),cont.end());
}
}
这是O(n²),在缓存命中方面应该非常本地化。有没有更快或者至少更整洁的解决方案?
编辑:关于为什么我不能使用集合。我做几何比较。一个例子可能是这样的,但我也有其他不同于多边形的实体。
bool match(SegPoly const& left,SegPoly const& right,double epsilon){
double const cLengthCompare = 0.1; //just an example
if(!isZero(left.getLength()- right.getLength(), cLengthCompare)) return false;
double const interArea =areaOfPolygon(left.intersected(right)); //this is a geometric intersection
if(!isZero(interArea-right.getArea(),epsilon)) return false;
else return true;
}
因此,对于这样的比较,我不知道如何制定排序或整洁的哈希函数。
首先,不要一次移除一个元素。
接下来,使用哈希表(或类似结构)来检测重复项。
如果不需要保持顺序,那么将所有元素复制到一个哈希集中(这会破坏重复项),然后使用哈希集中剩下的值重新创建向量。
如果您需要保留订单,那么:
- 将读和写迭代器设置到向量的开头
- 开始移动读取迭代器,根据哈希集或八叉树或其他可以快速查找附近元素的东西来检查元素
- 对于与hashset/octtree中的一个元素冲突的每个元素,只推进读取迭代器
- 对于不冲突的元素,从读迭代器移动到写迭代器,复制到hashset/octtree,然后两者都前进
- 当读迭代器到达末尾时,调用
erase
来截断写迭代器位置的向量
八叉树的关键优势在于,虽然它不会让你立即确定是否有足够接近的东西可以成为"重复",但它允许你只针对近邻进行测试,不包括大部分数据集。因此,根据空间分布,您的算法可能是O(N lg N)
,甚至是O(N lg lg N)
。
同样,如果你不在乎排序,你实际上可以把幸存者移到hashset/octtree中,最后把他们移回向量中(紧凑地)。
如果您不想重写代码以防止重复项从一开始就被放置在向量中,您可以这样做:
std::vector<Type> myVector;
// fill in the vector's data
std::unordered_set<Type> mySet(myVector.begin(), myVector.end());
myVector.assign(mySet.begin(), mySet.end());
其将是O(2*n)=O(n)。
std::set
(或std::unordered_set
,它使用哈希而不是比较)不允许重复,因此它将在初始化集合时消除它们。然后使用未重复的数据重新指定矢量。
由于您坚持不能创建哈希,另一种选择是创建一个临时向量:
std::vector<Type> vec1;
// fill vec1 with your data
std::vector<Type> vec2;
vec2.reserve(vec1.size()); // vec1.size() will be the maximum possible size for vec2
std::for_each(vec1.begin(), vec1.end(), [&](const Type& t)
{
bool is_unique = true;
for (std::vector<Type>::iterator it = vec2.begin(); it != vec2.end(); ++it)
{
if (!YourCustomEqualityFunction(s, t))
{
is_unique = false;
break;
}
}
if (is_unique)
{
vec2.push_back(t);
}
});
vec1.swap(vec2);
如果副本是一个问题,请切换到指针向量,这样可以减少内存的重新分配:
std::vector<std::shared_ptr<Type>> vec1;
// fill vec1 with your data
std::vector<std::shared_ptr<Type>> vec2;
vec2.reserve(vec1.size()); // vec1.size() will be the maximum possible size for vec2
std::for_each(vec1.begin(), vec1.end(), [&](const std::shared_ptr<Type>& t)
{
bool is_unique = true;
for (std::vector<Type>::iterator it = vec2.begin(); it != vec2.end(); ++it)
{
if (!YourCustomEqualityFunction(*s, *t))
{
is_unique = false;
break;
}
}
if (is_unique)
{
vec2.push_back(t);
}
});
vec1.swap(vec2);
相关文章:
- 检测win32服务创建和删除的最佳方法
- 尝试了解在导入的静态方法上使用删除方法时的错误
- 一种从内存中删除 UTF 字节的方法?
- 从数组中删除非唯一值、保持顺序和不使用向量的最佳方法?
- 在析构函数中删除单链表的正确方法是什么?
- 处理从列表中删除指向对象的指针的"healthy"方法是什么?
- 删除类成员的动态分配内存的最佳方法是什么
- 从浮点数中删除小数部分但保留类型的有效方法
- 如果方法在类中定义,则阻止编译器删除方法
- 删除复制构造函数的 Intel 13.1.2 中不良C++行为的解决方法
- 通过C++中的删除方法自行删除对象
- 是从我的圆形链接列表中删除方法的定义良好
- 数组放置 新结合_aligned_malloc,正确的删除方法是什么?
- 不能只删除方法的常量重载?
- C++AVLtree删除方法
- 矢量与来自 STL 的列表 - 删除方法
- 带有已删除方法的C++类是否可以简单地复制
- C++ 哈希表使用链接、删除方法
- 成功启用 -fno-finite-math-only on NaN 删除方法
- 二叉搜索树删除方法