简体   繁体   English

从多个std :: vectors中删除项目的最快方法

[英]fastest way to remove items from multiple std::vectors

I have three std::vectors , each containing different data types. 我有三个std::vectors ,每个都包含不同的数据类型。

What I need to do is remove the same index item from each, depending on the value of that indexed item in the first one. 我需要做的是从每个索引项中删除相同的索引项,具体取决于第一个索引项的值。

In the code below, if the value of localMap_points[i].m_counter is more than 30, I erase the item at index [i] from all three vectors. 在下面的代码中,如果localMap_points[i].m_counter值大于30,我将从所有三个向量中删除index [i]处的项目。 ( localMap_desc contains 8 items for the other vectors one, hence the x 8 added to that one) localMap_desc包含8个项目,其他向量一个,因此x 8添加到那个)

This works perfectly, but is slow. 这很好用,但很慢。 Is there a faster way to do this? 有更快的方法吗?

I have: 我有:

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

    }

}

The performance bottleneck here is the memory layout of std::vector , possibly together with the special member function properties/existence of the vector elements. 这里的性能瓶颈是std::vector的内存布局,可能还有特殊的成员函数属性/ vector元素的存在。 If you erase one element in the middle, all the elements from this position until the end must be moved to adjust to the element before the removed one. 如果擦除中间的一个元素,则必须移动从该位置到结尾的所有元素,以便在移除元素之前调整元素。 This is done via 这是通过

  • one copy construction per element, if there is no move ctor or if the move ctor is not marked noexcept 每个元素一个复制构造,如果没有移动ctor或者移动ctor没有标记为noexcept
  • one move construction per element otherwise. 否则,每个元素一个移动构造。

The first thing to ensure is hence that the element type stored in the vector has a noexcept move constructor. 因此,要确保的第一件事是存储在向量中的元素类型具有noexcept移动构造函数。

Second, make sure to use the erase-remove idiom here. 其次,请务必在此处使用erase-remove惯用法 By following this pattern, the reordering in terms of swap invocations is done first, before any calls to erase. 通过遵循此模式,在任何调用擦除之前,首先完成交换调用方面的重新排序。 For n items to be erased, those are n swap invocations. 对于要删除的n项目,这些是n交换调用。 Then, you will have a trivial call to std::vector::erase , as all elements are already in place as they should. 然后,您将对std::vector::erase进行一个简单的调用,因为所有元素都已按原样放置。 For this procedure to as fast as possible, you might want to consider providing a swap function for your custom types. 为了使此过程尽可能快,您可能需要考虑为自定义类型提供swap功能。

Use a more proper data structure. 使用更合适的数据结构。 vectors are not meant for fast internal deletion and insertion (the are O(n) ), lists may be a better choice if you don't need indexed access (insert/delete is O(1) == constant time). 向量不适用于快速内部删除和插入(是O(n) ),如果您不需要索引访问(插入/删除是O(1) ==常量时间),列表可能是更好的选择。 Depending by your needs, you may use an helper structure, but it's not possible without further information. 根据您的需要,您可以使用辅助结构,但如果没有进一步的信息,则无法实现。

--- Adding another thought (someone already suggested this though). ---添加另一个想法(虽然有人已经提出这个想法)。

If order of vector doesn't matter, you could swap the item to be deleted with the last in the vector, and then pop_back() . 如果向量的顺序无关紧要,您可以将要删除的项目与向量中的最后一项swap ,然后使用pop_back()

It would be O(1) . 这将是O(1)

--- Thinking out loud. - - 把想法大声说出来。

Another trick would be to use a priority queue . 另一个技巧是使用优先级队列 They are data structure that reorders itself based on the "weight" of one field, in your application it would be the counter field. 它们是基于一个字段的“权重”重新排序的数据结构,在您的应用程序中它将是counter字段。 they are able to insert in O(log n) and delete from top in O(1) . 它们能够插入O(log n)并从O(1)顶部删除。 So it would be quite fast to remove the items with higher counter , because they are always on top. 所以用较高的counter移除物品会很快,因为它们总是处于最顶层。

Here's an example how you can apply the erase-remove idiom for three vectors at once. 这是一个如何一次为三个向量应用擦除 - 移除习语的示例。

The algorithm in O( N ), ie requires a single pass over the vectors. 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; });

}

This works by moving all remaining elements to the beginning of the vectors and then trimming off the moved-out ones from the end. 这可以通过将所有剩余元素移动到向量的开头,然后从末尾修剪掉移出的元素来实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM