【问题标题】:Erase element in vector while iterating the same vector [duplicate]在迭代同一向量时擦除向量中的元素[重复]
【发布时间】:2012-03-29 14:13:25
【问题描述】:

可能重复:
Erasing from a std::vector while doing a for each?

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

/*
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); 行已经是一般用途但它给出了运行时错误。

【问题讨论】:

    标签: c++ vector


    【解决方案1】:

    行内:

    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;
       }
       ...
    }
    

    您可以阅读有关此here 的更多信息。

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

    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 中的下一个元素。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

        vector::erase()可以invalidate iterators指向向量。

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

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

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

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

        同样,即使您将擦除结果分配给it2,调用也会使it 无效,这不会改变。

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

        【讨论】:

          【解决方案4】:

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

          尝试更改您的 if in:

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

          【讨论】:

          • 如果迭代器不在最后,我必须继续迭代。
          • 事实上,break; 退出了 while,但没有退出 for。这样,for 循环就变成了 it2++ 并使用下一个迭代器进行迭代。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-01-02
          • 1970-01-01
          • 2018-10-09
          • 1970-01-01
          • 1970-01-01
          • 2013-02-09
          相关资源
          最近更新 更多