【问题标题】:C++ "Scrolling" through items in an stl::mapC ++“滚动”通过stl :: map中的项目
【发布时间】:2009-12-07 23:20:35
【问题描述】:

我已经创建了一个滚动/环绕项目地图的方法,因此如果到达终点,该方法将返回第一个项目,反之亦然。

还有更简洁的方法吗?

MyMap::const_iterator it = myMap.find(myKey);

if (it == myMap.end())
    return 0;

if (forward) {

    it++;

    if (it == myMap.end()) {
        it = myMap.begin();
    }

} else {

    if (it == myMap.begin()) {
        it = myMap.end();
    }

    it--;

}

【问题讨论】:

    标签: c++ stl map iterator


    【解决方案1】:

    您可以将环绕行为直接实现到一个新的迭代器类中 - 模板化为一些实际迭代器的包装器,为调用者提供更优雅的接口(以便它的增量和减量运算符进行包装 -自动环绕)。

    另外 - 小心空容器。当容器中没有元素时,您不想“环绕”。

    【讨论】:

      【解决方案2】:

      您可以使用模板执行此操作。正如之前的海报所述,从永远不会到达终点的角度来看,这可能很麻烦,因此用户必须以某种方式控制它。我假设您有充分的理由,也许会产生一些循环行为。

      #include <iostream>
      #include <string>
      #include <vector>
      #include <set>
      #include <map>
      
      using namespace std;
      
      template <class T>
      class ScrollIterator
      {
      public:
          ScrollIterator(T &myCtr, typename T::iterator pos)
              :ctr(myCtr),
               it(pos)
          {
      
          }
      
          ScrollIterator operator++()
          {
              if (++it == ctr.end()) { it = ctr.begin(); }
              return *this;
          }
      
          bool operator!=(const ScrollIterator &rhs) const
          {
              return (this->it != rhs.it);
          }
      
          bool operator!=(const typename T::const_iterator &rhsIT) const
          {
              return (this->it != rhsIT);
          }
      
          typename T::value_type operator*() const
          {
              return *it;
          }
      
      private:
          T &ctr;
          typename T::iterator it;
      };
      
      
      int main (int argc, char *argv[])
      {
          vector<int> v;
          v.push_back(2);
          v.push_back(3);
          v.push_back(5);
          v.push_back(7);
      
          int i = 0;
          for (ScrollIterator<vector<int> > it(v,v.begin()); it != v.end() && i < 10; ++i, ++it)
          {
              cout << "Vector = " << i << " Value: " << *it << "\n";
          }
      
          set<string> s;
          s.insert("c");
          s.insert("a");
          s.insert("b");
      
          i = 0;
          for (ScrollIterator<set<string> > it(s,s.begin()); it != s.end() && i < 10; ++i, ++it)
          {
              cout << "Set = " << i << " Value: " << *it << "\n";
          }
      
          map<string, int> y;
          y["z"] = 10;
          y["y"] = 20;
          y["x"] = 30;
      
          i = 0;
          for (ScrollIterator<map<string, int> > it(y,y.begin()); it != y.end() && i < 10; ++i, ++it)
          {
              cout << "Map = " << i << " Iterator: " << (*it).first << " = " << (*it).second << "\n";
          }
      
          return 1;
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用 upper_boundlower_bound。例如:

        if (myMap.empty()) return 0;
        
        MyMap::const_iterator it;
        
        if (forward) {
            it = myMap.upper_bound(myKey);
            if (it == myMap.end()) it = myMap.begin();
        } else {
            it = myMap.lower_bound(myKey);
            if (it == myMap.begin()) it = myMap.end();
            --it;
        }
        

        如果地图中不存在“myKey”,这也会有所不同。它将从钥匙所在的位置开始,而不是走到结尾或开头。

        【讨论】:

          【解决方案4】:

          您可以实现cyclical iterator

          【讨论】:

            【解决方案5】:

            这是一个困难的设计。如果到达“结束”环绕到“开始”,你如何表示一个空容器?环绕思想对无限序列或环进行建模,但无法检测迭代器是否仍指向有效位置。

            这个问题让人想起在不使用“虚拟条目”的情况下编写可变大小的环形缓冲区(例如队列)的尝试:如何区分空环和满环?存储基本位置和大小仅适用于随机访问存储(与链接节点相反),并且比指针或索引对更不适合锁定优化。

            【讨论】:

            • 这里的虚拟条目显然是map.end()
            猜你喜欢
            • 2013-03-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多