C++ 仅使用几乎相等的条件(无排序)从容器中删除重复项的最有效方法是什么
如何从未排序的容器(主要是向量)中删除重复项当我无法首先定义C++ 仅使用几乎相等的条件(无排序)从容器中删除重复项的最有效方法是什么,c++,algorithm,boost,stl,containers,C++,Algorithm,Boost,Stl,Containers,如何从未排序的容器(主要是向量)中删除重复项当我无法首先定义操作符时,不要一次删除一个元素 接下来,使用哈希表(或类似结构)检测重复项 如果不需要保留顺序,则将所有元素复制到哈希集中(这将销毁重复项),然后使用哈希集中留下的值重新创建向量 如果您需要保持秩序,则: 将读写迭代器设置为向量的开头 开始移动读迭代器,根据哈希集、八叉树或其他允许快速查找附近元素的内容检查元素 对于与hashset/octtree中的元素冲突的每个元素,只推进读迭代器 对于不冲突的元素,从读迭代器移动到写迭代器,复制到
操作符时,不要一次删除一个元素
接下来,使用哈希表(或类似结构)检测重复项
如果不需要保留顺序,则将所有元素复制到哈希集中(这将销毁重复项),然后使用哈希集中留下的值重新创建向量
如果您需要保持秩序,则:
将读写迭代器设置为向量的开头
开始移动读迭代器,根据哈希集、八叉树或其他允许快速查找附近元素的内容检查元素
对于与hashset/octtree中的元素冲突的每个元素,只推进读迭代器
对于不冲突的元素,从读迭代器移动到写迭代器,复制到hashset/octtree,然后将两者都推进
当读迭代器到达末尾时,调用erase
在写迭代器位置截断向量
八叉树的主要优点是,虽然它不允许您立即确定是否有足够接近的东西可以成为“重复”,但它允许您仅针对近邻进行测试,不包括大部分数据集。因此,根据空间分布,您的算法可能是O(nlgn)
甚至O(nlgn)
同样,如果您不关心排序,您实际上可以将幸存者移动到hashset/octree中,并在最后将其移回向量中(紧凑)。如果您不想重写代码以防止在向量中放置重复项,您可以这样做:
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());
如果需要复制,请切换到指针向量,这样可以减少内存重新分配:
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);
std::vec1;
//用您的数据填充vec1
std::vec2载体;
vec2.reserve(vec1.size());//vec1.size()将是vec2的最大可能大小
std::for_each(vec1.begin()、vec1.end()、[&](const std::shared_ptr&t)
{
布尔是唯一的=真;
对于(std::vector::iterator it=vec2.begin();it!=vec2.end();++it)
{
如果(!YourCustomEqualityFunction(*s,*t))
{
is_unique=false;
打破
}
}
如果(是唯一的)
{
vec2.推回(t);
}
});
vec1.掉期(vec2);
不要在第一个容器中放入副本place@EdHeal字体相信我,如果我有选择的话,我不会的。但是,在很多情况下,您还没有(例如,在我的case arcs中读取包含几乎重复元素的文件),您可以通过额外的集合(最好是hashmap)一次性完成。只需为每个元素尝试将其添加到映射。如果它已经存在,你应该在它已经被找到时删除它。。。否则它不应该出现在map中。@texasbruce:如果我们接受提问者的说法,即不可能对元素进行排序,那么就不可能将它们添加到集合中。
@Zac:请为bool操作符==(双a,双b){返回abs(a-b)<.001;}
提出一个哈希,现在为bool操作符提出一个哈希==(point2da,point2db){return(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)<.000001;}
注意这些元素是自反的和交换的,但不是传递的。“首先,不要一次删除一个元素。”你指的是vector::erase
?一次一个是什么意思。只在最后执行擦除操作?@dyp:我指的是,如果元素2被删除,元素3也被删除,元素4会被移动两次。它应该被移动一次,直接移动到索引2。@Martin:这有点多,但这会有所帮助。a这就是为什么“计算机科学”被认为是理论数学的一个分支…正如我所说的,集合不是一个选项。我无法对当时的数据制定一个不合理的条件hand@Martin您可以在创建集合时更改比较操作。它是第二个模板参数。或者使用std::unordered_set
@BenVoigt:选择的公理意味着y组是有序的。所以有一组是存在的,困难在于找到它;-)@ZacHowland“我无法理解3张反对票。”群体心理效应可能是;-):“要想成为羊群中完美的一员,首先必须是一只羊。”a.E.@Martin:每次你移除其中的一个元素O(N)
,你就移动或复制它后面的O(N)
元素。这是昂贵的,而且仅仅建造幸存者的载体要便宜得多。正如我在回答中提到的,这也可以在原始向量中进行。
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());
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);