在迭代同一矢量时擦除矢量中的元素

Erase element in vector while iterating the same vector

本文关键字:元素 擦除 迭代      更新时间:2023-10-16

可能的重复项:
从 std::vector 中删除,同时为每个执行 a?

我正在尝试根据此算法实现顶点着色;

/*
Given G=(V,E):
Compute Degree(v) for all v in V.
Set uncolored = V sorted in decreasing order of Degree(v).
set currentColor = 0.
while there are uncolored nodes:
   set A=first element of uncolored
   remove A from uncolored
   set Color(A) = currentColor
   set coloredWithCurrent = {A}
   for each v in uncolored:
      if v is not adjacent to anything in coloredWithCurrent:
         set Color(v)=currentColor.
         add v to currentColor.
         remove v from uncolored.
      end if
   end for
   currentColor = currentColor + 1.
end while
*/

我不明白"将v添加到currentColor"行,但我想,这意味着将currentColor添加到v。那么什么是"集合"?无论如何,问题是在迭代时擦除矢量中的元素。这是代码。

    vector<struct Uncolored> uc;
    vector<struct Colored> c;   
    int currentColor = 0;
    struct Colored A;
    struct Colored B;
    vector<struct Uncolored>::iterator it;
    vector<struct Uncolored>::iterator it2;
    vector<struct Colored>::iterator it3;
    for(it=uc.begin();it<uc.end();it++){
        A.id = (*it).id;        
        uc.erase(uc.begin());
        A.color = currentColor;
        c.push_back(A);
        for(it2=uc.begin();it2<uc.end();it2++) {
            it3=c.begin();
            while(it3 != c.end()) {
                if( adjacencyMatris[(*it2).id][(*it3).id] == 0 ) {
                    B.id = (*it2).id;       
                    it2 = uc.erase(it2);
                    B.color = currentColor;
                    c.push_back(B);
                }
                it3++;
            }
        }
        currentColor = currentColor + 1;
    }

我认为it2 = uc.erase(it2);行已经是通用的,但它给出了运行时错误。

在行中:

it2 = uc.erase(it2);

迭代器it2指向的元素从向量中删除,元素在内存中移动以填补使it2无效的空白。 it2 获取一个新值,现在指向删除的元素或向量末尾之后的第一个元素(如果删除的元素是最后一个元素(。这意味着擦除元素后不应前进it2。建议remove-erase idiom的替代方案是一个简单的技巧:

for(it2 = uc.begin(); it2 != uc.end();)
{
   ...   
   if(...)
   {
      it2 = uc.erase(it2); 
   }
   else
   {
      ++it2;
   }
   ...
}

您可以在此处阅读有关此内容的更多信息。

编辑:关于你的评论,你可以使用一个标志来传递一个元素是否被删除的信息,当你从内部循环中出来时,你可以检查它:

for(it2=uc.begin(); it2 != uc.end();)
{
   bool bErased = false;
   for(it3 = c.begin(); it3 != c.end(); ++it3)
   {
      if(adjacencyMatris[(*it2).id][(*it3).id] == 0 )
      {
         B.id = (*it2).id;
         it2 = uc.erase(it2);
         bErased = true;
         B.color = currentColor;
         c.push_back(B);
         break;
      }
   }
   if(!bErased)
      ++it2;
}

uc中删除元素后,需要断开内部循环。在外部循环的下一次迭代中,您将能够通过有效的迭代器访问uc中的下一个元素。

不要使用iterator类型,而是将索引存储到vector中。当你需要一个迭代器时——也许是为了传递到erase——你可以说begin() + myIndex来生成一个迭代器。

这也使循环看起来更熟悉,例如

for(ind=0; ind < uc.size(); ind++) {

vector::erase()可以使指向向量的迭代器无效。

这将使所有迭代器和对位置(或第一个(及其后续元素的引用无效。

您需要将erase的结果添加到迭代器中(它将指向擦除后的元素(并因此使用它。请注意,在

for(it=uc.begin();it<uc.end();++it){ 
  A.id = (*it).id;         
  uc.erase(uc.begin()); 
  ...
}

迭代器ituc.erase 后无效,因此后续 ++ 和使用可能会导致运行时错误。

类似地,即使将擦除的结果分配给it2,调用也可以使it无效,这不会改变。

你最好的选择是在每次erase()之后从头开始你的算法,或者如果你可以改变它,以便它可以从erase返回的迭代器继续,这样做以获得一些效率。

您遇到了运行时错误,因为it2 = uc.erase(it2);在最后一个删除的元素之后返回迭代器,因此for(it2=uc.begin();it2<uc.end();it2++)中的it2++超出了最后一个元素。

尝试在以下位置更改您的 if:

if( adjacencyMatris[(*it2).id][(*it3).id] == 0 ) {
    B.id = (*it2).id;       
    uc.erase(it2);
    B.color = currentColor;
    c.push_back(B);
    break;
}