2012-09-04 34 views
1

這是我的問題,我有一個雙向量,我需要在一定條件下消除其中的一些。這裏是一個代碼示例:vector :: erase()是否改變位置?

vector <double> appo; 
for(int i=0;i<appo.size();i++){ 
     for(int j=i+1;j<appo.size();j++){ 
     if(condition(appo[i],appo[j])){ 
      appo.erase(appo.begin()+j); 
      j--; 
     } 
     } 
    } 

因爲擦除後()1,所有的元素,我的尺寸減小就剩移左,是正確的降低J&prime;

好的我決定不使用removeif,因爲它是一個小程序,我現在不在乎性能,但是我得到了段錯誤。 下面是代碼:

vector <double> *point; 
for(int i=0;i<point->size();i+=3){ 
    for(int j=i+3;j<point->size();j+=3){ 
     if(distance((*point)[i],(*point)[i+1],(*point)[i+2],(*point)[j],(*point)[j+1],(*point)[j+2]) < treshold){ 
     point->erase(point->begin()+j,point->begin()+j*3); 
     j-=3; 
     } 
    } 
    } 

點是座標爲載體所以像(X1,Y1,Z1,X2,Y2,Z3,...,XN,YN,ZN)。 有什麼想法?

+2

擦除後的所有元素* *。取決於許多事情,'std :: remove_if'可能證明更有效。 –

回答

6

這是正確的遞減j,因爲指數j擦除元素之後,以前是在j+1的元素現在是在j,所以你要與j相同的值重複這個循環。減少它有這種效果,因爲循環本身增加它。

你也可以考慮使用迭代器替代索引:

vector<double>::iterator j = appo.begin() + i + 1; 
while (j != appo.end()) { 
    if (condition(appo[i], *j)) { 
     j = appo.erase(j); 
    } else { 
     ++j; 
    } 
} 

已經這樣做了,你可以使用一個迭代器i爲好。

由於「eq-」在評論中說,有一個標準算法可以幫助你。你可以選擇是否在可用性方面更喜歡循環,但它通常更高效,因爲反覆調用「擦除」每次一步一步地洗牌每個元素,而remove_if保持跟蹤「讀取位置」和「寫入位置「,所以它最多隻能複製每個元素一次。

appo.erase(
    appo.remove_if(
     appo.begin() + i + 1, 
     appo.end(), 
     ShouldRemove(appo[i]) 
    ), 
    appo.end() 
); 

在C++ 03你必須定義ShouldRemove類似於:

struct ShouldRemove { 
    double lhs; 
    ShouldRemove(double d) : lhs(d) {} 
    bool operator()(double rhs) { 
     return condition(lhs, rhs); 
    } 
}; 

在C++ 11可以使用lambda代替ShouldRemove:

appo.erase(
    appo.remove_if(
     appo.begin() + i + 1, 
     appo.end(), 
     [&](double d) { return condition(appo[i], d); } 
    ), 
    appo.end() 
); 

也有一些選項使用std::bind1stboost::bind(在C++ 03中)或std::bind(在C++ 11中),但這些都很難正確理解。