我有以下玩具代码,旨在从矢量中删除重复项:
void overlap_removal(vector<int> &vec1, vector<int> &vec2) {
for (vector<int>::iterator it1 = vec1.begin(); it1 != vec1.end(); ++it1) {
for (vector<int>::iterator it2 = vec2.begin(); it2 != vec2.end(); ++it2) {
if ((*it1)*(*it2) < 10) {
vec1.erase();
}
}
}
}
我在实际代码中做了稍微复杂的比较,但不想混淆问题。问题是分段错误不可避免地跟随执行:我认为这是因为我正在删除一个元素,然后继续循环遍历同一个向量。
如何使代码有效?这甚至是正确的起点吗? 提前致谢
答案 0 :(得分:10)
试试remove_if。
基本思想是提供一个函数对象,如果传入的元素应该删除,则返回true:
class ItemInOtherVectorPred
{
const std::vector<int>& otherVec;
ItemInOtherVectorPred(const std::vector<int>& vec) : otherVec(vec) {}
// return true if removeVecsElem should be deleted
bool operator()(const int& removeVecsElem) const
{
return (otherVec.find(removeVecsElem) != otherVec.end())
}
}
然后你使用该对象的一个实例来告诉remove_if从你的向量中删除什么。
void overlap_removal(vector<int> &vec1, vector<int> &vec2)
{
ItemInOtherVectorPred trueIfItemInOtherVecPred( vec2);
vector<int>::iterator eraseBeg =
std::remove_if( vec1.begin(), vec1.end(), trueIfItemInOtherVecPred);
vec1.erase(eraseBeg, vec1.end());
}
答案 1 :(得分:3)
如果我想尽可能地保留你的逻辑,我会这样做。
it1
在外循环结束时更新,具体取决于是否在内循环中找到了匹配项。
使用引用传入参数以避免复制输入并确保第一个输入反映更改。
秒vector
为const
。
void overlap_removal(vector<int>& vec1, const vector<int>& vec2) {
for (vector<int>::iterator it1 = vec1.begin(); it1 != vec1.end(); ) {
bool match(false);
for (vector<int>::const_iterator it2 = vec2.begin(); it2 != vec2.end(); ++it2) {
if (*it1 == *it2) {
match = true;
break;
}
}
if (match)
{
it1 = vec1.erase(it1);
}
else
{
++it1;
}
}
}
有更好的方法可以使用STL功能执行此操作,但其他人在我看到的帖子上发布。尽管如此,理解矢量方法的工作方式仍然很好,即使你可以在这种情况下绕过它们。
答案 2 :(得分:1)
这是真的。删除元素后,迭代器无效。每次删除元素时都必须创建一个新的迭代器。
答案 3 :(得分:0)
如果vec2很大或有许多重复元素(在此函数中反复无用地扫描),对第二个向量进行排序并将其置于(无序)集合中可能更有效,以降低复杂性。
#include <vector>
#include <unordered_set>
#include <iostream>
#include <iterator>
#include <algorithm>
void overlap_removal(std::vector<int> &v1, const std::vector<int> &v2)
{
std::unordered_set<int> s(v2.begin(), v2.end());
v1.erase(std::remove_if(v1.begin(), v1.end(),
[&s](int i){return s.count(i);}),
v1.end());
}
int main()
{
std::vector<int> v1 = {5,6,3,2,3,5,1,2,1};
std::vector<int> v2 = {2,3};
overlap_removal(v1, v2);
copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
或者,保持C ++ 98
struct IsInSet {
const std::set<int>& m_s;
IsInSet(const std::set<int>& s) : m_s(s) {}
bool operator()(int i) const { return m_s.count(i); }
};
void overlap_removal(std::vector<int> &v1, const std::vector<int> &v2)
{
std::set<int> s(v2.begin(), v2.end());
v1.erase( std::remove_if(v1.begin(), v1.end(), IsInSet(s)), v1.end());
}