【问题标题】:iterator for 2d vector二维向量的迭代器
【发布时间】:2010-12-19 13:35:30
【问题描述】:

如何为二维向量(向量的向量)创建迭代器?

【问题讨论】:

  • 也许能更好地描述问题的上下文?
  • 更具体地说:你的二维向量的声明是什么?你想迭代什么顺序?你想如何使用迭代器?

标签: c++ stl vector iterator


【解决方案1】:

虽然您的问题不是很清楚,但我会假设您的意思是 2D 向量表示向量的向量:

vector< vector<int> > vvi;

那么你需要使用两个迭代器来遍历它,第一个是“行”的迭代器,第二个是那个“行”中“列”的迭代器:

//assuming you have a "2D" vector vvi (vector of vector of int's)
vector< vector<int> >::iterator row;
vector<int>::iterator col;
for (row = vvi.begin(); row != vvi.end(); row++) {
    for (col = row->begin(); col != row->end(); col++) {
        // do stuff ...
    }
}

【讨论】:

  • 对不起,我的问题不是很清楚,但这正是我想要的。虽然我收到此代码的编译器错误:cannot convert from 'std::_Vector_iterator<_ty>' to 'int' on for (row = vvi.begin(); row != vvi.end(); row++ ) {
  • 始终使用预增量运算符。使用向量时,使用向量可能无关紧要,但这是一个不好的习惯。如果是 ++C 而不是 C++,生活会更加清晰。
  • 如果列中只有 2 个元素。遍历行后如何访问它们。
  • @Anoop 对不起,我不明白你的问题?你的意思是你需要访问*col[0]*col[1]
【解决方案2】:

您可以使用 range for 语句来迭代二维向量中的所有元素。

vector< vector<int> > vec;

假设您已经将很多元素 push_back 到 vec 中;

for(auto& row:vec){
   for(auto& col:row){
      //do something using the element col
   }
}

【讨论】:

    【解决方案3】:

    解释此问题的另一种方法是,您希望在 vector&lt;vector&lt;&gt;&gt; 上使用一维迭代器,例如将其提供给 for_each() 或其他算法。

    你可以这样做:

    #include <iostream>
    
    #include <iterator>
    #include <vector>
    #include <algorithm>
    
    // An iterator over a vector of vectors.
    template<typename T>
    class vv_iterator : public std::iterator<std::bidirectional_iterator_tag, T>{
    public:
    
      static vv_iterator<T> begin(std::vector<std::vector<T>>& vv) {
        return vv_iterator(&vv, 0, 0);
      }
      static vv_iterator<T> end(std::vector<std::vector<T>>& vv) {
        return vv_iterator(&vv, vv.size(), 0);
      }
    
      vv_iterator() = default;
      // ++prefix operator
      vv_iterator& operator++()
      {
        // If we haven't reached the end of this sub-vector.
        if (idxInner + 1 < (*vv)[idxOuter].size())
        {
          // Go to the next element.
          ++idxInner;
        }
        else
        {
          // Otherwise skip to the next sub-vector, and keep skipping over empty
          // ones until we reach a non-empty one or the end.
          do
          {
            ++idxOuter;
          } while (idxOuter < (*vv).size() && (*vv)[idxOuter].empty());
    
          // Go to the start of this vector.
          idxInner = 0;
        }
        return *this;
      }
      // --prefix operator
      vv_iterator& operator--()
      {
        // If we haven't reached the start of this sub-vector.
        if (idxInner > 0)
        {
          // Go to the previous element.
          --idxInner;
        }
        else
        {
          // Otherwise skip to the previous sub-vector, and keep skipping over empty
          // ones until we reach a non-empty one.
          do
          {
            --idxOuter;
          } while ((*vv)[idxOuter].empty());
    
          // Go to the end of this vector.
          idxInner = (*vv)[idxOuter].size() - 1;
        }
        return *this;
      }
      // postfix++ operator
      vv_iterator operator++(int)
      {
        T retval = *this;
        ++(*this);
        return retval;
      }
      // postfix-- operator
      vv_iterator operator--(int)
      {
        T retval = *this;
        --(*this);
        return retval;
      }
      bool operator==(const vv_iterator& other) const
      {
        return other.vv == vv && other.idxOuter == idxOuter && other.idxInner == idxInner;
      }
      bool operator!=(const vv_iterator &other) const
      {
        return !(*this == other);
      }
      const T& operator*() const
      {
        return *this;
      }
      T& operator*()
      {
        return (*vv)[idxOuter][idxInner];
      }
      const T& operator->() const
      {
        return *this;
      }
      T& operator->()
      {
        return *this;
      }
    
    private:
      vv_iterator(std::vector<std::vector<T>>* _vv,
                  std::size_t _idxOuter,
                  std::size_t _idxInner)
        : vv(_vv), idxOuter(_idxOuter), idxInner(_idxInner) {}
    
      std::vector<std::vector<int>>* vv = nullptr;
      std::size_t idxOuter = 0;
      std::size_t idxInner = 0;
    };
    
    
    
    int main()
    {
        std::vector<std::vector<int>> a = {{3, 5, 2, 6}, {-1, -4, -3, -5}, {100}, {-100}};
        std::reverse(vv_iterator<int>::begin(a), vv_iterator<int>::end(a));
        for (const auto& v : a)
        {
            std::cout << "{ ";
            for (auto i : v)
               std::cout << i << " ";
            std::cout << "}\n";
        }
    }
    

    打印:

    { -100 100 -5 -3 }
    { -4 -1 6 2 }
    { 5 }
    { 3 }
    

    请注意,这不适用于std::sort(),因为这需要随机访问迭代器。您可以将其设为随机访问迭代器,但您必须在开始时扫描向量,以便您可以在恒定时间内从平面索引映射到 idxOuteridxInner。不完全是微不足道的,但也不难。

    【讨论】:

    • 我正在寻找您对问题的准确解释。我对吗,这只是非常量迭代器,需要为const_iterator 编写第二个类?您存储索引而不是向量迭代器是否有任何特定原因?顺便说一句,我花了一些时间来理解这个例子,因为输出使用“普通”迭代器,而一维迭代器的使用在这个看似无辜的 reverse 行中有点隐藏。
    • 是的,在我的实际代码中,我有一个 const_iterator 版本。它或多或少是删除了非常量成员的复制/粘贴(我找不到避免复制/粘贴的方法)。好点我想没有理由不使用向量迭代器。这可能更好,我只是没想到。
    【解决方案4】:

    假设你有一个这样的向量:-

    vector &lt;vector&lt;int&gt;&gt; vect{{1,2,3},{4,5,6},{7,8,9}};

    现在使用带有 2D 向量的迭代器:-

     for(auto i = vect.begin() ; i<vect.end() ; i++)
      {
         for(auto j = i->begin() ; j<i->end() ; j++)
            cout << *j <<" ";
         cout <<"\n";  
         //similarly you can do other things
      }
    



    还有其他更短的方法是

     for(auto i : vect)
      {
         for(auto j : i)
            cout << j <<" ";
         cout << "\n";
    //similarly you can do other things also.
      }
    



    请注意两种情况下调用变量的方式不同。

    【讨论】:

      【解决方案5】:

      您可以在这种情况下使用 auto 关键字:

      #include <iostream>
      #include<bits/stdc++.h>
      using namespace std;
      
      int main() {
          // your code goes here
          vector<vector<int>>v;
      
          for(int i=0;i<5;i++)
          {
              vector<int> x={1,2,3,4,5};
              v.push_back(x);
          }
          cout<<"-------------------------------------------"<<endl;
          cout<<"Print without iterator"<<endl;
          cout<<"-------------------------------------------"<<endl;
          for(int i=0;i<5;i++)
          {
              vector<int> y=v[i];
              for(int j=0;j<y.size();j++)
              {
                  cout<<y[j]<<" ";
              }
              cout<<endl;
          }
          cout<<"-------------------------------------------"<<endl;
          cout<<"Print with iterator"<<endl;
          cout<<"-------------------------------------------"<<endl;
          for(auto iterator=v.begin();iterator!=v.end();iterator++)
          {
              vector<int> y=*iterator;
              for(auto itr=y.begin();itr!=y.end();itr++)
              {
                  cout<<*itr<<" ";
              }
              cout<<endl;
          }
          return 0;
      }
      

      【讨论】:

        【解决方案6】:

        由于是 2020 年,我将发布一个更新且简单的方法。在撰写本文时适用于 c++11 及更高版本。 参见下面的例子,其中迭代二维向量(向量的向量)的元素(这里:tuples of )以与另一个值(string query),然后该函数返回第一个匹配的元素,或指示“未找到”。

        tuple<string, size_t> find_serial_data( vector <vector <tuple <string, size_t>>> &serial,
                                                string query)
        {
            for (auto& i : serial)
            {
                for (auto& j : i)
                {
                    if ( get<0>(j).compare(query) == 0) return j;
                }
            }
            cout << "\n Not found";
            return make_tuple( "", 0);
        }
        

        这是一个没有元组的例子:

        string find_serial_data( vector <vector <string> > &serials,
                                                string query)
        {
            for (auto& i : serials)
            {
                for (auto& j : i)
                {
                    if ( j.compare(query) == 0) return j;
                }
            }
            cout << "\n Not found";
            return  "";
        }
        

        【讨论】:

          【解决方案7】:

          假设您的意思是一个 STL 迭代器和一个实现通用 2D 对象数组的自定义容器,这是不可能的。 STL 迭代器仅支持递增和递减(即“下一个”和“上一个”)操作,其中通过 2D 集合的运动需要四个这样的原语(例如左/右/上/下等)。比喻不相符。

          你想做什么?

          【讨论】:

            【解决方案8】:

            假设您的意思是一个向量向量,并且您想到了std::vector,没有内置的方法可以做到这一点,因为迭代器只支持递增和递减操作来向前和向后移动。

            二维向量是一个矩阵,因此您需要两种迭代器类型:行迭代器和列迭代器。行迭代器将“向上”和“向下”移动矩阵,而列迭代器将“向左”和“向右”移动。

            您必须自己实现这些迭代器类,这不一定是一件小事。当然,除非您只是想遍历矩阵中的每个槽,在这种情况下,使用索引变量 ij 的双循环就可以正常工作。根据您的需要(您的帖子在这里的内容有点缺乏),您可能想要使用 boost::numeric::ublas::matrix,它是 Boost 线性代数库中的一个矩阵类。这个矩阵类具有内置的行和列迭代器,这使得迭代矩阵通常很容易。

            【讨论】:

            • 正是我的意思,带有(现在我知道这两个)迭代器的二维向量矩阵。我认为问题很清楚:( ...无论如何我对向量还是很陌生,我必须在这项工作中使用它们。现在另一个问题是我在上面的评论中发布的错误(格式很糟糕)。无法赋值到第一个(行)迭代器,因为该类型不匹配。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-01-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多