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);