在C++中迭代遍历向量中的特定元素

5

如果这是一个琐碎的问题,请原谅我,我只是在学习C++并试图理解某些概念。特别是当涉及到迭代器时,我完全迷失了。

假设我有一个自定义类来表示一些数据结构,并且其中一个成员是整数向量。我想为该类编写一个双向迭代器,仅输出向量中的偶数。有没有简单而有启示性的方法?我希望不要使用STL以外的库。


4
你为什么不展示一下你到目前为止所做的事情? - lordjeb
4
我知道你不想使用其他库,但如果有其他人阅读这个问题并且不介意使用它们的话,Boost库中有一个 filter iterator 可以完美地实现此目的。 - cdhowie
1
你想输出偶数还是偶数索引的数字? - dlf
copy_if(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "), [](int i){ return (i % 2) == 0; }); - Neil Kirk
3个回答

3

如果你不确定如何自己编写迭代器,那么最好使用条件语句for_each函数。

std::for_each可以对每个元素执行操作。很容易创建一个for_each_if对特定元素执行操作。例如,下面的程序仅打印向量中的偶数(4、6和8)。

#include <iostream>
#include <vector>

using namespace std;

struct is_even {
  typedef bool return_type;
  bool operator() (const int& value) {return (value%2)==0; }
};

struct doprint {
  bool operator() (const int& value) { std::cout << value << std::endl; }
};

template <class InputIterator, class Predicate, class Function> 
void for_each_if(InputIterator first, InputIterator last, Function f, Predicate pred) 
{ 
    while ( first != last )
    {  
        if (pred (*first)) 
            f(*first++);  
        else 
            first ++; 
    }
}

int main()
{
   std::vector<int> v;
   v.push_back( 4 );
   v.push_back( 5 );
   v.push_back( 6 );
   v.push_back( 8 );

   for_each_if( v.begin(), v.end(), doprint(), is_even());

   return 0;
}

3
根据您的要求,从vector::iterator派生可能是最简单的方法:
class my_iterator : private std::vector<int>::iterator {
    typedef std::vector<int>::iterator base;
    base m_base_end;   // Stores the real end iterator of the internal vector.
                       // We need it so that the even/odd checking code
                       // doesn't run off the end of the vector
                       // (initialize it in a constructor, omitted here for
                       // brevity).
public:

    using base::operator*;
    using base::operator->;
    // etc. for other members...

    // except for increment:

    my_iterator& operator++()
    {
        do {
            base::operator++();
        } while( static_cast<base&>(*this) != m_base_end
                 && base::operator*() % 2 );
        return *this;
    }

    my_iterator operator++(int)
    {
        my_iterator temp;
        operator++();
        return temp;
    }

    // TODO: decrement and other arithmetic operators
};

这还是相当多的样板代码,您还需要为 const_iterator 做同样的事情(我可能会将上述类作为模板使其更容易)。

考虑使用Boost - 它有专门为此目的设计的 filter_iterator。如果不适合您,也可以考虑使用 iterator_adaptor


这个解决方案非常危险,可能会覆盖太多其他代码。例如,这个循环很可能会崩溃,因为erase也应该被覆盖:my_iterator iter = v.begin(); while ( iter != v.end() ) { if ( cond ) ++iter; else iter = v.erase(); }。此外,vector::operator++virtual的吗?因为非虚函数不应该被覆盖... - jpo38

1

#include <vector>
#include <iostream>

class X {

public:

  class EvenIterator {
  public:
    EvenIterator(std::vector<int>::iterator it, std::vector&ltint>::iterator end) : it(it), end(end) {
      while (true) {
        if (isEven(*it)) {
          break;
        } else if (it == end) {
          break;
        }
        it++;
      }
    }

    bool operator != (const EvenIterator& evenIt) {
      return evenIt.it != this->it;
    }

    int operator * () {
      return *it;
    }

    EvenIterator operator ++ () {
      while (true) {
        it++;
        if (isEven(*it)) {
          return EvenIterator(it, end);
        } else if (it == end) {
          return EvenIterator(it, end);
        }
      }
    }
  private:
    std::vector&ltint>::iterator it;    
    std::vector&ltint>::iterator end;    
  };

  static bool isEven(int number) {
    return number % 2 == 0;
  }

  void add(int number) {
    v.push_back(number);
  }

  EvenIterator evenBegin() {
    return EvenIterator(v.begin(), v.end());
  }

  EvenIterator evenEnd() {
    return EvenIterator(v.end(), v.end());
  }

private:
  std::vector&ltint> v;

};

int main() {
  X x;
  x.add(1);
  x.add(2);
  x.add(3);
  x.add(2);
  x.add(2);
  x.add(31);
  x.add(56);
  x.add(101);

  for (X::EvenIterator it = x.evenBegin(); it != x.evenEnd(); ++it){
    std::cout << *it << std::endl; // only prints the even numbers
  }
}


太棒了,这看起来就像是我期望的代码样子,如果我知道如何做的话;-) 不过应该是number % 2 == 0 :-) - user32849
在你解引用迭代器之前,你真的想要先检查结束条件... - jrok
这个版本即使第一个元素是奇数也会获取它。应该是 iterator evenBegin() { std::vector<int>::iterator i = data.begin(); while (!isEven(*i)){ ++i; } return iterator(i, data.end()); } - user32849

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接