C++ 从多个std::Vector中删除项目的最快方法

C++ 从多个std::Vector中删除项目的最快方法,c++,stdvector,C++,Stdvector,我有三个std::vectors,每个都包含不同的数据类型 我需要做的是从每个索引项中删除相同的索引项,具体取决于第一个索引项中该索引项的值 在下面的代码中,如果localMap\u points[i].m\u counter的值大于30,我将从所有三个向量中删除索引[i]处的项。(localMap_desc包含其他向量的8项,因此添加了x 8) 这种方法工作得很好,但速度很慢。有没有更快的方法 我有: for (int i = 0; i < localMap_points.size();

我有三个
std::vectors
,每个都包含不同的数据类型

我需要做的是从每个索引项中删除相同的索引项,具体取决于第一个索引项中该索引项的值

在下面的代码中,如果
localMap\u points[i].m\u counter
的值大于30,我将从所有三个向量中删除索引
[i]
处的项。(
localMap_desc
包含其他向量的8项,因此添加了
x 8

这种方法工作得很好,但速度很慢。有没有更快的方法

我有:

for (int i = 0; i < localMap_points.size(); i++)
{
    if (localMap_points[i].m_counter > 30)
    {
        localMap_kp.erase(localMap_kp.begin() + i, localMap_kp.begin() + i + 1); // Deleting from n element to n element
        localMap_desc.erase(localMap_desc.begin() + (i * 8), localMap_desc.begin() + (i * 8) + 8); // Deleting from n element to n element X 8
        localMap_points.erase(localMap_points.begin() + i, localMap_points.begin() + i + 1); // Deleting from n element to n element

    }

}
for(int i=0;i30)
{
localMap_kp.erase(localMap_kp.begin()+i,localMap_kp.begin()+i+1);//从n元素删除到n元素
localMap_desc.erase(localMap_desc.begin()+(i*8),localMap_desc.begin()+(i*8)+8);//从n元素删除到n元素X 8
localMap_points.erase(localMap_points.begin()+i,localMap_points.begin()+i+1);//从n元素删除到n元素
}
}

使用更合适的数据结构。向量不适用于快速内部删除和插入(即
O(n)
),如果您不需要索引访问(插入/删除为
O(1)
==恒定时间),则列表可能是更好的选择。根据您的需要,您可以使用助手结构,但如果没有进一步的信息,这是不可能的

---添加另一个想法(尽管有人已经提出了)

如果向量的顺序无关紧要,您可以
将要删除的项与向量中的最后一个项交换,然后
弹出返回()

它将是
O(1)

---大声思考


另一个诀窍是使用一个。它们是根据一个字段的“权重”对自身进行重新排序的数据结构,在您的应用程序中,它将是
计数器
字段。它们可以在
O(logn)
中插入,并在
O(1)
中从顶部删除。因此,删除具有较高
计数器的项将非常快,因为它们总是位于顶部。

这里的性能瓶颈是
std::vector
的内存布局,可能还有特殊的成员函数属性/向量元素的存在。如果删除中间的一个元素,则必须将该位置的所有元素移动到结束之前,以在移除的元素之前调整元素。这是通过

  • 如果没有移动向量或移动向量未标记为
    noexcept
  • 否则,每个元素一次移动构造
因此,首先要确保向量中存储的元素类型具有
noexcept
move构造函数


第二,确保在此处使用。通过遵循此模式,交换调用的重新排序首先完成,然后再调用擦除。对于要擦除的
n
项,这些是
n
交换调用。然后,您将有一个对
std::vector::erase
的简单调用,因为所有元素都已按其应有的方式就位。为了使这个过程尽可能快,您可能需要考虑为您的自定义类型提供<代码>交换< /代码>函数。

< p>这里是一个示例,您可以如何同时应用三个向量。 O(N)中的算法,即需要对向量进行单次传递

template<typename T1, typename T2, typename T3, typename P>
void erase3(T1& v1, T2& v2, T3& v3, P predicate) {
    auto first1 = begin(v1);
    auto first2 = begin(v2);
    auto first3 = begin(v3);
    while (first1 != end(v1) && !predicate(*first1)) {
        ++first1; ++first2; ++first3;
    }
    if (first1 != end(v1)) {
        auto it1 = first1; auto it2 = first2; auto it3 = first3;
        while (++it1 != end(v1)) {
            ++it2;
            ++it3;
            if (!predicate(*it1)) {
                *first1++ = std::move(*it1);
                *first2++ = std::move(*it2);
                *first3++ = std::move(*it3);
            }
        }
        v1.erase(first1, end(v1));
        v2.erase(first2, end(v2));
        v3.erase(first3, end(v3));
    }
}

int main()
{
    std::vector<int> v1 = { 1,2,3,4,5 }, v2 = { 11,12,13,14,15 }, v3 = { 21,22,23,24,25 };

    erase3(v1, v2, v3, [](int a) { return a == 3 || a == 4; });

}
模板
无效擦除3(T1和v1、T2和v2、T3和v3、P谓词){
自动优先1=开始(v1);
自动优先2=开始(v2);
auto first3=开始(v3);
while(first1!=end(v1)&&!谓词(*first1)){
++first1;++first2;++first3;
}
如果(第一个1!=结束(v1)){
自动it1=first1;自动it2=first2;自动it3=first3;
而(++it1!=结束(v1)){
++it2;
++it3;
if(!谓词(*it1)){
*first1++=std::move(*it1);
*first2++=std::move(*it2);
*first3++=std::move(*it3);
}
}
v1.擦除(第一个1,结束(v1));
v2.擦除(first2,end(v2));
v3.擦除(first3,end(v3));
}
}
int main()
{
向量v1={1,2,3,4,5},v2={11,12,13,14,15},v3={21,22,23,24,25};
擦除3(v1,v2,v3,[](inta){返回a==3 | | a==4;});
}

这是通过将所有剩余的元素移动到向量的开头,然后从末尾修剪掉移出的元素来实现的。

可能存储一组索引并将它们一次全部删除,而不是一直复制las元素。可能需要后退一步,回顾为什么相关数据需要存储在三个不同的位置向量可能导致不同的设计,问题可能不再出现?向量中项目的顺序对您重要吗?使用交换/擦除技巧可以大大提高删除性能。即载体在中间有缓慢的删除/插入,但在后面很快。当您遇到要删除的项目时,您可以将其与最后一个项目交换,然后
pop_back()
。顺序并不重要,只要这三个向量都对应,因此我可以对这三个向量使用交换技巧。我试试这个。谢谢谢谢你的解释。非常有用。我将尝试如上所述的交换/弹出回技巧。(刚才注意到有人已经提出了这一点。很抱歉,我没有看到)。谢谢!我将实施这一点。