我有一个对象矢量。所有对象元素都是唯一的。 Functor是为类的唯一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())
myvec.erase(itonmyvec);
答案 0 :(得分:4)
实际上最快的方法都不是。两者都受到保留其余元素相对顺序的标准中的额外约束,但这不是你所要求的。
因此,最快的解决方案是
执行O(1)分配,而不是O(N)。
答案 1 :(得分:2)
当您使用向量时,两个建议的实现几乎完全相同。
第一个将遍历向量一次,测试每个元素并同时压缩向量,然后最终破坏最后一个元素并缩短向量。
第二个将遍历向量,直到找到元素,然后遍历向量的其余部分以压缩并最终缩短向量。
事实证明,两个版本之间唯一真正的区别是,第二个版本能够保存平均O(n / 2)比较。如果比较便宜,性能将更多地取决于系统的其他属性,例如:哪个实现更加缓存友好。
因此,最终答案只能是基准测试!
PS:第一个版本必须检查remove_if
的结果是否与向量的end
完全等效,以便在两个版本中检查完成(或不完成)方式。
答案 2 :(得分:1)
remove_if的文档说
从范围...
中删除满足特定条件的所有元素
将find_if指定为
返回范围中的第一个元素......
由于您知道矢量中的所有元素都是唯一的,因此您可以在第一次匹配后安全地停止搜索。这意味着对于这种特定情况,第二种形式可能更快。
另请注意,正如评论中所述,第一种方法是错误的。 remove_if
将迭代器返回到(可能更新的)范围的末尾。您不希望从矢量中删除它 - 保证不会与您的目标值匹配。
答案 3 :(得分:0)
对于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();
答案 4 :(得分:0)
你可以做得比当前接受的答案更好,如果你愿意牺牲异常安全:不是用最后一个元素交换然后调用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 });
}