我有三个std::vectors
,每个包含不同的数据类型。
我需要做的是从每个索引项中删除相同的索引项,具体取决于第一个索引项的值。
在下面的代码中,如果localMap_points[i].m_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
}
}
答案 0 :(得分:4)
这里的性能瓶颈是std::vector
的内存布局,可能还有特殊的成员函数属性/矢量元素的存在。如果擦除中间的一个元素,则必须移动从该位置到末尾的所有元素,以适应删除的元素之前的元素。这是通过
noexcept
的移动ctor,则每个元素一个副本构造因此,要确保的第一件事是向量中存储的元素类型具有noexcept
move构造函数。
第二,请确保在此处使用erase-remove idiom。通过遵循这种模式,在进行任何擦除操作之前,首先要完成对交换调用的重新排序。对于要删除的n
个项目,它们是n
交换调用。然后,您将对std::vector::erase
进行微不足道的调用,因为所有元素都已经按需放置。为了使此过程尽快完成,您可能要考虑为自定义类型提供一个swap
函数。
答案 1 :(得分:2)
使用更合适的数据结构。向量不用于快速内部删除和插入(O(n)
),如果不需要索引访问(插入/删除为O(1)
==恒定时间),则列表可能是更好的选择。根据您的需要,您可以使用辅助结构,但是如果没有更多信息,这是不可能的。
---添加了另一种想法(尽管有人已经提出了这个想法)。
如果矢量的顺序无关紧要,则可以swap
将要删除的项目与矢量中的最后一个一起,然后pop_back()
。
应该是O(1)
。
---大声思考。
另一个技巧是使用priority queue。它们是一种数据结构,它根据一个字段的“权重”对自身进行重新排序,在您的应用程序中,它将是counter
字段。他们可以在O(log n)
中插入,并在O(1)
中从顶部删除。因此,删除具有较高counter
的项目将非常快,因为它们始终位于最前面。
答案 2 :(得分:2)
这是一个示例,您如何一次将erase-remove idiom应用于三个向量。
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; });
}
这是通过将所有剩余元素移动到向量的开头,然后从结尾处修剪掉移出的元素来实现的。