C ++,在函数内部从一对中删除元素

时间:2011-02-13 13:33:23

标签: c++

我正在使用C ++,我有一个配对变量的向量,第一个元素是一个向量,第二个元素是一个整数。我的问题是我试图从这个向量中删除某些元素,似乎无法让它工作!

代码如下所示,一切正常,因为我期待这一行:

vec1.erase(i);

因为我可以将一些其他相关变量从矢量传递到屏幕,它们是正确的。

compareVecs只是该类的一个元素,用于比较一些变量。

void myCode::PairRemoval(vector<myTypeDef> &vec1, const vector<myTypeDef> &vec2, double conditionMax) {
  bool condition=false;
  for (unsigned int i=0; i<vec1.size(); i++){
    for (unsigned int j=0; j<vec2.size(); j++){
      if (vec1[i].first.compareVecs(vec2[j].first) <= conditionMax) {
    condition = true;
       break;
      }
     }  
    if (condition) {
      vec1.erase(i);
      cout<<"removed"<<endl;
    } 
  }
}

如果满足条件,我希望从该向量中删除该对。

提前感谢您的帮助!

6 个答案:

答案 0 :(得分:3)

erase的问题在于它会删除你指向的元素,同时也会改变向量的大小。由于向量要求每个后续元素都被向下复制,因此效率非常低。因此,如果您有15个元素并擦除第一个元素,那么您现在只需复制14个元素。

您可以使用

来解决这个问题
for(vector<whatever>::iterator foo = myVector.begin(); foo != myVector.end(); ++foo){
    if( myPredicate( foo ) ){
        foo = myVector.erase(foo);
    }
}

但正如我所说,这是非常低效的。如果需要擦除每个元素,则可能需要O(N ^ 2)时间。

相反,请使用复制和交换技术:

vector<T> myNewVector;
copy_if( myOldVector.begin(), myOldVector.end(), back_inserter(myNewVector), fun_ptr(myPredicate) );
myOldVector.swap(myNewVector);

答案 1 :(得分:2)

您不应在循环内迭代向量和擦除元素。擦除元素时,矢量大小会更改,索引也会更改。推荐的方法是将你必须删除的元素存储在另一个结构中(如矢量),然后循环删除它们。

void myCode::PairRemoval(vector<myTypeDef> &vec1, const vector<myTypeDef> &vec2, double conditionMax) {
    bool condition=false;
    vector<vector<myTypeDef>::iterator> toRemove;
    for (vector<myTypeDef>::iterator it = vec1.begin(); it != vec1.end(); it++){
        for (unsigned int j=0; j<vec2.size(); j++){
            if ((*it).first.compareVecs(vec2[j].first) <= conditionMax) {
                condition = true;
                break;
            }
        }  
        if (condition) {
            toRemove.push_back(it);
        } 
    }
    for(int i = 0; i < toRemove.size(); i++){
        vec1.erase(toRemove[i]);
    }
}

答案 2 :(得分:2)

标准库已经包含一个函数[template],用于根据自定义谓词从序列中删除元素,因此可以更清楚地将“条件”抽象为仿函数并使用标准的擦除/删除习惯用法。

这个示例编译但我无法给仿函数一个有意义的名称,因为我不确定你的条件逻辑背后的基本原理是什么。

#include <vector>
#include <algorithm>

struct x { double compareVecs( const x& ) const; };
typedef std::pair<x, int> myTypeDef;

class ErasePredicate
{
public:
    ErasePredicate(const std::vector<myTypeDef>& vec2, double conditionMax)
        : _vec2(&vec2), _conditionMax(conditionMax) {}

    // The valuable condition logic goes here
    bool operator()( const myTypeDef& v ) const // assume this can be const ref
    {
        for (size_t j = 0; j != _vec2->size(); ++j)
        {
            if (v.first.compareVecs((*_vec2)[j].first) <= _conditionMax)
            {
                return true;
            }
        }
        return false;
    }

private:
    // pointer, to get copy-ctor and op= for free
    const std::vector<myTypeDef>* _vec2;
    double _conditionMax;
};

void PairRemoval(std::vector<myTypeDef> &vec1,
                 const std::vector<myTypeDef> &vec2,
                 double conditionMax)
{
    // The mechanics of performing the erase is handled by stdlib functionality
    vec1.erase(std::remove_if(vec1.begin(),
                              vec1.end(),
                              ErasePredicate(vec2, conditionMax)),
               vec1.end());
}

答案 3 :(得分:1)

我认为你的for循环存在缺陷。假设我是5并且您删除元素5.然后我将增加到6以进行下一次迭代。但是现在元素6的元素现在位于第5位。这意味着你的循环不会擦除向量中的后续元素。

作为一种解决方法,在从向量中删除元素后减少i。

答案 4 :(得分:1)

通过引用c++ reference,我认为erase应该以迭代器作为参数。也许你的代码应该是vec1.erase(vec1.begin()+ i);

答案 5 :(得分:0)

看起来您想要从容器中删除一些元素。 C ++标准库只有一个算法:std::remove。唯一需要注意的是它不会从容器中移除任何东西:)

如果可以使用简单的运算符==标识要删除的元素,则可以使用std::remove。如果识别元素更复杂,则需要使用std::remove_if

现在请注意。在C ++标准库中,算法与容器分离。 std::remove需要几个迭代器,因此它可能会破坏这些迭代器之间的元素,但它对容器一无所知,因此无法更改它。解决方案是erase-remove idiom

auto it = std::remove_if( v.begin(), v.end(), some_predicate_returning_bool());
myOldVector.erase(it, v.end()); // or a lambda^

首先,我们使用remove将“未删除的”元素移动到容器的开头。 remove返回一个迭代器,它指向我们不想要的第一个元素。

std::vector<int> v { 1, 3, 3, 7 };
auto it = std::remove(v.begin(), v.end(), 3);

此次通话后,v将包含1, 7, 3, 7it点,而不是7。 (1保留了它的位置,7在它后面洗牌)。调用

v.erase(it, v.end());

导致v成为1, 7