【问题标题】:C++ : deleting multiple elements of a list while iterating the listC ++:在迭代列表时删除列表的多个元素
【发布时间】:2013-08-18 08:36:07
【问题描述】:

我知道如何擦除列表的元素,并且擦除返回一个有效的迭代器。我的问题是,我不仅要删除一个元素,还要删除多个元素。

其实我的代码是这样的

 for(list<Treenode*>::iterator it=currentLevel->begin(); it!=currentLevel->end(); ++it){
     if(something(*it))  {
         for(list<Treenode*>::iterator it2=currentNewLevel->begin();it2!=currentNewLevel->end();){
             if (somethingDifferent(*it2)) {
                 it2=currentLevel->erase(it2);
             } else {
                 ++it2;
             }
         }
     }
 }

这当然行不通,因为it 没有改变。我不知道如何更改迭代器,但请继续执行此迭代步骤。

感谢您的阅读。我希望有人知道答案。

【问题讨论】:

  • 可能是我头脑简单:if(it2 == it) 在擦除后也调整一下

标签: c++ list iterator erase


【解决方案1】:

一般来说,根据条件从列表中删除元素的方法是使用std::list::remove_if成员函数。

bool pred(const Treenode* t) { .... }
currentNewLevel.remove_if(pred);

谓词可以是函子,因此它可以保持实现删除条件所需的任何状态:

#include <algorithm> // for std::find_if
#include <list>

// unary predicate functor. Returns true if an element of a reference
// list satisfies "something" and the functor call argument satisfies "somethingDifferent"
struct Pred
{
  Pred(const std::list<Treenode*>& nodes) : nodes_(nodes) {}
  bool (const Treenode* t) const
  {
    return std::find_if(nodes_.begin(), nodes_.end(), something) != nodes_.end() &&
           somethingDifferent(t);
  }
 private:
  const std::list<Treenode*>& nodes_;
};

然后

Pred p(currentLevel);
currentLevel.remove_if(p);

【讨论】:

  • 谢谢。问题是我在外循环中做了一些其他的事情。我可以将您的方式用于内部循环,但外部循环的迭代器将无效。
  • @user2693497 你可以编写一个使用currentLevel 的函子。而且我并没有真正看到外部循环迭代器的问题。您可能应该解释您要达到的目标。
  • @Name 我添加了一个带有仿函数的示例。它做了我认为你的原始代码试图做的事情。
  • 再次感谢您。 “if(SomethinDifferent){...}”部分只是我为每个列表条目所做的一小部分。我做了很多最终改变其他列表条目的事情。迭代器不应访问已更改的列表条目。所以我想将它们从 currentLevel 中删除。所以我真的需要外循环。我想从我迭代的列表中删除元素我得到一个分段错误。但这仅在删除迭代器当前显示的元素时才成立。所以我只需要确保我不删除这个元素。感谢您的帮助!
【解决方案2】:

做while循环。它也大多是 ++,所以性能应该不错。

std::vector<PdfTextRegion*>::const_iterator textRegion = m_pdfTextRegions.begin();
    while(textRegion != m_pdfTextRegions.end())        
    {
        if ((*textRegion)->glyphs.empty())
        {
            m_pdfTextRegions.erase(textRegion);
            textRegion = m_pdfTextRegions.begin();
        }
        else
            textRegion++;
    }

【讨论】:

  • 性能很容易很糟糕 - 最坏的情况 O(n**2),因为它每次都从头开始。 remove_if 版本将目标元素交换到最后,保证线性时间和单次通过。各方面都更好。
猜你喜欢
  • 2018-07-18
  • 2015-06-30
  • 2016-11-21
  • 2013-01-23
  • 2011-04-02
  • 2011-03-18
  • 2017-12-13
  • 2013-01-29
  • 1970-01-01
相关资源
最近更新 更多