C++ STL矢量元素去除效率
我有一个物体的矢量。所有对象元素都是唯一的。函子是为类的唯一id定义的 从矢量中删除对象元素更有效的方法是什么C++ STL矢量元素去除效率,c++,stl,C++,Stl,我有一个物体的矢量。所有对象元素都是唯一的。函子是为类的唯一id定义的 从矢量中删除对象元素更有效的方法是什么 myvec.erase(std::remove_if(myvec.begin(), myvec.end(), MyClass(id)), myvec.end()); //OR itonmyvec = std::find_if(myvec.begin(), myvec.end(), MyClass(id)); if(itonmyvec != myvec.end()) myve
myvec.erase(std::remove_if(myvec.begin(), myvec.end(), MyClass(id)), myvec.end());
//OR
itonmyvec = std::find_if(myvec.begin(), myvec.end(), MyClass(id));
if(itonmyvec != myvec.end())
myvec.erase(itonmyvec);
比如说
从范围中删除满足特定条件的所有元素
while被指定为
返回范围中的第一个元素
因为您知道向量中的所有元素都是唯一的,所以可以在第一次匹配后安全地停止搜索。这意味着第二种形式对于这种特定情况可能更快
还请注意,如评论中所述,第一种方法是错误的<如果将迭代器返回到(可能已更新)范围的末尾,则code>remove_。您不想从向量中删除此内容-它保证不匹配您的目标值。当您使用向量时,两个建议的实现几乎相同 第一个将遍历向量一次,测试每个元素并同时压缩向量,然后最终销毁最后一个元素并缩短向量 第二个将遍历向量直到找到元素,然后遍历向量的其余部分以压缩并最终缩短向量 事实证明,两个版本之间唯一的真正区别是,第二个版本将能够保存O(n/2)个比较的平均值。如果比较便宜,则性能将更多地取决于系统的其他属性,例如,哪个实现对缓存更友好 因此,最终答案只能是基准测试它强>
注意:第一个版本必须检查
remove\u的结果是否是向量的end
,以便以相同的方式在两个版本中进行检查(或不进行检查)。实际最快的方法都不是。这两个元素都会受到标准中附加的约束,即保持其余元素的相对顺序,但这不是您所要求的
因此,最快的解决方案是
找到元素
将其与最后一个元素交换
删除新的最后一个元素
这将执行O(1)赋值,而不是O(N)。对于MSalters给出的答案,我已经写下了代码。我无法将代码添加到该答案的注释中,因此将其添加到新答案中。希望有帮助
//Remove 3rd element
vector<int> v {1,2,3,4,5}; //C++11 compiler needed!
vector<int>::iterator it1 = find(v.begin(), v.end(), 3);
vector<int>::iterator it2 = --v.end();
std::swap(*it1, *it2);
v.pop_back();
//删除第三个元素
向量v{1,2,3,4,5}//需要C++11编译器!
向量::迭代器it1=find(v.begin(),v.end(),3);
向量::迭代器it2=--v.end();
标准:交换(*it1,*it2);
v、 向后弹出();
如果您愿意牺牲异常安全性,您可以比当前接受的答案做得更好:您可以简单地用最后一个元素覆盖要删除的元素,而不是用最后一个元素交换,然后调用pop_back()
。必须从最后一个元素开始向后迭代
如果您使用整数,这是很好的,而且很可能会节省大量时间。如果您使用的是谁知道在移动复制时会抛出哪些类,那么您就有麻烦了,您的异常安全保证就没有了
下面是一个示例代码:
#include <iostream>
#include <vector>
template <typename Vector, typename Pred>
void remove(Vector& v, Pred p) {
auto last(v.rbegin());
for (auto pos(last), rend(v.rend()); pos!=rend; ++pos) {
if (p(*pos))
// overwrite the element to be removed with the currently last element
*pos = std::move(*last++);
}
v.erase(last.base(), v.end());
}
// pretty print the vector for debugging
template <typename Vector>
void show(const Vector& v) {
std::cout << "{ ";
auto pos(v.begin());
auto last(v.end());
if (pos!=last) {
--last;
while (pos!=last)
std::cout << *pos++ << ", ";
std::cout << *last;
}
std::cout << " }" << std::endl;
}
// a simple-minded test that removes all 2s from the vector
void remove_2s(std::initializer_list<int> l) {
auto equals_two = [](int i) { return i==2;};
std::vector<int> v{l};
remove(v, equals_two);
show(v);
}
int main() {
remove_2s({1, 2, 3, 2, 5, 7, 4, 2, 6});
remove_2s({ 1, 2 });
remove_2s({ 2, 1 });
remove_2s({ 2 });
remove_2s({ 2, 2 });
remove_2s({ });
remove_2s({ 1 });
}
#包括
#包括
模板
无效删除(矢量和v、Pred p){
自动最后(v.rbegin());
用于(自动转位(最后一个)、rend(v.rend());转位!=rend;++pos){
如果(p(*pos))
//用当前最后一个元素覆盖要删除的元素
*pos=std::move(*last++);
}
v、 擦除(last.base(),v.end());
}
//漂亮的打印矢量以进行调试
模板
无效显示(常量向量和v){
std::你为什么不对它进行基准测试?擦除
是一个成员函数,而不是一个算法
@DivyangPatel不,不是真的。获取这一特定知识的努力是最小的,每个回答这个问题的人都很可能会做完全相同的事情(不太可能有人研究过这个特定的事情)。有很多知识和经验可以让人做出有根据的猜测,但是(1)描述完整的推理进入了“过于宽泛”的领域,(2)它仍然只是猜测,而不是一个明确的答案。问题“a比B快”非常窄(也许太窄),问题“我如何决定什么更快?”太宽泛了。@DivyangPatel我明白了。我的即时直觉预测是,没有人手头有基准,到目前为止的答案证实了这一点:有根据的猜测,但仍然是猜测。@DivyangPatel-如果有人回答你说“第一个代码更快”,你会相信他们的话而不自己做基准测试吗?完美而高效的技术!我在下面的一个新答案中添加了相同的代码!如果你愿意牺牲异常安全,你可以做得更好,请参阅我的答案。如果你愿意牺牲异常安全,你可以做得更好,请参阅我的答案。还有move\u if_但实际上,我们正在优化O(1)部分,而搜索仍然是O(N)@MSalters是的,我知道,它只影响常数因子。问题是这样的,线性时间搜索是不可避免的,因此我们只能在常数因子上进行改进。@MSalters啊,他只需要删除一个元素。我的错,没有注意到。那么可能是我的“改进”真的没什么大不了的。嗯,我不能在代码审查中就此签字。你为了什么利益而牺牲异常安全?这不值得。你最终会像谷歌一样,为未来的程序员编写指南,他们不能使用异常,因为所有的遗留代码都不是异常安全的。@CodyGray好吧,如果你需要的话“最快”的算法,而且你知道你正在处理的类型不会抛出move-copy,那么我上面写的是安全的。然而,你让我好奇:“你为了什么好处而牺牲了异常安全?”我将在周末对它进行测量。当我们在做的时候:如果